Compare commits

..

58 Commits

Author SHA1 Message Date
cron
7470a83896 property_manager database backup as of 2010_02_27_0124
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@935 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-27 09:24:39 +00:00
cron
f8a10c56d3 property_manager database backup as of 2010_02_26_0122
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@934 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-26 09:22:29 +00:00
cron
bf17965b05 property_manager database backup as of 2010_02_21_0118
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@933 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-21 09:18:59 +00:00
cron
e69eb83f26 property_manager database backup as of 2010_02_20_0114
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@932 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-20 09:15:31 +00:00
cron
bbee815075 property_manager database backup as of 2010_02_19_0113
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@931 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-19 09:13:41 +00:00
cron
c305f90aad property_manager database backup as of 2010_02_15_0125
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@930 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-15 09:25:33 +00:00
cron
feeb912213 property_manager database backup as of 2010_02_13_0111
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@929 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-13 09:12:11 +00:00
cron
d26754f85c property_manager database backup as of 2010_02_12_0114
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@928 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-12 09:15:06 +00:00
cron
5d6d6475cf property_manager database backup as of 2010_02_11_0102
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@927 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-11 09:02:47 +00:00
cron
adfc0ab5eb property_manager database backup as of 2010_02_10_0123
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@926 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-10 09:23:42 +00:00
cron
229d36ca85 property_manager database backup as of 2010_02_09_0123
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@925 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-09 09:23:41 +00:00
cron
294cfb4e5f property_manager database backup as of 2010_02_08_0116
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@924 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-08 09:16:56 +00:00
cron
6a4d03be2f property_manager database backup as of 2010_02_06_0115
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@923 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-06 09:15:53 +00:00
cron
959a42c874 property_manager database backup as of 2010_02_04_0103
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@922 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-04 09:03:51 +00:00
cron
43e8e454b3 property_manager database backup as of 2010_02_01_0114
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@921 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-02-01 09:14:34 +00:00
cron
73ad0a3c49 property_manager database backup as of 2010_01_30_0111
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@920 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-30 09:12:01 +00:00
cron
7ca5fbcfbd property_manager database backup as of 2010_01_28_0111
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@919 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-28 09:11:31 +00:00
cron
8961df4e0c property_manager database backup as of 2010_01_21_0110
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@918 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-21 09:10:59 +00:00
cron
b9da799802 property_manager database backup as of 2010_01_20_0116
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@917 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-20 09:17:07 +00:00
cron
c8c460b15b property_manager database backup as of 2010_01_17_0101
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@916 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-17 09:01:49 +00:00
cron
a2d0ba4b5c property_manager database backup as of 2010_01_15_0105
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@915 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-15 09:06:36 +00:00
cron
38c3a3c9cb property_manager database backup as of 2010_01_12_0106
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@913 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-12 09:06:51 +00:00
cron
be2c5591ee property_manager database backup as of 2010_01_09_0117
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@912 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-09 09:18:02 +00:00
cron
a243bf9ec9 property_manager database backup as of 2010_01_08_0105
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@911 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-08 09:05:54 +00:00
cron
cd8deda8cd property_manager database backup as of 2010_01_07_0115
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@910 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-07 09:15:42 +00:00
cron
fac91f3178 property_manager database backup as of 2010_01_05_0106
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@909 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-05 09:06:59 +00:00
cron
79f58cb2fb property_manager database backup as of 2010_01_04_0117
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@908 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-04 09:18:39 +00:00
cron
26048172ef property_manager database backup as of 2009_12_30_0100
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@907 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-30 09:01:28 +00:00
cron
6f63cba37a property_manager database backup as of 2009_12_29_0112
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@906 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-29 09:13:47 +00:00
cron
3fb3bb8290 property_manager database backup as of 2009_12_17_0125
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@905 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-17 09:25:42 +00:00
cron
ea4c9771be property_manager database backup as of 2009_12_16_0122
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@904 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-16 09:22:53 +00:00
cron
dc491637e2 property_manager database backup as of 2009_12_13_0111
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@903 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-13 09:12:34 +00:00
cron
e7e0a8971f property_manager database backup as of 2009_12_11_0123
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@902 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-11 09:24:38 +00:00
cron
b5aef9d8a5 property_manager database backup as of 2009_12_10_0105
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@901 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-10 09:06:13 +00:00
cron
a3def96248 property_manager database backup as of 2009_12_09_0100
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@899 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-09 09:00:31 +00:00
cron
281a192aac property_manager database backup as of 2009_12_08_0110
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@898 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-08 09:11:08 +00:00
cron
6c5bf2034c property_manager database backup as of 2009_12_05_0106
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@897 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-05 09:06:45 +00:00
cron
3b150a5035 property_manager database backup as of 2009_12_04_0102
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@896 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-04 09:02:36 +00:00
cron
ffd4c1cb02 property_manager database backup as of 2009_12_03_0121
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@895 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-03 09:21:36 +00:00
cron
d390e24259 property_manager database backup as of 2009_12_01_0118
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@894 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-01 09:18:50 +00:00
cron
c0c74c9390 property_manager database backup as of 2009_11_28_0100
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@893 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-28 09:01:19 +00:00
cron
2f83c0a95d property_manager database backup as of 2009_11_19_0100
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@892 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-19 09:01:00 +00:00
cron
ca6c88509f property_manager database backup as of 2009_11_14_0116
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@891 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-14 09:17:27 +00:00
cron
e7d1d68316 property_manager database backup as of 2009_11_13_0109
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@890 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-13 09:09:45 +00:00
cron
2ed0506099 property_manager database backup as of 2009_11_11_0118
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@889 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-11 09:19:16 +00:00
cron
75f13f5cfd property_manager database backup as of 2009_11_10_0103
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@888 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-10 09:04:08 +00:00
cron
2f6e55bf40 property_manager database backup as of 2009_11_08_0119
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@887 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-08 09:19:27 +00:00
cron
e99e344599 property_manager database backup as of 2009_11_06_0113
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@886 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-06 09:13:52 +00:00
cron
31dd195a53 property_manager database backup as of 2009_11_04_0114
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@885 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-04 09:15:07 +00:00
cron
09a10827c5 property_manager database backup as of 2009_11_03_0101
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@884 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-03 09:02:13 +00:00
cron
2bfa726e9b property_manager database backup as of 2009_11_03_0007
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@883 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-11-03 08:07:40 +00:00
cron
4a8d505d53 property_manager database backup as of 2009_10_31_0124
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@882 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-31 08:25:02 +00:00
cron
6ca1dcdf17 property_manager database backup as of 2009_10_28_0101
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@881 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-28 08:01:40 +00:00
cron
314c79aa36 property_manager database backup as of 2009_10_18_0126
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@880 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-18 08:26:46 +00:00
cron
6fb81b383f property_manager database backup as of 2009_10_16_0107
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@879 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-16 08:07:37 +00:00
cron
958b6bc6f3 property_manager database backup as of 2009_10_13_0115
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@878 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-13 08:16:19 +00:00
cron
08f5c48a3c property_manager database backup as of 2009_10_12_0106
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@877 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-12 08:07:11 +00:00
cron
845eec126f property_manager database backup as of 2009_10_10_0120
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@876 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-10 08:20:55 +00:00
45 changed files with 12392 additions and 2626 deletions

3
build.cmd Normal file
View File

@@ -0,0 +1,3 @@
@echo off
mysql --user=pmgr --password=pmgruser < %~dp0\db\property_manager.sql
echo Done!

10098
db/property_manager.sql Normal file

File diff suppressed because it is too large Load Diff

578
db/scratch.sql Normal file
View File

@@ -0,0 +1,578 @@
-- Delete bad transaction(s)
DELETE M
FROM
pmgr_ledger_entries LE,
pmgr_tenders M
WHERE
M.ledger_entry_id = LE.id AND
LE.transaction_id
IN (467);
DELETE LE
FROM
pmgr_ledger_entries LE
WHERE
LE.transaction_id
IN (467);
DELETE SE
FROM
pmgr_statement_entries SE
WHERE
SE.transaction_id
IN (467);
DELETE T
FROM
pmgr_transactions T
WHERE
T.id
IN (467);
-- Delete bad transaction, one variable setting
SET @tid = 467;
DELETE M FROM pmgr_ledger_entries LE, pmgr_tenders M
WHERE M.ledger_entry_id = LE.id AND LE.transaction_id = @tid;
DELETE LE FROM pmgr_ledger_entries LE
WHERE LE.transaction_id = @tid;
DELETE SE FROM pmgr_statement_entries SE
WHERE SE.transaction_id = @tid;
DELETE T FROM pmgr_transactions T
WHERE T.id = @tid;
-- Delete all but one customer
SET @cid = 6;
-- DELETE T FROM pmgr_transactions T
-- LEFT JOIN pmgr_customers C ON C.id = T.customer_id
-- WHERE C.id IS NOT NULL AND C.id <> @cid;
DELETE C FROM pmgr_customers C
WHERE C.id <> @cid;
DELETE L FROM pmgr_leases L
LEFT JOIN pmgr_customers C ON C.id = L.customer_id
WHERE C.id IS NULL;
DELETE T FROM pmgr_transactions T
LEFT JOIN pmgr_customers C ON C.id = T.customer_id
WHERE C.id IS NULL;
DELETE SE FROM pmgr_statement_entries SE
LEFT JOIN pmgr_customers C ON C.id = SE.customer_id
WHERE C.id IS NULL;
DELETE LE FROM pmgr_ledger_entries LE
LEFT JOIN pmgr_transactions T ON T.id = LE.transaction_id
WHERE T.id IS NULL;
DELETE M FROM pmgr_tenders M
LEFT JOIN pmgr_ledger_entries LE ON M.ledger_entry_id = LE.id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
WHERE LE.id IS NULL;
UPDATE pmgr_ledger_entries LE, pmgr_ledgers L, pmgr_accounts A
SET LE.ledger_id = L.id
WHERE A.id = LE.account_id AND L.account_id = A.id AND L.sequence = 1;
DELETE FROM pmgr_ledgers WHERE sequence > 1;
UPDATE pmgr_ledgers SET prior_ledger_id = NULL, close_transaction_id = NULL;
-- Delete a ledger entry, associated double entry, and matching ledger_entry
SET @leid = 1365;
DELETE FROM pmgr_ledger_entries WHERE id = @leid;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
WHERE LE.id IS NULL;
DELETE LE FROM pmgr_ledger_entries LE
LEFT JOIN pmgr_double_entries DE
ON DE.credit_entry_id = LE.id OR DE.debit_entry_id = LE.id
WHERE DE.id IS NULL;
-- Add and update every Tender.ledger_entry_id (for rolling up old databases)
-- Takes a while to complete (~30s at time of writing)
ALTER TABLE `pmgr_tenders`
ADD `deposit_ledger_entry_id` INT UNSIGNED DEFAULT NULL
AFTER `nsf_ledger_entry_id`;
UPDATE
pmgr_tenders Tnd
JOIN pmgr_tender_types TndT ON TndT.id = Tnd.tender_type_id
JOIN pmgr_transactions T ON T.id = Tnd.deposit_transaction_id
JOIN pmgr_ledger_entries LE ON LE.transaction_id = T.id AND LE.account_id = TndT.account_id
JOIN pmgr_double_entries DE ON DE.debit_entry_id = LE.id OR DE.credit_entry_id = LE.id
JOIN pmgr_ledger_entries LEd ON (DE.debit_entry_id = LEd.id OR DE.credit_entry_id = LEd.id)
AND LEd.id <> LE.id
SET Tnd.deposit_ledger_entry_id = LEd.id;
-- Add auto_deposit and deposit_account_id to tenders
ALTER TABLE `pmgr_tender_types`
ADD `auto_deposit` TINYINT(1) UNSIGNED DEFAULT '0' NOT NULL
AFTER `tillable`;
ALTER TABLE `pmgr_tender_types`
ADD `deposit_account_id` INTEGER(10) UNSIGNED DEFAULT NULL
AFTER `account_id`;
-- Determine economic conditions
SELECT `status`, COUNT(id), SUM(rent) FROM pmgr_units
GROUP BY `status` WITH ROLLUP;
-- Check that transaction totals add up correctly
SELECT T.id, T.type, T.amount,
-- T.type, A.type, E.crdr,
SUM(IF(E.account_id = T.account_id,
IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1),0)
*E.amount) AS Tamt,
SUM(IF(E.account_id = T.account_id,
0,IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1))
*E.amount) AS Oamt,
COUNT(E.id) AS Ecnt
FROM pmgr_transactions T
-- LEFT JOIN pmgr_statement_entries E ON E.transaction_id = T.id
LEFT JOIN pmgr_ledger_entries E ON E.transaction_id = T.id
LEFT JOIN pmgr_accounts A ON A.id = T.account_id -- E.account_id
-- WHERE
-- E.account_id != T.account_id
GROUP BY T.id
HAVING
(T.type = 'INVOICE' AND Tamt <> T.amount)
OR
(T.type <> 'INVOICE' AND Oamt <> T.amount)
OR
(Tamt * -1 <> Oamt)
-- Verify that statement entries all have the correct type
SELECT SE.id, SE.type, T.id, T.type
FROM pmgr_statement_entries SE
LEFT JOIN pmgr_transactions T ON T.id = SE.transaction_id
WHERE
((T.type = 'RECEIPT' OR T.type = 'CREDIT_NOTE') AND
SE.type NOT IN ('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS')
)
OR
((T.type = 'INVOICE' OR T.type = 'PAYMENT') AND
SE.type NOT IN ('CHARGE', 'PAYMENT', 'REFUND')
)
-- catch other types not considered in this query
OR T.type NOT IN ('RECEIPT', 'CREDIT_NOTE', 'INVOICE', 'PAYMENT')
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- ## USER / GROUP
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
VALUES('Owner', 'Owner Group', 25);
SET @o_gid = LAST_INSERT_ID();
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
VALUES('Admin', 'Admin Group', 50);
SET @a_gid = LAST_INSERT_ID();
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
VALUES('Manager', 'Manager Group', 75);
SET @m_gid = LAST_INSERT_ID();
INSERT INTO pmgr_groups (`code`, `name`)
VALUES('Temp', 'Temporary Help');
SET @t_gid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('AP', 'abijah', 0);
SET @a_uid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('SK', 'shirley', 0);
SET @s_uid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('DE', 'dan', 0);
SET @d_uid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('KD', 'kevin', 0);
SET @k_uid = LAST_INSERT_ID();
INSERT INTO pmgr_sites (`code`, `name`)
VALUES('VSS', 'Valley Storage');
SET @v_sid = LAST_INSERT_ID();
INSERT INTO pmgr_sites (`code`, `name`)
VALUES('FAKE', 'Fake Site');
SET @f_sid = LAST_INSERT_ID();
-- Site Membership
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @a_uid, @o_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @a_uid, @a_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @a_uid, @m_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @s_uid, @m_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @d_uid, @t_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @s_uid, @a_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @s_uid, @m_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @k_uid, @o_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @d_uid, @t_gid);
-- Options
INSERT INTO pmgr_options (`name`) VALUES ('theme');
SET @t_oid = LAST_INSERT_ID();
INSERT INTO pmgr_options (`name`) VALUES ('menu');
SET @m_oid = LAST_INSERT_ID();
-- Default Option Values
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'blue');
INSERT INTO pmgr_default_options (`option_value_id`) VALUES(LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'basic');
INSERT INTO pmgr_default_options (`option_value_id`) VALUES(LAST_INSERT_ID());
-- Group options
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'gold');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@o_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'silver');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@a_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'red');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@m_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'advanced');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@o_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'advanced');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@a_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'restricted');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@t_gid, LAST_INSERT_ID());
-- User Options
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'special');
INSERT INTO pmgr_user_options (`user_id`, `option_value_id`)
VALUES(@s_uid, LAST_INSERT_ID());
-- Site Options
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'site-theme');
INSERT INTO pmgr_site_options (`site_id`, `option_value_id`)
VALUES(@f_sid, LAST_INSERT_ID());
-- SELECT U.id, P.name, MAX(P.access)
-- FROM pmgr_users U
-- LEFT JOIN pmgr_site_membership M ON M.user_id = U.id
-- LEFT JOIN pmgr_groups G ON G.id = M.group_id
-- LEFT JOIN pmgr_group_permissions P ON P.group_id = G.id
-- GROUP BY U.id, P.name
-- User access to site
SELECT U.id, U.login, COUNT(G.id) AS 'groups', MIN(G.rank) AS highest_rank
FROM pmgr_users U
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
JOIN pmgr_groups G ON G.id = M.group_id
WHERE S.code = 'VSS'
GROUP BY U.id
-- User Options
SELECT O.id, O.name, O.default,
GROUP_CONCAT(Uopt.value) AS 'value', COUNT(U.id) AS 'count'
FROM pmgr_options O
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
WHERE U.id = 1
GROUP BY O.id
-- Group Options
SELECT O.id, O.name, O.default,
GROUP_CONCAT(Gopt.value) AS 'value', COUNT(G.id) AS 'count'
FROM pmgr_options O
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
WHERE G.id = 1
GROUP BY O.id
-- Site Options
SELECT O.id, O.name, O.default,
GROUP_CONCAT(Sopt.value) AS 'value', COUNT(S.id) AS 'count'
FROM pmgr_options O
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
WHERE S.id = 1
GROUP BY O.id
-- Option value for member & site
SELECT O.id, O.name, O.default,
S.id AS site_id, Sopt.value,
G.id AS group_id, Gopt.value,
U.id AS user_id, Uopt.value
FROM pmgr_options O
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
WHERE O.name = 'theme'
--GROUP BY O.id
-- Option value for member & site
-- 1) User
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, U.id, Uopt.value
FROM pmgr_options O
JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
JOIN pmgr_users U ON U.id = Uopt.user_id
-- JOIN pmgr_site_memberships M ON M.user_id = U.id
-- JOIN pmgr_groups G ON G.id = M.group_id
-- JOIN pmgr_sites S ON S.id = M.site_id
WHERE -- S.id = @sid AND
U.id = @uid AND O.id = @oid
;
-- 2) Group
SELECT O.name, G.rank, G.id, Gopt.value
FROM pmgr_options O
JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
JOIN pmgr_groups G ON G.id = Gopt.group_id
JOIN pmgr_site_memberships M ON M.group_id = G.id
JOIN pmgr_users U ON U.id = M.user_id
JOIN pmgr_sites S ON S.id = M.site_id
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY G.rank
;
-- 3) Site
SELECT O.name, S.id, Sopt.value
FROM pmgr_options O
JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
JOIN pmgr_sites S ON S.id = Sopt.site_id
-- JOIN pmgr_site_memberships M ON M.site_id = S.id
-- JOIN pmgr_groups G ON G.id = M.group_id
-- JOIN pmgr_users U ON U.id = M.user_id
WHERE S.id = @sid
-- AND U.id = @uid
AND O.id = @oid
;
-- 3) Default
SELECT O.name, O.default AS 'value'
FROM pmgr_options O
WHERE O.id = @oid
;
-- User Permissions
-- Group Permissions
-- All option values, in order
SELECT O.name, V.value,
U.id AS uid, G.id AS gid, S.id as sid,
Dopt.id AS did, G.rank
FROM pmgr_option_values V
JOIN pmgr_options O ON O.id = V.option_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
WHERE O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
-- Option values relevant to the user and site, in order
SELECT O.name, V.value,
U.id AS uid, G.id AS gid, S.id as sid,
Dopt.id AS did, G.rank
FROM pmgr_option_values V
JOIN pmgr_options O ON O.id = V.option_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
JOIN pmgr_site_memberships M ON M.user_id = U.id AND M.site_id = S.id
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, V.value,
U.id AS uid,
-- G.id AS gid,
S.id as sid,
Dopt.id AS did
-- G.rank
FROM pmgr_option_values V
JOIN pmgr_options O ON O.id = V.option_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
-- LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
-- LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
-- LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
JOIN pmgr_site_memberships M ON M.user_id = U.id -- AND M.site_id = S.id
WHERE -- S.id = @sid AND U.id = @uid AND
O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
-- IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4)) -- ) ASC,
-- IF (G.id IS NOT NULL, G.rank, 0) ASC
-- ------------------------------------------------------------
-- ------------------------------------------------------------
-- ------------------------------------------------------------
-- Working version (without defaults)
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
U.id AS uid,
G.id AS gid,
S.id AS sid,
-- Dopt.id AS did
G.rank
FROM pmgr_users U
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
LEFT JOIN pmgr_groups G ON G.id = M.group_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.user_id = U.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.group_id = G.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.site_id = S.id
LEFT JOIN pmgr_option_values V ON (V.id = Uopt.option_value_id OR
V.id = Gopt.option_value_id OR
V.id = Sopt.option_value_id)
JOIN pmgr_options O ON O.id = V.option_id
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
;
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
U.id AS uid,
G.id AS gid,
S.id AS sid,
-- Dopt.id AS did
G.rank
FROM pmgr_options O
LEFT JOIN pmgr_option_values V ON V.option_id = O.id
-- Now have the option and all possible values
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
-- Now have the user/group/site that each value applies to
LEFT JOIN pmgr_users U U ON Uopt.user_id = U.id OR Uopt.user_id IS NULL
-- Now restricted to our user
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
ON O.id = V.option_id
LEFT JOIN pmgr_groups G ON G.id = M.group_id
LEFT JOIN pmgr_option_values V ON (V.id = Uopt.option_value_id OR
V.id = Gopt.option_value_id OR
V.id = Sopt.option_value_id)
JOIN
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
;
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
U.id AS uid,
G.id AS gid,
S.id AS sid,
-- Dopt.id AS did
G.rank
FROM pmgr_options O LEFT JOIN pmgr_option_values V ON V.option_id = O.id,
pmgr_users U
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
LEFT JOIN pmgr_groups G ON G.id = M.group_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.user_id = U.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.group_id = G.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.site_id = S.id,
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
AND (V.id = Uopt.option_value_id OR
V.id = Gopt.option_value_id OR
V.id = Sopt.option_value_id)
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
;

68
requirements.txt Normal file
View File

@@ -0,0 +1,68 @@
N - GATE
N - ACH / CREDIT CARD PROCESSING
Y - CREDIT CARD ENTRY
Y - ACH ENTRY
P - INVENTORY TRACKING / POS
Y - UNIT TYPES
Y - UNIT SIZES
Y - UNITS
Y - MOVE IN / OUT
Y - UNIT TRANSFERS
Y - LEASE TRACKING (PDF Generation)
Y - LETTERS (PDF Generation)
Y - REMINDERS
Y - MULTIPLE LATE RENT SCHEDULES (Tenant A vs Tenant B)
Y - ACCOUNTING (assign charges to accounts)
Y - DETAILED REPORTING (HTML & PDF)
Y - SITE MAP; HOT CLICKABLE
P - PROSPECTIVE TENANTS
Y - MARKETING
P - RESERVATIONS
P - MOVE OUT NOTICES
P - MULTI-SITE (One database, multiple sites)
Y - GENERATE GEOGRAPHIC MAP OF CUSTOMERS USING GOOGLE!
- Major advantage here... MapPoint only choice with competitors
Y - WEB BASED
Y - CUSTOMER VIEW / MANAGER VIEW
Y - CUSTOMERS CAN CREATE ACCOUNTS, VIEW HISTORY
Y - CUSTOMERS CAN SIGN UP FOR AUTO PAY
----------------------------------------------------------------------
----------------------------------------------------------------------
Operations to be functional
'X' marks functionality sufficiently completed
X - Create Customer ID/Account
X - Add Contact information to Customer
X - Move Customer into Unit
X - Enter Rent Concessions given
X - Asses Rent Charges
X - Asses Late Charges
X - Asses Security Deposits
X - Receive and record Checks
X - Receive and record Money Orders
X - Receive and record Cash
X - Receive and record ACH Deposits
X - Reverse rent charges (early moveout on prepaid occupancy)
X - Handle NSF checks
X - Assess NSF Fees
X - Determine Lease Paid-Through status
X - Report: List of customers overdue
X - Flag unit as overlocked
X - Flag unit as evicting
X - Flag unit as normal status
X - Flag unit as dirty
- Enter notes when communicating with Customer
X - Accept pre-payments
X - Record Customer Move-Out from Unit
X - Record utilization of Security Deposit
X - Record issuing of a refund
- Record Deposit into Petty Cash
- Record Payment from Petty Cash to expenses
X - Record Petty Cash to refund.
X - Write Off Bad Debt
X - Perform a Deposit
X - Close the Books (nightly / weekly, etc)
X - Determine Rents Collected for a given period.

View File

@@ -39,7 +39,7 @@ class AppController extends Controller {
var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid'); var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid');
var $components = array('DebugKit.Toolbar'); var $components = array('DebugKit.Toolbar');
var $sidemenu = array('areas' => array('SITE' => false, 'REPORT' => false, 'CONTROLLER' => false, 'ACTION' => false, 'SANDBOX' => false)); var $sidemenu = array('areas' => array('SITE' => false, 'CONTROLLER' => false, 'ACTION' => false, 'SANDBOX' => false));
var $std_area = 10; var $std_area = 10;
var $admin_area = 20; var $admin_area = 20;
var $dev_area = 30; var $dev_area = 30;
@@ -52,15 +52,6 @@ class AppController extends Controller {
parent::__construct(); parent::__construct();
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: dev/admin()
* - Indicates if the user has dev/admin access
*/
function dev() { return !empty($this->params['dev']); }
function admin() { return !empty($this->params['admin']); }
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -80,8 +71,6 @@ class AppController extends Controller {
$name = Inflector::humanize($this->params['controller']); $name = Inflector::humanize($this->params['controller']);
elseif ($area == 'ACTION') elseif ($area == 'ACTION')
$name = Inflector::humanize(Inflector::singularize($this->params['controller'])); $name = Inflector::humanize(Inflector::singularize($this->params['controller']));
elseif ($area == 'REPORT')
$name = 'Reports';
elseif ($area == 'SANDBOX') elseif ($area == 'SANDBOX')
$name = 'Sandbox'; $name = 'Sandbox';
@@ -257,38 +246,11 @@ class AppController extends Controller {
$this->addSideMenuLink('New Deposit', $this->addSideMenuLink('New Deposit',
array('controller' => 'tenders', 'action' => 'deposit'), null, array('controller' => 'tenders', 'action' => 'deposit'), null,
'SITE', $this->op_area); 'SITE', $this->op_area);
if ($this->admin()) if (!empty($this->params['admin']))
$this->addSideMenuLink('Assess Charges', $this->addSideMenuLink('Assess Charges',
array('controller' => 'leases', 'action' => 'assess_all'), null, array('controller' => 'leases', 'action' => 'assess_all'), null,
'SITE', $this->op_area); 'SITE', $this->op_area);
if ($this->admin()) {
$acct = new Account;
$this->addSideMenuLink('Collected Rent',
array('controller' => 'accounts',
'action' => 'collected',
$acct->rentAccountID()), null,
'REPORT');
$this->addSideMenuLink('Unpaid Charges',
array('controller' => 'statement_entries', 'action' => 'unpaid'), null,
'REPORT');
$this->addSideMenuLink('Lease Up',
array('controller' => 'leases', 'action' => 'overview'), null,
'REPORT');
$this->addSideMenuLink('Unit Summary',
array('controller' => 'units', 'action' => 'overview'), null,
'REPORT');
$this->addSideMenuLink('Monthly Charges',
array('controller' => 'statement_entries', 'action' => 'chargesbymonth'), null,
'REPORT');
}
else {
$this->sideMenuEnable('REPORT', null, false);
}
$url_components = array('plugin', 'controller', 'action', 'named'); $url_components = array('plugin', 'controller', 'action', 'named');
if (devbox()) { if (devbox()) {
/* $sources = ConnectionManager::sourceList(); */ /* $sources = ConnectionManager::sourceList(); */
@@ -346,19 +308,19 @@ class AppController extends Controller {
$this->params['admin'] = $this->Option->enabled('admin'); $this->params['admin'] = $this->Option->enabled('admin');
$this->params['dev'] = devbox(); $this->params['dev'] = devbox();
if ($this->dev() && !$this->Option->enabled('dev')) if ($this->params['dev'] && !$this->Option->enabled('dev'))
$this->redirect("/"); $this->redirect("/");
if ($this->dev()) if (!$this->params['dev'])
Configure::write('debug', 2); Configure::write('debug', '0');
$this->addDefaultSideMenuLinks(); $this->addDefaultSideMenuLinks();
//$this->sideMenuEnable('SITE', $this->op_area, false); //$this->sideMenuEnable('SITE', $this->op_area, false);
foreach ($this->sidemenu['areas'] AS $area_name => $area) { foreach ($this->sidemenu['areas'] AS $area_name => $area) {
if (!$this->dev()) if (empty($this->params['dev']))
$this->sideMenuEnable($area_name, $this->dev_area, false); $this->sideMenuEnable($area_name, $this->dev_area, false);
if (!$this->admin()) if (empty($this->params['admin']))
$this->sideMenuEnable($area_name, $this->admin_area, false); $this->sideMenuEnable($area_name, $this->admin_area, false);
} }
@@ -427,13 +389,6 @@ class AppController extends Controller {
$this->sideMenuAreaActivate($area_name); $this->sideMenuAreaActivate($area_name);
} }
// If generating reports, don't display the controller menu.
// Each report comes from a controller, but there is no need
// to present the controller actions, so remove that section
// from the menu.
if ($this->sidemenu['active']['area'] == 'REPORT')
$this->sideMenuEnable('CONTROLLER', null, false);
//pr($this->sidemenu); //pr($this->sidemenu);
$this->set('sidemenu', $this->sidemenu); $this->set('sidemenu', $this->sidemenu);
} }
@@ -645,12 +600,15 @@ class AppController extends Controller {
// Grouping (which would not be typical) // Grouping (which would not be typical)
$query['group'] = $this->gridDataCountGroup($params, $model); $query['group'] = $this->gridDataCountGroup($params, $model);
if ($params['debug'])
$params['count_query'] = $query;
// Get the number of records prior to pagination // Get the number of records prior to pagination
return $this->gridDataCountExecute($params, $model, $query); return $this->gridDataCountExecute($params, $model, $query);
} }
function gridDataCountExecute(&$params, &$model, $query) { function gridDataCountExecute(&$params, &$model, $query) {
return $this->gridDataFind($params, $model, 'count', $query); return $model->find('count', $query);
} }
function gridDataCountTables(&$params, &$model) { function gridDataCountTables(&$params, &$model) {
@@ -868,9 +826,6 @@ class AppController extends Controller {
$page = ($params['page'] <= 1) ? 1 : (($params['page'] > $total) ? $total : $params['page']); $page = ($params['page'] <= 1) ? 1 : (($params['page'] > $total) ? $total : $params['page']);
$start = $limit * ($page - 1); $start = $limit * ($page - 1);
// Adjust the limit upward, if multiple pages were requested.
$limit *= empty($params['npage']) ? 1 : $params['npage'];
return compact('record_count', 'limit', 'page', 'start', 'total'); return compact('record_count', 'limit', 'page', 'start', 'total');
} }
@@ -902,11 +857,14 @@ class AppController extends Controller {
isset($params['sidx']) ? $params['sidx'] : null, isset($params['sidx']) ? $params['sidx'] : null,
isset($params['sord']) ? $params['sord'] : null); isset($params['sord']) ? $params['sord'] : null);
if ($params['debug'])
$params['query'] = $query;
return $this->gridDataRecordsExecute($params, $model, $query); return $this->gridDataRecordsExecute($params, $model, $query);
} }
function gridDataRecordsExecute(&$params, &$model, $query) { function gridDataRecordsExecute(&$params, &$model, $query) {
return $this->gridDataFind($params, $model, 'all', $query); return $model->find('all', $query);
} }
function gridDataTables(&$params, &$model) { function gridDataTables(&$params, &$model) {
@@ -948,24 +906,12 @@ class AppController extends Controller {
'value' => $params['filtValue']); 'value' => $params['filtValue']);
} }
// Translate a user specified date into the SQL date format
foreach ($searches AS &$search) {
if (preg_match('/(_date|stamp)$/', $search['field']) &&
preg_match('%(\d{1,2})[-/](\d{1,2})[-/](\d{2,4})%', $search['value'], $matches)) {
$search['value'] = sprintf('%04d%02d%02d',
$matches[3] + ($matches[3] < 50 ? 2000 : ($matches[3] < 100 ? 1900 : 0)),
$matches[2], $matches[1]);
}
}
unset($search);
$ops = array('eq' => array('op' => null, 'pre' => '', 'post' => ''), $ops = array('eq' => array('op' => null, 'pre' => '', 'post' => ''),
'ne' => array('op' => '<>', 'pre' => '', 'post' => ''), 'ne' => array('op' => '<>', 'pre' => '', 'post' => ''),
'lt' => array('op' => '<', 'pre' => '', 'post' => ''), 'lt' => array('op' => '<', 'pre' => '', 'post' => ''),
'le' => array('op' => '<=', 'pre' => '', 'post' => ''), 'le' => array('op' => '<=', 'pre' => '', 'post' => ''),
'gt' => array('op' => '>', 'pre' => '', 'post' => ''), 'gt' => array('op' => '>', 'pre' => '', 'post' => ''),
'ge' => array('op' => '>=', 'pre' => '', 'post' => ''), 'ge' => array('op' => '>=', 'pre' => '', 'post' => ''),
'in' => array('op' => 'IN', 'pre' => '(', 'post' => ')'),
'bw' => array('op' => 'LIKE', 'pre' => '', 'post' => '%'), 'bw' => array('op' => 'LIKE', 'pre' => '', 'post' => '%'),
'ew' => array('op' => 'LIKE', 'pre' => '%', 'post' => ''), 'ew' => array('op' => 'LIKE', 'pre' => '%', 'post' => ''),
'cn' => array('op' => 'LIKE', 'pre' => '%', 'post' => '%'), 'cn' => array('op' => 'LIKE', 'pre' => '%', 'post' => '%'),
@@ -1015,13 +961,6 @@ class AppController extends Controller {
return $start . ', ' . $limit; return $start . ', ' . $limit;
} }
function gridDataFind(&$params, &$model, $type, $query) {
if ($params['debug'])
$params['queries'][] = compact('type', 'query');
return $model->find($type, $query);
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -1168,7 +1107,6 @@ class AppController extends Controller {
} }
function gridDataOutputSummary(&$params, &$model, $pagination) { function gridDataOutputSummary(&$params, &$model, $pagination) {
if ($params['debug'])
echo " <params><![CDATA[\n" . print_r($params, true) . "\n]]></params>\n"; echo " <params><![CDATA[\n" . print_r($params, true) . "\n]]></params>\n";
echo " <page>{$pagination['page']}</page>\n"; echo " <page>{$pagination['page']}</page>\n";
echo " <total>{$pagination['total']}</total>\n"; echo " <total>{$pagination['total']}</total>\n";
@@ -1210,7 +1148,7 @@ class AppController extends Controller {
function gridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) { function gridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
// be sure to put text data in CDATA // be sure to put text data in CDATA
if (preg_match("/^[\d.]*$/", $data)) if (preg_match("/^\d*$/", $data))
echo " <cell>$data</cell>\n"; echo " <cell>$data</cell>\n";
else else
echo " <cell><![CDATA[$data]]></cell>\n"; echo " <cell><![CDATA[$data]]></cell>\n";

View File

@@ -32,22 +32,15 @@
* *
*/ */
function _box($type) { function sandbox() {
static $box = array('type' => null, 'test' => array());
if (!isset($box['type']) && !isset($box['test'][$type])) {
$r = Router::requestRoute(); $r = Router::requestRoute();
/* if (!preg_match("/gridData/", $_SERVER['REQUEST_URI'])) { */ return !empty($r[3]['sand_route']);
/* print("<PRE>Route:\n");print_r($r);print("\n</PRE>\n"); */
/* } */
$box['test'][$type] = !empty($r[3]["${type}_route"]);
if ($box['test'][$type])
$box['type'] = $type;
}
return $box['type'] == $type;
} }
function sandbox() { return _box('sand'); } function devbox() {
function devbox() { return _box('dev'); } $r = Router::requestRoute();
return !empty($r[3]['dev_route']);
}
function server_request_var($var) { function server_request_var($var) {
if (preg_match("/^HTTP_ACCEPT|REMOTE_PORT/", $var)) if (preg_match("/^HTTP_ACCEPT|REMOTE_PORT/", $var))

View File

@@ -38,7 +38,7 @@
* In production mode, flash messages redirect after a time interval. * In production mode, flash messages redirect after a time interval.
* In development mode, you need to click the flash message to continue. * In development mode, you need to click the flash message to continue.
*/ */
Configure::write('debug', 0); Configure::write('debug', 2);
/** /**
* Application wide charset encoding * Application wide charset encoding
*/ */

View File

@@ -43,16 +43,6 @@ Router::connect('/sand',
array('sand_route' => true) + $default_path); array('sand_route' => true) + $default_path);
Router::connect('/sand/:controller/:action/*', Router::connect('/sand/:controller/:action/*',
array('sand_route' => true, 'action' => null)); array('sand_route' => true, 'action' => null));
/* Unfortunately, for some reason we need an extra route to solve
* a bug with form generation. When $this->data is set by the
* controller, and a URL is generated by the FormHelper, this
* route is required to ensure the form action is correct. An
* example of a broken page is for /customers/edit/XX. It appears
* the page location uses the route above, it's only URL generation
* that seems to be broken.
*/
Router::connect('/sand/:controller/:action/:id/*',
array('sand_route' => true,'action' => null, 'id'=>null));
/* /*
* Route for developement functionality * Route for developement functionality
@@ -61,15 +51,5 @@ Router::connect('/dev',
array('dev_route' => true) + $default_path); array('dev_route' => true) + $default_path);
Router::connect('/dev/:controller/:action/*', Router::connect('/dev/:controller/:action/*',
array('dev_route' => true, 'action' => null)); array('dev_route' => true, 'action' => null));
/* Unfortunately, for some reason we need an extra route to solve
* a bug with form generation. When $this->data is set by the
* controller, and a URL is generated by the FormHelper, this
* route is required to ensure the form action is correct. An
* example of a broken page is for /customers/edit/XX. It appears
* the page location uses the route above, it's only URL generation
* that seems to be broken.
*/
Router::connect('/dev/:controller/:action/:id/*',
array('dev_route' => true,'action' => null, 'id'=>null));
?> ?>

View File

@@ -2,14 +2,6 @@
class CustomersController extends AppController { class CustomersController extends AppController {
var $components = array('RequestHandler');
// DEBUG FUNCTION ONLY!
// Call without id to update ALL customers
function force_update($id = null) {
$this->Customer->update($id);
$this->redirect(array('action'=>'index'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -313,11 +305,6 @@ class CustomersController extends AppController {
array('action' => 'edit', $id), null, array('action' => 'edit', $id), null,
'ACTION'); 'ACTION');
if ($this->admin())
$this->addSideMenuLink('Merge',
array('action' => 'merge', $id), null,
'ACTION');
// Prepare to render. // Prepare to render.
$title = 'Customer: ' . $customer['Customer']['name']; $title = 'Customer: ' . $customer['Customer']['name'];
$this->set(compact('customer', 'title', $this->set(compact('customer', 'title',
@@ -452,41 +439,6 @@ class CustomersController extends AppController {
$this->edit(); $this->edit();
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* action: merge
* - Merges two customers
*/
function merge($id = null) {
if ($id) {
$this->Customer->recursive = -1;
$customer = $this->Customer->read(null, $id);
$customer = $customer['Customer'];
if (empty($customer))
$this->INTERNAL_ERROR("Customer $id does not exist");
$this->set('dst_customer', $customer);
$this->set('dst_name', $customer['name']);
$this->set('dst_id', $id);
}
else {
$this->INTERNAL_ERROR("Merge called with invalid customer");
}
}
function mergeFinal() {
if (!$this->RequestHandler->isPost()) {
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
return;
}
$post = $this->params['form'];
$this->Customer->merge($post['dst-id'], $post['src-id'],
unserialize($post['contact-ids']));
$this->redirect(array('action'=>'view', $post['dst-id']));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -176,20 +176,16 @@ class LeasesController extends AppController {
function move_out($id = null) { function move_out($id = null) {
if ($this->data) { if ($this->data) {
// Handle the move out based on the data given // Handle the move out based on the data given
//pr($this->data);
$this->Lease->moveOut($this->data['Lease']['id'], $this->Lease->moveOut($this->data['Lease']['id'],
'VACANT', 'VACANT',
$this->data['Lease']['moveout_date'] $this->data['Lease']['moveout_date']
); );
$lease = $this->Lease->find $this->redirect(array('controller' => 'leases',
('first', array
('contain' => array('Customer.id'),
'conditions' => array(array('Lease.id' => $this->data['Lease']['id'])),
));
$this->redirect(array('controller' => 'customers',
'action' => 'view', 'action' => 'view',
$lease['Customer']['id'])); $this->data['Lease']['id']));
} }
if (isset($id)) { if (isset($id)) {
@@ -444,64 +440,6 @@ class LeasesController extends AppController {
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* action: overview
* - Displays lease up information
*/
function overview($months = 12) {
$overview = array('months' => array());
for ($month = 0; $month < $months; ++$month) {
//for ($month = 12; $month >= 0; --$month) {
$this_month = "(DATE(NOW() - INTERVAL $month MONTH - INTERVAL DAY(NOW())-1 DAY))";
$next_month = "($this_month + INTERVAL 1 MONTH)";
$row = $this->Lease->find
('first', array('link' => array(),
'fields' => array("MONTHNAME($this_month) AS month",
"YEAR($this_month) AS year"),
));
$mname = $row[0]['month'] .', '. $row[0]['year'];
$overview['months'][$mname] = array('name' => $mname);
foreach(array('start' => array('before' => $this_month, 'after' => $this_month),
'finish' => array('before' => $next_month, 'after' => $next_month),
'peak' => array('before' => $next_month, 'after' => $this_month))
AS $type => $parm) {
$count = $this->Lease->find
('count',
array('link' => array(),
'conditions' => array("movein_date < {$parm['before']}",
"(moveout_date IS NULL OR moveout_date >= {$parm['after']})",
),
));
$overview['months'][$mname][$type] = $count;
}
foreach(array('movein', 'moveout') AS $mvinout) {
$count = $this->Lease->find
('count',
array('link' => array(),
'conditions' => array("{$mvinout}_date < $next_month",
"{$mvinout}_date >= $this_month")
));
$overview['months'][$mname][$mvinout] = $count;
}
}
// Enable the Reports menu section
$this->sideMenuAreaActivate('REPORT');
// Prepare to render.
$this->set('title', 'Lease Up Report');
$this->set(compact('overview'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -11,7 +11,6 @@ class StatementEntriesController extends AppController {
*/ */
function index() { $this->gridView('All Statement Entries'); } function index() { $this->gridView('All Statement Entries'); }
function unpaid() { $this->gridView('Unpaid Charges', 'unreconciled'); }
/************************************************************************** /**************************************************************************
@@ -48,17 +47,7 @@ class StatementEntriesController extends AppController {
if (!empty($params['post']['custom']['statement_entry_id'])) { if (!empty($params['post']['custom']['statement_entry_id'])) {
$link['ChargeEntry'] = array(); $link['ChargeEntry'] = array();
// This query actually represents a union... $link['DisbursementEntry'] = array();
// Unpaid Charge/Surplus: ChargeID - NULL; DisbursementID - NULL
// Paid Charge/Refund: ChargeID - NULL; DisbursementID - !NULL
// Disbursement/Reversal: ChargeID - !NULL; DisbursementID - NULL
// <EMPTY SET>: ChargeID - !NULL; DisbursementID - !NULL
//
// The query is really slow unless we add the `id` condition to the join.
// A cleaner query would be nice, but we must work within the Cake framework.
$link['DisbursementEntry'] = array('conditions' =>
'`DisbursementEntry`.`id` = '
. $params['post']['custom']['statement_entry_id']);
} }
return array('link' => $link); return array('link' => $link);
@@ -124,6 +113,18 @@ class StatementEntriesController extends AppController {
array(array('ChargeEntry.id' => $statement_entry_id), array(array('ChargeEntry.id' => $statement_entry_id),
array('DisbursementEntry.id' => $statement_entry_id))); array('DisbursementEntry.id' => $statement_entry_id)));
if ($params['action'] === 'unreconciled') {
$query = array('conditions' => $conditions);
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
$entries = array();
foreach ($set['entries'] AS $entry)
$entries[] = $entry['StatementEntry']['id'];
$conditions[] = array('StatementEntry.id' => $entries);
$params['userdata']['balance'] = $set['summary']['balance'];
}
return $conditions; return $conditions;
} }
@@ -147,48 +148,33 @@ class StatementEntriesController extends AppController {
// defaults into the sort mechanism. If we're already // defaults into the sort mechanism. If we're already
// sorting by one of them, it will only be redundant, // sorting by one of them, it will only be redundant,
// and should cause no harm (possible a longer query?) // and should cause no harm (possible a longer query?)
if ($index != 'Transaction.stamp' &&
$index != 'StatementEntry.effective_date') {
$order[] = 'Transaction.stamp ' . $direction; $order[] = 'Transaction.stamp ' . $direction;
$order[] = 'StatementEntry.effective_date ' . $direction; $order[] = 'StatementEntry.effective_date ' . $direction;
}
$order[] = 'StatementEntry.id ' . $direction; $order[] = 'StatementEntry.id ' . $direction;
return $order; return $order;
} }
function gridDataCountExecute(&$params, &$model, $query) {
if ($params['action'] === 'unreconciled') {
// REVISIT <AP> 20100413:
// This is a lame solution, as it runs the same queries twice
// (and causes code duplication). However, I'm not in the mood
// to flush out an actual "count" solution at the moment, and I
// also don't want to cache the results in $params (although
// that is probably the most sensible solution). So, I'll just
// calculate the reconciled set both times and live with the
// performance and maintenance penalty
$lquery = array('conditions' => $query['conditions']);
$set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true);
return count($set['entries']);
}
return parent::gridDataCountExecute($params, $model, $query);
}
function gridDataRecordsExecute(&$params, &$model, $query) { function gridDataRecordsExecute(&$params, &$model, $query) {
/* if ($params['action'] === '???') { */
/* $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1)); */
/* $tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," . */
/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */
/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */
/* " AS 'applied'", */
if ($params['action'] === 'unreconciled') { /* "StatementEntry.amount - (" . */
$lquery = array('conditions' => $query['conditions']); /* "IF(StatementEntry.type = 'CHARGE'," . */
$set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true); /* " SUM(COALESCE(DisbursementEntry.amount,0))," . */
/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */
$entries = array(); /* ") AS 'balance'", */
foreach ($set['entries'] AS $entry) /* ); */
$entries[] = $entry['StatementEntry']['id'];
$query['conditions'] = array('StatementEntry.id' => $entries);
$params['userdata']['balance'] = $set['summary']['balance'];
}
/* //pr(compact('tquery')); */
/* $total = $model->find('first', $tquery); */
/* $params['userdata']['total'] = $total[0]['applied']; */
/* $params['userdata']['balance'] = $total[0]['balance']; */
/* } */
if ($params['action'] === 'collected') { if ($params['action'] === 'collected') {
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1)); $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'"); $tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
@@ -257,53 +243,6 @@ class StatementEntriesController extends AppController {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* action: chargesbymonth
* - Displays charges by month
*/
function chargesbymonth($months = 12) {
$result = $this->StatementEntry->find
('all',
array('link' => array('Account' => array('fields' => 'name')),
'fields' => array_merge(array('MONTHNAME(effective_date) AS month',
'YEAR(effective_date) AS year'),
$this->StatementEntry->chargeDisbursementFields(true)),
'conditions' => array('Account.type' => 'INCOME',
'effective_date >= DATE(NOW() - INTERVAL '.($months-1).' MONTH - INTERVAL DAY(NOW())-1 DAY)',
'effective_date <= NOW()',
),
'group' => array('YEAR(effective_date)', 'MONTH(effective_date)', 'Account.id'),
'order' => array('YEAR(effective_date) DESC', 'MONTH(effective_date) DESC', 'Account.name'),
));
$overview = array('months' => array(), 'charges' => 0);
foreach ($result AS $row) {
$mname = $row[0]['month'] .', '. $row[0]['year'];
if (empty($overview['months'][$mname]))
$overview['months'][$mname] = array('name' => $mname,
'subs' => array(),
'charges' => 0);
$month = &$overview['months'][$mname];
$month['subs'][] = array('name' => $row['Account']['name'],
'charges' => $row[0]['balance']);
$month['charges'] += $row[0]['balance'];
$overview['charges'] += $row[0]['balance'];
}
// Enable the Reports menu section
$this->sideMenuAreaActivate('REPORT');
// Prepare to render.
$this->set('months', $months);
$this->set('title', 'Monthly Charges');
$this->set(compact('overview'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -54,12 +54,6 @@ class TransactionsController extends AppController {
$this->gridView('Deposits'); $this->gridView('Deposits');
} }
function gridView($title, $action = null, $element = null) {
if ($title != 'Deposits')
$this->set('include', array('Customer'));
parent::gridView($title, $action, $element);
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -83,7 +77,6 @@ class TransactionsController extends AppController {
$link = $this->gridDataCountTables($params, $model); $link = $this->gridDataCountTables($params, $model);
$link['link']['StatementEntry'] = array('fields' => array()); $link['link']['StatementEntry'] = array('fields' => array());
$link['link']['DepositTender'] = array('fields' => array()); $link['link']['DepositTender'] = array('fields' => array());
$link['link']['Customer'] = array('fields' => array('id', 'name'));
return $link; return $link;
} }
@@ -108,7 +101,6 @@ class TransactionsController extends AppController {
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) { function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit' $links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
? 'deposit_slip' : 'view')); ? 'deposit_slip' : 'view'));
$links['Customer'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links); return parent::gridDataPostProcessLinks($params, $model, $records, $links);
} }

View File

@@ -148,23 +148,6 @@ class UnitSizesController extends AppController {
return $conditions; return $conditions;
} }
function gridDataOrder(&$params, &$model, $index, $direction) {
if ($index == 'UnitType.name')
$index = 'UnitType.code';
$order = parent::gridDataOrder($params, $model, $index, $direction);
// After sorting by whatever the user wants, add these
// defaults into the sort mechanism. If we're already
// sorting by one of them, it will only be redundant,
// and should cause no harm (possible a longer query?)
$order[] = 'UnitType.code ' . $direction;
$order[] = 'sqft ' . $direction;
$order[] = 'UnitSize.rent ' . $direction;
return $order;
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) { function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['UnitSize'] = array('name'); $links['UnitSize'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links); return parent::gridDataPostProcessLinks($params, $model, $records, $links);

View File

@@ -225,69 +225,6 @@ class UnitsController extends AppController {
function unlock($id) { $this->status($id, 'OCCUPIED'); } function unlock($id) { $this->status($id, 'OCCUPIED'); }
/**************************************************************************
**************************************************************************
**************************************************************************
* action: overview
* - Displays overview information for all units
*/
function overview() {
$result = $this->Unit->find
('all',
array('link' => array('UnitSize' => array('fields' => array(), 'UnitType' => array('fields' => array('name')))),
'fields' => array('status', 'COUNT(Unit.id) AS cnt', 'SUM(Unit.rent) AS rents'),
//'conditions' => array('
'group' => array('UnitType.id', 'Unit.status'),
'order' => array('UnitType.name', 'Unit.status')
));
$overview = array('types' => array(), 'count' => 0, 'rents' => 0);
foreach ($result AS $row) {
$utname = $row['UnitType']['name'];
if (empty($overview['types'][$utname]))
$overview['types'][$utname] = array('name' => $utname,
'subs' => array(),
'count' => 0,
'rents' => 0,
'phys_pct' => 0,
'econ_pct' => 0);
$type = &$overview['types'][$utname];
$type['subs'][] = array('name' => $row['Unit']['status'],
'count' => $row[0]['cnt'],
'rents' => $row[0]['rents'],
'phys_subpct' => 0,
'phys_totpct' => 0,
'econ_subpct' => 0,
'econ_totpct' => 0);
$type['count'] += $row[0]['cnt'];
$type['rents'] += $row[0]['rents'];
$overview['count'] += $row[0]['cnt'];
$overview['rents'] += $row[0]['rents'];
}
foreach ($overview['types'] AS &$type) {
foreach ($type['subs'] AS &$sub) {
$sub['phys_subpct'] = $sub['count'] / $type['count'];
$sub['econ_subpct'] = $sub['rents'] / $type['rents'];
$sub['phys_totpct'] = $sub['count'] / $overview['count'];
$sub['econ_totpct'] = $sub['rents'] / $overview['rents'];
}
$type['phys_pct'] = $type['count'] / $overview['count'];
$type['econ_pct'] = $type['rents'] / $overview['rents'];
}
// Enable the Reports menu section
$this->sideMenuAreaActivate('REPORT');
// Prepare to render.
$this->set('title', 'Unit Overview');
$this->set(compact('overview'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -20,25 +20,15 @@ class Customer extends AppModel {
), ),
'Lease', 'Lease',
'StatementEntry', 'StatementEntry',
'ContactsCustomer' => array( 'ContactsCustomer',
// It would be nice to claim a dependency here, which would
// simplify deletion of a customer. However, for this to work
// Cake must have a primaryKey as a single field. This table
// makes use of a complex key, so we're out of luck.
/* 'dependent' => true, */
),
'Transaction', 'Transaction',
'Tender',
); );
var $hasAndBelongsToMany = array( var $hasAndBelongsToMany = array(
'Contact' => array( 'Contact',
'unique' => true,
),
); );
//var $default_log_level = 20;
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -202,13 +192,6 @@ class Customer extends AppModel {
} }
$id = $this->id; $id = $this->id;
// Appears that $this->save() "helpfully" choses to add in
// any missing data fields, populated with default values.
// So, after saving is complete, the fields 'lease_count',
// 'past_lease_count', and 'current_lease_count' have all
// been reset to zero. Gee, thanks Cake...
$this->update($id);
// Remove all associated Customer Contacts, as it ensures // Remove all associated Customer Contacts, as it ensures
// any entries deleted by the user actually get deleted // any entries deleted by the user actually get deleted
// in the system. We'll recreate the needed ones anyway. // in the system. We'll recreate the needed ones anyway.
@@ -289,116 +272,6 @@ class Customer extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: merge
* - Merges two customers into one
*/
function merge($dst_id, $src_id, $contacts) {
$this->prEnter(compact('dst_id', 'src_id', 'contacts'));
// Get the entire list of destination customer contacts
$dst_contacts = array();
$result = $this->find('all',
array('link' => array('ContactsCustomer'),
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
'conditions' => array(array('id' => $dst_id,
'ContactsCustomer.active' => true))));
foreach ($result AS $contact) {
$dst_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
}
$this->pr(17, compact('dst_contacts'));
// Get the entire list of source customer contacts
$src_contacts = array();
$result = $this->find('all',
array('link' => array('ContactsCustomer'),
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
'conditions' => array(array('id' => $src_id,
'ContactsCustomer.active' => true))));
foreach ($result AS $contact) {
$src_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
}
$this->pr(17, compact('src_contacts'));
// Verify the contacts list are all valid source customer contacts
foreach ($contacts AS $contact_id) {
if (!array_key_exists($contact_id, $src_contacts))
return $this->prReturn(false);
}
// Remove any contacts which are already destination customer contacts
$new_contacts = array_diff($contacts, array_keys($dst_contacts));
$all_contacts = array_merge($new_contacts, array_keys($dst_contacts));
$this->pr(17, compact('new_contacts', 'all_contacts'));
// For now, we'll assume the operation will succeed.
$ret = true;
// Add each desired source customer contact to the destination customer
foreach ($new_contacts AS $contact_id) {
$CM = new ContactsCustomer();
if (!$CM->save(array('customer_id' => $dst_id)
+ $src_contacts[$contact_id], false)) {
$ret = false;
}
}
$this->Lease->updateAll
(array('Lease.customer_id' => $dst_id),
array('Lease.customer_id' => $src_id)
);
$this->Tender->updateAll
(array('Tender.customer_id' => $dst_id),
array('Tender.customer_id' => $src_id)
);
$this->StatementEntry->updateAll
(array('StatementEntry.customer_id' => $dst_id),
array('StatementEntry.customer_id' => $src_id)
);
$this->Transaction->updateAll
(array('Transaction.customer_id' => $dst_id),
array('Transaction.customer_id' => $src_id)
);
// Make sure our lease counts, etc are correct
$this->update($dst_id);
// Delete the old customer
$this->pr(12, compact('src_id'), "Delete Customer");
$this->delete($src_id);
// Delete all the orphaned customers
foreach (array_diff(array_keys($src_contacts), $all_contacts) AS $contact_id) {
// Delete un-used or duplicate contacts
// REVISIT <AP> 20100702:
// Not sure if we really want to do this.
// On the one hand, they're probably really redundant,
// and only clutter up the list of all contacts. On the
// other hand, it destroys data, not only losing the
// history, but making it difficult to recover if the
// merge is a mistake. Additionally, we need to do
// extra checking to ensure that the contact is not
// in use by some other customer.
// We need some sort of Contact.deleted field...
$this->pr(12, compact('contact_id'), "Delete Contact");
$this->Contact->delete($contact_id);
}
// Finally, delete all customer contact relationships
$this->ContactsCustomer->deleteAll
(array('customer_id' => $src_id), false);
// Return the result
return $this->prReturn($ret);
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -148,11 +148,9 @@ class Lease extends AppModel {
array('class' => 'StatementEntry', array('class' => 'StatementEntry',
'fields' => array(), 'fields' => array(),
'conditions' => array 'conditions' => array
('SEx.lease_id = StatementEntry.lease_id', ('SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
'SEx.type' => 'CHARGE', 'SEx.lease_id = StatementEntry.lease_id',
'SEx.account_id' => $rent_account_id,
'SEx.reverse_transaction_id IS NULL', 'SEx.reverse_transaction_id IS NULL',
'SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
), ),
), ),
), ),
@@ -544,7 +542,7 @@ class Lease extends AppModel {
function conditionDelinquent($table_name = 'Lease') { function conditionDelinquent($table_name = 'Lease') {
if (empty($table_name)) $t = ''; else $t = $table_name . '.'; if (empty($table_name)) $t = ''; else $t = $table_name . '.';
return ("({$t}close_date IS NULL AND" . return ("({$t}close_date IS NULL AND" .
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 1 DAY))"); " NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 10 DAY))");
} }
function delinquentDaysSQL($table_name = 'Lease') { function delinquentDaysSQL($table_name = 'Lease') {

View File

@@ -338,72 +338,6 @@ class StatementEntry extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: outstandingDebits
* - Determines all debit types that have not yet been resolved.
* The name is a bit dumb, but it means any statement entry type
* that a positive customer balance could be used to offset. In
* other words, entries that are still in need of matching
* disbursements. Most notably, this means charges but could
* also mean things like refunds as well.
*/
function outstandingDebits($query = null, $customer_id = null,
$lease_id = null, $debit_types = null)
{
$this->prEnter(compact('query', 'lease_id',
'customer_id', 'charge_ids',
'debit_types'));
$this->queryInit($query);
if (empty($debit_types))
$debit_types = $this->debitTypes();
if (!empty($customer_id))
$query['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
if (!empty($lease_id))
$query['conditions'][] = array('StatementEntry.lease_id' => $lease_id);
/* if (isset($charge_ids)) { */
/* // REVISIT <AP> 20100330: */
/* // Not using $query here, as this code was extracted from its */
/* // original location in assignCredits, and so I'm keeping the */
/* // logic consistent. It does seem, however, that we shouldn't */
/* // be ignoring $query if passed in. I'm sure this won't be */
/* // looked at until someone _does_ pass $query in (and it break), */
/* // so hopefully at that time, we can understand what needs to */
/* // happen in that case (requirements are not clear at present). */
/* $lquery = array('contain' => false, */
/* 'conditions' => array('StatementEntry.id' => $charge_ids)); */
/* } else { */
/* $lquery = $query; */
/* // If we're working with a specific lease, then limit charges to it */
/* if (!empty($lease_id)) */
/* $lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id); */
/* } */
if (empty($query['order']))
$query['order'] = 'StatementEntry.effective_date ASC';
$debits = array();
foreach ($debit_types AS $dtype) {
$rset = $this->reconciledSet($dtype, $query, true);
$entries = $rset['entries'];
$debits = array_merge($debits, $entries);
$this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries");
}
return $this->prReturn($debits);
}
function outstandingCharges($query = null, $customer_id = null, $lease_id = null) {
return $this->outstandingDebits($query, $customer_id, $lease_id, array('CHARGE'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -425,6 +359,9 @@ class StatementEntry extends AppModel {
'customer_id', 'lease_id')); 'customer_id', 'lease_id'));
$this->queryInit($query); $this->queryInit($query);
if (!empty($customer_id))
$query['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
if (empty($disbursement_type)) if (empty($disbursement_type))
$disbursement_type = 'DISBURSEMENT'; $disbursement_type = 'DISBURSEMENT';
@@ -438,9 +375,6 @@ class StatementEntry extends AppModel {
$this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt"); $this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt");
$lquery = $query; $lquery = $query;
if (!empty($customer_id))
$lquery['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS'); $lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
// REVISIT <AP>: 20090804 // REVISIT <AP>: 20090804
// We need to ensure that we're using surplus credits ONLY from either // We need to ensure that we're using surplus credits ONLY from either
@@ -489,16 +423,23 @@ class StatementEntry extends AppModel {
"Receipt Credit Added"); "Receipt Credit Added");
} }
// Now find all unpaid charges, using either the specific set // Now find all unpaid charges
// of charges given, or all outstanding charges based on the if (isset($charge_ids)) {
// query, customer and/or lease $lquery = array('contain' => false,
if (!empty($charge_ids)) { 'conditions' => array('StatementEntry.id' => $charge_ids));
$this->INTERNAL_ERROR("PERHAPS IMPLEMENTED - THOUGH NEVER TESTED");
$lquery = $query;
$lquery['conditions'][] = array('StatementEntry.id' => $charge_ids);
$charges = $this->reconciledSet('CHARGE', $query, true);
} else { } else {
$charges = $this->outstandingDebits($query, $customer_id, $lease_id); $lquery = $query;
// If we're working with a specific lease, then limit charges to it
if (!empty($lease_id))
$lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id);
}
$lquery['order'] = 'StatementEntry.effective_date ASC';
$charges = array();
foreach ($this->debitTypes() AS $dtype) {
$rset = $this->reconciledSet($dtype, $lquery, true);
$entries = $rset['entries'];
$charges = array_merge($charges, $entries);
$this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries");
} }
// Work through all unpaid charges, applying disbursements as we go // Work through all unpaid charges, applying disbursements as we go
@@ -542,14 +483,14 @@ class StatementEntry extends AppModel {
// Set the disbursement amount to the maximum amount // Set the disbursement amount to the maximum amount
// possible without exceeding the charge or credit balance // possible without exceeding the charge or credit balance
$disbursement_amount = round(min($charge['balance'], $credit['balance']), 2); $disbursement_amount = min($charge['balance'], $credit['balance']);
if (!isset($credit['applied'])) if (!isset($credit['applied']))
$credit['applied'] = 0; $credit['applied'] = 0;
$credit['applied'] = round($credit['applied'] + $disbursement_amount, 2); $credit['applied'] += $disbursement_amount;
$credit['balance'] = round($credit['balance'] - $disbursement_amount, 2); $credit['balance'] -= $disbursement_amount;
$this->pr(20, compact('credit', 'disbursement_amount'), $this->pr(20, compact('credit'),
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') . ($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
(empty($credit['receipt']) ? ' Credit' : ' Receipt')); (empty($credit['receipt']) ? ' Credit' : ' Receipt'));
@@ -614,12 +555,12 @@ class StatementEntry extends AppModel {
} }
// Adjust the charge balance to reflect the new disbursement // Adjust the charge balance to reflect the new disbursement
$charge['balance'] = round($charge['balance'] - $disbursement_amount, 2); $charge['balance'] -= $disbursement_amount;
$this->pr(20, compact('charge', 'disbursement_amount'),
($charge['balance'] > 0 ? 'Unfinished' : 'Fully Paid') . ' Charge');
if ($charge['balance'] < 0) if ($charge['balance'] < 0)
die("HOW DID WE GET A NEGATIVE CHARGE AMOUNT?"); die("HOW DID WE GET A NEGATIVE CHARGE AMOUNT?");
if ($charge['balance'] <= 0)
$this->pr(20, 'Fully Paid Charge');
} }
// Break the $credit reference to avoid future problems // Break the $credit reference to avoid future problems
unset($credit); unset($credit);

View File

@@ -163,7 +163,7 @@ class ToolbarComponent extends Object {
trigger_error(sprintf(__('Could not load DebugToolbar panel %s', true), $panel), E_USER_WARNING); trigger_error(sprintf(__('Could not load DebugToolbar panel %s', true), $panel), E_USER_WARNING);
continue; continue;
} }
$panelObj = new $className(); $panelObj =& new $className();
if (is_subclass_of($panelObj, 'DebugPanel') || is_subclass_of($panelObj, 'debugpanel')) { if (is_subclass_of($panelObj, 'DebugPanel') || is_subclass_of($panelObj, 'debugpanel')) {
$this->panels[$panel] =& $panelObj; $this->panels[$panel] =& $panelObj;
} }
@@ -456,7 +456,7 @@ class LogPanel extends DebugPanel {
* @return array * @return array
*/ */
function _parseFile($filename) { function _parseFile($filename) {
$file = new File($filename); $file =& new File($filename);
$contents = $file->read(); $contents = $file->read();
$timePattern = '/(\d{4}-\d{2}\-\d{2}\s\d{1,2}\:\d{1,2}\:\d{1,2})/'; $timePattern = '/(\d{4}-\d{2}\-\d{2}\s\d{1,2}\:\d{1,2}\:\d{1,2})/';
$chunks = preg_split($timePattern, $contents, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); $chunks = preg_split($timePattern, $contents, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

View File

@@ -49,7 +49,7 @@ class DebugViewTestCase extends CakeTestCase {
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::parse('/'); Router::parse('/');
$this->Controller =& ClassRegistry::init('Controller'); $this->Controller =& ClassRegistry::init('Controller');
$this->View = new DebugView($this->Controller, false); $this->View =& new DebugView($this->Controller, false);
$this->_debug = Configure::read('debug'); $this->_debug = Configure::read('debug');
} }
@@ -98,7 +98,7 @@ class DebugViewTestCase extends CakeTestCase {
'here' => '/posts/index', 'here' => '/posts/index',
); );
$this->Controller->layout = 'default'; $this->Controller->layout = 'default';
$View = new DebugView($this->Controller, false); $View =& new DebugView($this->Controller, false);
$View->render('index'); $View->render('index');
$result = DebugKitDebugger::getTimers(); $result = DebugKitDebugger::getTimers();

View File

@@ -41,8 +41,8 @@ class FirePhpToolbarHelperTestCase extends CakeTestCase {
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::parse('/'); Router::parse('/');
$this->Toolbar = new ToolbarHelper(array('output' => 'DebugKit.FirePhpToolbar')); $this->Toolbar =& new ToolbarHelper(array('output' => 'DebugKit.FirePhpToolbar'));
$this->Toolbar->FirePhpToolbar = new FirePhpToolbarHelper(); $this->Toolbar->FirePhpToolbar =& new FirePhpToolbarHelper();
$this->Controller =& ClassRegistry::init('Controller'); $this->Controller =& ClassRegistry::init('Controller');
if (isset($this->_debug)) { if (isset($this->_debug)) {

View File

@@ -38,10 +38,10 @@ class HtmlToolbarHelperTestCase extends CakeTestCase {
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::parse('/'); Router::parse('/');
$this->Toolbar = new ToolbarHelper(array('output' => 'DebugKit.HtmlToolbar')); $this->Toolbar =& new ToolbarHelper(array('output' => 'DebugKit.HtmlToolbar'));
$this->Toolbar->HtmlToolbar = new HtmlToolbarHelper(); $this->Toolbar->HtmlToolbar =& new HtmlToolbarHelper();
$this->Toolbar->HtmlToolbar->Html = new HtmlHelper(); $this->Toolbar->HtmlToolbar->Html =& new HtmlHelper();
$this->Toolbar->HtmlToolbar->Javascript = new JavascriptHelper(); $this->Toolbar->HtmlToolbar->Javascript =& new JavascriptHelper();
$this->Controller =& ClassRegistry::init('Controller'); $this->Controller =& ClassRegistry::init('Controller');
if (isset($this->_debug)) { if (isset($this->_debug)) {

View File

@@ -30,14 +30,14 @@ $timers = DebugKitDebugger::getTimers();
?> ?>
<h2><?php __('Timers'); ?></h2> <h2><?php __('Timers'); ?></h2>
<p class="request-time"> <p class="request-time">
<?php $totalTime = sprintf(__('%s (seconds)', true), DebugKitDebugger::requestTime()); ?> <?php $totalTime = sprintf(__('%s (seconds)', true), $number->precision(DebugKitDebugger::requestTime(), 6)); ?>
<?php echo $toolbar->message(__('Total Request Time:', true), $totalTime)?> <?php echo $toolbar->message(__('Total Request Time:', true), $totalTime)?>
</p> </p>
<?php foreach ($timers as $timerName => $timeInfo): <?php foreach ($timers as $timerName => $timeInfo):
$rows[] = array( $rows[] = array(
$timeInfo['message'], $timeInfo['message'],
$timeInfo['time'] $number->precision($timeInfo['time'], 6)
); );
$headers = array(__('Message', true), __('time in seconds', true)); $headers = array(__('Message', true), __('time in seconds', true));
endforeach; endforeach;

View File

@@ -1,176 +0,0 @@
<?php /* -*- mode:PHP -*- */ ?>
<div class="customer merge">
<?php
; // Editor alignment
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Javascript
*/
// Warnings _really_ screw up javascript
$saved_debug_state = Configure::read('debug');
Configure::write('debug', '0');
?>
<script type="text/javascript"><!--
// pre-submit callback
function verifyRequest() {
if (!$("#src-customer-id").val()) {
alert("Must select source customer");
return false;
}
rows = $('#<?php echo "contacts-jqGrid"; ?>').getGridParam('selarrrow');
$('#<?php echo "contact-ids"; ?>').val(serialize(rows));
// return false to prevent the form from being submitted;
// anything other than false will allow submission.
return true;
}
function updateContacts() {
$('#contacts-jqGrid').clearGridData();
var filter = new Array();
filter['ContactsCustomer.customer_id'] = $("#src-customer-id").val();
var dynamic_post = new Array();
dynamic_post['filter'] = filter;
$('#contacts-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#contacts-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
}
function onRowSelect(grid_id, customer_id) {
//$('#output-debug').append("select: "+grid_id+"; "+customer_id+"<BR>\n");
// Set the item id that will be returned with the form
$("#src-customer-id").val(customer_id);
// Get the item name from the grid
$("#src-customer-name").html($(grid_id).getCell(customer_id, "Customer-name"));
updateContacts();
$("#customers-list .HeaderButton").click();
}
function onGridState(grid_id, state) {
//$('#output-debug').append("state: "+grid_id+"; "+state+"<BR>\n");
if (state == 'visible') {
$(".customer-selection-invalid").hide();
$(".customer-selection-valid").hide();
}
else {
if ($("#src-customer-id").val() > 0) {
$(".customer-selection-invalid").hide();
$(".customer-selection-valid").show();
} else {
$(".customer-selection-invalid").show();
$(".customer-selection-valid").hide();
}
}
}
--></script>
<?php
; // align
// Re-Enable warnings
Configure::write('debug', $saved_debug_state);
echo $form->create(null, array('id' => 'customer-merge-form',
'onsubmit' => 'return verifyRequest();',
'url' => array('controller' => 'customers',
'action' => 'mergeFinal')))."\n";
echo '<input type="hidden" id="src-customer-id" name="src-id" value="0" />'."\n";
echo '<input type="hidden" id="dst-customer-id" name="dst-id" value="'.$dst_id.'" />'."\n";
echo $this->element('customers', array
('config' => array
('grid_div_id' => 'customers-list',
'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#customers-list .HeaderButton\').click();'.
' return false;">Select Customer</A>'),
'grid_events' => array('onSelectRow' =>
array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
'onHeaderClick' =>
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'filter' => array('Customer.id !=' => $dst_id),
//'nolinks' => true,
'limit' => 10,
)));
echo ('<DIV CLASS="customer-merge grid-selection-text">' .
'<DIV CLASS="customer-selection-valid" style="display:none">' .
'Destination Customer: <SPAN id="src-customer-name"></SPAN>' .
'</DIV>' .
'<DIV CLASS="customer-selection-invalid" style="display:none">' .
'Please select customer to merge into' .
'</DIV>' .
'</DIV>' . "\n");
echo $this->element('contacts', array
(// Grid configuration
'config' => array
(
'grid_div_id' => 'contacts',
'grid_setup' => array('multiselect' => true),
'caption' => 'Source contacts to keep',
'filter' => array('ContactsCustomer.customer_id' => 0),
'include' => array('Relationship', 'License', 'Comment'),
),
));
// Add a hidden item to hold the jqGrid selection,
// which we'll populate prior to form submission.
echo "\n";
echo '<input type="hidden" id="contact-ids" name="contact-ids" value="" />'."\n";
?>
<H3>WARNING!</H3>
The above selected customer is about to be deleted, and all related data (leases, transactions, etc) will be merged into customer #<?php echo $dst_id ?>: <?php echo $dst_name ?>. This process is NOT reversible, so please ensure the selections are correct before proceeding.<BR>
<?php
echo $form->end('Merge Customers') . "\n";
?>
<div id="output-debug" style="display:none"></div>
<?php
// Warnings _really_ screw up javascript
Configure::write('debug', '0');
?>
<script type="text/javascript"><!--
$(document).ready(function(){
$("#src-customer-id").val(0);
$("#src-customer-name").html("INTERNAL ERROR");
//onGridState(null, 'visible');
<?php if ($this->params['dev']): ?>
$('#output-debug').show();
<?php endif; ?>
});
--></script>
</div>

View File

@@ -48,34 +48,26 @@ function verifyRequest(formData, jqForm, options) {
if (formData[i]['name'] == "data[Customer][id]" && if (formData[i]['name'] == "data[Customer][id]" &&
!(formData[i]['value'] > 0)) { !(formData[i]['value'] > 0)) {
//$("#debug").append('<P>Missing Customer ID'); //$("#debug").append('<P>Missing Customer ID');
alert("Please select a customer first."); alert("Must select a customer first");
return false; return false;
} }
if (formData[i]['name'] == "data[Transaction][stamp]" && if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') { formData[i]['value'] == '') {
//$("#debug").append('<P>Bad Stamp'); //$("#debug").append('<P>Bad Stamp');
if (formData[i]['value'] != '') alert("Must enter a valid date stamp");
alert(formData[i]['value'] + " is not valid date stamp. Please correct it.");
else
alert("Please enter a valid date stamp first.");
return false; return false;
} }
// Terrible way to accomplish this... // Terrible way to accomplish this...
for (var j = 0; j < 20; ++j) { for (var j = 0; j < 20; ++j) {
if (formData[i]['name'] == "data[Entry]["+j+"][amount]") { if (formData[i]['name'] == "data[Entry]["+j+"][amount]" &&
var val = formData[i]['value'].replace(/\$/,''); !(formData[i]['value'] > 0)) {
//$("#debug").append('<P>Bad Amount'); //$("#debug").append('<P>Bad Amount');
if (!(val > 0)) { alert("Must enter a valid amount");
if (formData[i]['value'] == '')
alert("Please enter an amount first.");
else
alert('"'+formData[i]['value']+'"' + " is not valid amount. Please correct it.");
return false; return false;
} }
} }
}
} }
@@ -130,11 +122,11 @@ function updateCharges(id) {
$("#receipt-balance").html("Calculating..."); $("#receipt-balance").html("Calculating...");
$("#receipt-charges-caption").html("Please Wait..."); $("#receipt-charges-caption").html("Please Wait...");
var filter = new Array(); var custom = new Array();
filter['StatementEntry.customer_id'] = id; custom['customer_id'] = id;
var dynamic_post = new Array(); var dynamic_post = new Array();
dynamic_post['filter'] = filter; dynamic_post['custom'] = custom;
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post)); $('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#charge-entries-jqGrid') $('#charge-entries-jqGrid')
@@ -333,7 +325,7 @@ echo $this->element('statement_entries', array
'action' => 'unreconciled', 'action' => 'unreconciled',
'exclude' => array('Customer', 'Type', 'Debit', 'Credit'), 'exclude' => array('Customer', 'Type', 'Debit', 'Credit'),
'include' => array('Applied', 'Balance'), 'include' => array('Applied', 'Balance'),
'remap' => array('Received' => 'Paid'), 'remap' => array('Applied' => 'Paid'),
'limit' => 8, 'limit' => 8,
), ),
)); ));

View File

@@ -53,55 +53,15 @@ echo '<div CLASS="detail supporting">' . "\n";
/********************************************************************** /**********************************************************************
* Unpaid Charges * Contacts
*/ */
echo $this->element('statement_entries', array echo $this->element('contacts', array
(// Grid configuration (// Grid configuration
'config' => array 'config' => array
('caption' => 'Outstanding Charges', ('caption' => 'Customer Contacts',
'limit' => 10, 'filter' => array('Customer.id' => $customer['Customer']['id']),
'action' => 'unreconciled', 'include' => array('Relationship'),
'filter' => array('StatementEntry.customer_id' => $customer['Customer']['id']),
'exclude' => array('Customer'),
)));
/**********************************************************************
* Customer Credits
*/
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Oustanding Credits',
'grid_div_id' => 'surplus',
'limit' => 10,
'filter' => array('Customer.id' => $customer['Customer']['id'],
'StatementEntry.type' => 'SURPLUS'),
'exclude' => array('Entry', 'Effective', 'Customer', 'Unit', 'Account', 'Debit', 'Credit'),
'include' => array('Transaction', 'Amount'),
'remap' => array('Transaction' => 'Receipt'),
)));
/**********************************************************************
* Receipt History
*/
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('caption' => 'Receipts',
'limit' => 5,
'filter' => array('Customer.id' => $customer['Customer']['id'],
'Transaction.type' => 'RECEIPT',
'Tender.id !=' => null,
//'Account.id !=' => '-AR-'
),
'include' => array('Transaction'),
'exclude' => array('Entry', 'Account', 'Cr/Dr'),
'remap' => array('Transaction' => 'Receipt'),
))); )));
@@ -113,7 +73,6 @@ echo $this->element('leases', array
(// Grid configuration (// Grid configuration
'config' => array 'config' => array
('caption' => 'Lease History', ('caption' => 'Lease History',
'limit' => 5,
'filter' => array('Customer.id' => $customer['Customer']['id']), 'filter' => array('Customer.id' => $customer['Customer']['id']),
'exclude' => array('Customer'), 'exclude' => array('Customer'),
'sort_column' => 'Move-In', 'sort_column' => 'Move-In',
@@ -121,20 +80,6 @@ echo $this->element('leases', array
))); )));
/**********************************************************************
* Contacts
*/
echo $this->element('contacts', array
(// Grid configuration
'config' => array
('caption' => 'Customer Contacts',
'limit' => 5,
'filter' => array('Customer.id' => $customer['Customer']['id']),
'include' => array('Relationship'),
)));
/********************************************************************** /**********************************************************************
* Customer Account History * Customer Account History
*/ */
@@ -145,11 +90,28 @@ echo $this->element('statement_entries', array
('caption' => 'Customer Statement', ('caption' => 'Customer Statement',
'filter' => array('Customer.id' => $customer['Customer']['id'], 'filter' => array('Customer.id' => $customer['Customer']['id'],
'type !=' => 'VOID'), 'type !=' => 'VOID'),
//'include' => array('Sub-Total'),
'exclude' => array('Customer'), 'exclude' => array('Customer'),
))); )));
/**********************************************************************
* Receipt History
*/
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('caption' => 'Receipts',
'filter' => array('Customer.id' => $customer['Customer']['id'],
'Transaction.type' => 'RECEIPT',
'Tender.id !=' => null,
//'Account.id !=' => '-AR-'
),
'include' => array('Transaction'),
'exclude' => array('Entry', 'Account', 'Cr/Dr'),
)));
/* End "detail supporting" div */ /* End "detail supporting" div */
echo '</div>' . "\n"; echo '</div>' . "\n";

View File

@@ -6,7 +6,6 @@ $cols['Relationship'] = array('index' => 'ContactsCustomer.type', 'formatter'
$cols['Name'] = array('index' => 'Contact.display_name', 'formatter' => 'longname'); $cols['Name'] = array('index' => 'Contact.display_name', 'formatter' => 'longname');
$cols['Last Name'] = array('index' => 'Contact.last_name', 'formatter' => 'name'); $cols['Last Name'] = array('index' => 'Contact.last_name', 'formatter' => 'name');
$cols['First Name'] = array('index' => 'Contact.first_name', 'formatter' => 'name'); $cols['First Name'] = array('index' => 'Contact.first_name', 'formatter' => 'name');
$cols['License'] = array('index' => 'Contact.id_local', 'formatter' => 'name');
$cols['Company'] = array('index' => 'Contact.company_name', 'formatter' => 'longname'); $cols['Company'] = array('index' => 'Contact.company_name', 'formatter' => 'longname');
$cols['Comment'] = array('index' => 'Contact.comment', 'formatter' => 'comment'); $cols['Comment'] = array('index' => 'Contact.comment', 'formatter' => 'comment');
@@ -17,4 +16,4 @@ $grid
->defaultFields(array('Last Name', 'First Name')) ->defaultFields(array('Last Name', 'First Name'))
->searchFields(array('Last Name', 'First Name', 'Company')) ->searchFields(array('Last Name', 'First Name', 'Company'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Relationship', 'License', 'Comment'))); array_diff(array_keys($cols), array('Relationship', 'Comment')));

View File

@@ -6,9 +6,7 @@ $cols['Relationship'] = array('index' => 'ContactsCustomer.type', 'formatt
$cols['Name'] = array('index' => 'Customer.name', 'formatter' => 'longname'); $cols['Name'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Last Name'] = array('index' => 'PrimaryContact.last_name', 'formatter' => 'name'); $cols['Last Name'] = array('index' => 'PrimaryContact.last_name', 'formatter' => 'name');
$cols['First Name'] = array('index' => 'PrimaryContact.first_name', 'formatter' => 'name'); $cols['First Name'] = array('index' => 'PrimaryContact.first_name', 'formatter' => 'name');
$cols['Units'] = array('index' => 'current_lease_count', 'formatter' => 'number'); $cols['Leases'] = array('index' => 'current_lease_count', 'formatter' => 'number');
$cols['Past Leases'] = array('index' => 'past_lease_count', 'formatter' => 'number');
$cols['Leases'] = array('index' => 'lease_count', 'formatter' => 'number');
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency'); $cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
$cols['Comment'] = array('index' => 'Customer.comment', 'formatter' => 'comment'); $cols['Comment'] = array('index' => 'Customer.comment', 'formatter' => 'comment');
@@ -19,4 +17,4 @@ $grid
->defaultFields(array('Name')) ->defaultFields(array('Name'))
->searchFields(array('Name', 'Last Name', 'First Name')) ->searchFields(array('Name', 'Last Name', 'First Name'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Relationship', 'Past Leases', 'Comment'))); array_diff(array_keys($cols), array('Relationship', 'Comment')));

View File

@@ -4,7 +4,6 @@
$cols = array(); $cols = array();
$cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id'); $cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id');
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname', 'align' => 'center'); $cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname', 'align' => 'center');
$cols['Customer id'] = array('index' => 'Customer.id', 'hidden' => true);
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname'); $cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Rent'] = array('index' => 'Lease.rent', 'formatter' => 'currency'); $cols['Rent'] = array('index' => 'Lease.rent', 'formatter' => 'currency');
$cols['Deposit'] = array('index' => 'Lease.deposit', 'formatter' => 'currency'); $cols['Deposit'] = array('index' => 'Lease.deposit', 'formatter' => 'currency');
@@ -12,7 +11,6 @@ $cols['Signed'] = array('index' => 'Lease.lease_date', 'formatter' => 'dat
$cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date'); $cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date');
$cols['Move-Out'] = array('index' => 'Lease.moveout_date', 'formatter' => 'date'); $cols['Move-Out'] = array('index' => 'Lease.moveout_date', 'formatter' => 'date');
$cols['Closed'] = array('index' => 'Lease.close_date', 'formatter' => 'date'); $cols['Closed'] = array('index' => 'Lease.close_date', 'formatter' => 'date');
$cols['Charge-Thru'] = array('index' => 'Lease.charge_through_date', 'formatter' => 'date');
$cols['Paid-Thru'] = array('index' => 'Lease.paid_through_date', 'formatter' => 'date'); $cols['Paid-Thru'] = array('index' => 'Lease.paid_through_date', 'formatter' => 'date');
$cols['Status'] = array('index' => 'status', 'formatter' => 'longenum'); $cols['Status'] = array('index' => 'status', 'formatter' => 'longenum');
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency'); $cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
@@ -20,7 +18,7 @@ $cols['Comment'] = array('index' => 'Lease.comment', 'formatter' => 'com
if (!empty($this->params['action'])) { if (!empty($this->params['action'])) {
if ($this->params['action'] === 'closed') if ($this->params['action'] === 'closed')
$grid->invalidFields(array('Charge-Thru', 'Paid-Thru', 'Status')); $grid->invalidFields(array('Paid-Thru', 'Status'));
elseif ($this->params['action'] === 'active') elseif ($this->params['action'] === 'active')
$grid->invalidFields(array('Closed')); $grid->invalidFields(array('Closed'));
elseif ($this->params['action'] === 'delinquent') elseif ($this->params['action'] === 'delinquent')
@@ -34,4 +32,4 @@ $grid
->defaultFields(array('Lease')) ->defaultFields(array('Lease'))
->searchFields(array('Customer', 'Unit')) ->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Signed', 'Charge-Thru', 'Status', 'Comment'))); array_diff(array_keys($cols), array('Signed', 'Status', 'Comment')));

View File

@@ -21,7 +21,7 @@ $cols['Debit'] = array('index' => 'charge', 'formatter' =>
$cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency'); $cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency');
$cols['Amount'] = array('index' => "StatementEntry.amount", 'formatter' => 'currency'); $cols['Amount'] = array('index' => "StatementEntry.amount", 'formatter' => 'currency');
$cols['Received'] = array('index' => "applied", 'formatter' => 'currency'); $cols['Applied'] = array('index' => "applied", 'formatter' => 'currency');
// 'balance' is already in use as part of charge/disbursement/balance. // 'balance' is already in use as part of charge/disbursement/balance.
// 'unapplied' isn't quite the right term, but it's not customer visible. // 'unapplied' isn't quite the right term, but it's not customer visible.
$cols['Balance'] = array('index' => "unapplied", 'formatter' => 'currency'); $cols['Balance'] = array('index' => "unapplied", 'formatter' => 'currency');
@@ -32,22 +32,6 @@ if (isset($subtotal_column))
$cols['Sub-Total']['index'] = $cols['Sub-Total']['index'] =
'subtotal-' . $cols[$subtotal_column]['index']; 'subtotal-' . $cols[$subtotal_column]['index'];
if ((isset($action) && $action == 'unreconciled') ||
(isset($config) && isset($config['action']) && $config['action'] == 'unreconciled')) {
if (isset($config) && !isset($config['grid_div_id']))
$config['grid_div_id'] = 'unpaid';
$include_columns = array('Entry', 'Date',
'Effective', 'Customer', 'Unit',
'Account', 'Amount', 'Received', 'Balance');
}
else {
$include_columns =
array_diff(array_keys($cols),
array('Transaction', 'Through', 'Lease',
'Amount', 'Received', 'Balance', 'Sub-Total',
'Comment'));
}
// Include custom data // Include custom data
$grid->customData(compact('statement_entry_id')); $grid->customData(compact('statement_entry_id'));
@@ -57,5 +41,8 @@ $grid
->sortField('Date', 'DESC') ->sortField('Date', 'DESC')
->defaultFields(array('Entry', 'Date', 'Charge', 'Payment')) ->defaultFields(array('Entry', 'Date', 'Charge', 'Payment'))
->searchFields(array('Customer', 'Unit')) ->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null, $include_columns); ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Transaction', 'Through', 'Lease',
'Amount', 'Applied', 'Balance', 'Sub-Total',
'Comment')));

View File

@@ -1,18 +1,13 @@
<?php /* -*- mode:PHP -*- */ <?php /* -*- mode:PHP -*- */
if (isset($include))
$include = is_array($include) ? $include : array($include);
else
$include = array();
// Define the table columns // Define the table columns
$cols = array(); $cols = array();
$cols['ID'] = array('index' => 'Transaction.id', 'formatter' => 'id'); $cols['ID'] = array('index' => 'Transaction.id', 'formatter' => 'id');
$cols['Type'] = array('index' => 'Transaction.type', 'formatter' => 'enum'); $cols['Type'] = array('index' => 'Transaction.type', 'formatter' => 'enum');
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname'); //$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Timestamp'] = array('index' => 'Transaction.stamp', 'formatter' => 'date'); $cols['Timestamp'] = array('index' => 'Transaction.stamp', 'formatter' => 'date');
$cols['Amount'] = array('index' => 'Transaction.amount', 'formatter' => 'currency'); $cols['Amount'] = array('index' => 'Transaction.amount', 'formatter' => 'currency');
$cols['Entries'] = array('index' => 'entries', 'formatter' => 'number'); $cols['entries'] = array('index' => 'entries', 'formatter' => 'number');
$cols['Comment'] = array('index' => 'Transaction.comment', 'formatter' => 'comment'); $cols['Comment'] = array('index' => 'Transaction.comment', 'formatter' => 'comment');
// Render the grid // Render the grid
@@ -22,4 +17,4 @@ $grid
->defaultFields(array('ID', 'Timestamp')) ->defaultFields(array('ID', 'Timestamp'))
->searchFields(array('Type', 'Comment')) ->searchFields(array('Type', 'Comment'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_merge($include, array_diff(array_keys($cols), array('Customer', 'Comment')))); array_diff(array_keys($cols), array('Comment')));

View File

@@ -3,7 +3,6 @@
// Define the table columns // Define the table columns
$cols = array(); $cols = array();
$cols['Size'] = array('index' => 'UnitSize.name', 'formatter' => 'shortname'); $cols['Size'] = array('index' => 'UnitSize.name', 'formatter' => 'shortname');
$cols['Type'] = array('index' => 'UnitType.name', 'formatter' => 'shortname');
$cols['Width'] = array('index' => 'UnitSize.width', 'formatter' => 'number'); $cols['Width'] = array('index' => 'UnitSize.width', 'formatter' => 'number');
$cols['Depth'] = array('index' => 'UnitSize.depth', 'formatter' => 'number'); $cols['Depth'] = array('index' => 'UnitSize.depth', 'formatter' => 'number');
$cols['Height'] = array('index' => 'UnitSize.height', 'formatter' => 'number'); $cols['Height'] = array('index' => 'UnitSize.height', 'formatter' => 'number');
@@ -11,8 +10,8 @@ $cols['Area'] = array('index' => 'sqft', 'formatter' => 'nu
$cols['Volume'] = array('index' => 'cuft', 'formatter' => 'number'); $cols['Volume'] = array('index' => 'cuft', 'formatter' => 'number');
$cols['Deposit'] = array('index' => 'UnitSize.deposit', 'formatter' => 'currency'); $cols['Deposit'] = array('index' => 'UnitSize.deposit', 'formatter' => 'currency');
$cols['Rent'] = array('index' => 'UnitSize.rent', 'formatter' => 'currency'); $cols['Rent'] = array('index' => 'UnitSize.rent', 'formatter' => 'currency');
$cols['Per Foot'] = array('index' => 'sqcost', 'formatter' => 'currency'); $cols['A. Cost'] = array('index' => 'sqcost', 'formatter' => 'currency');
$cols['Per Cubic Ft'] = array('index' => 'cucost', 'formatter' => 'currency'); $cols['V. Cost'] = array('index' => 'cucost', 'formatter' => 'currency');
$cols['Unavailable'] = array('index' => 'unavailable', 'formatter' => 'number'); $cols['Unavailable'] = array('index' => 'unavailable', 'formatter' => 'number');
$cols['Occupied'] = array('index' => 'occupied', 'formatter' => 'number'); $cols['Occupied'] = array('index' => 'occupied', 'formatter' => 'number');
$cols['Available'] = array('index' => 'available', 'formatter' => 'number'); $cols['Available'] = array('index' => 'available', 'formatter' => 'number');
@@ -28,13 +27,7 @@ $grid
->defaultFields(array('Size', 'Area')) ->defaultFields(array('Size', 'Area'))
->searchFields(array('Size', 'Width', 'Depth', 'Area', 'Deposit', 'Rent')) ->searchFields(array('Size', 'Width', 'Depth', 'Area', 'Deposit', 'Rent'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Width', 'Depth', array_diff(array_keys($cols), array('Height', 'Volume',
'Deposit', 'A. Cost', 'V. Cost',
'Height', 'Volume', 'Occupied', 'Total', 'Occupancy', 'Vacancy',
//'Per Foot',
'Per Cubic Ft',
'Occupied',
//'Total',
'Occupancy',
//'Vacancy',
'Comment'))); 'Comment')));

View File

@@ -47,13 +47,6 @@ class FormatHelper extends AppHelper {
return $currency; return $currency;
} }
function percent($amount, $precision = 2) {
if (!isset($amount))
return '-';
return self::$number->toPercentage($amount*100, $precision);
}
function date($date, $age = false, $class = null, $time = false) { function date($date, $age = false, $class = null, $time = false) {
if (!$date) return null; if (!$date) return null;

View File

@@ -215,12 +215,6 @@ class GridHelper extends AppHelper {
} }
$this->jqGrid_options['controller'] = $controller; $this->jqGrid_options['controller'] = $controller;
// Add in any custom variables requested
if (isset($config['custom'])) {
$this->customData($config['custom']);
unset($config['custom']);
}
// Incorporate all other user options // Incorporate all other user options
if (isset($config)) if (isset($config))
$this->jqGrid_options = array_merge($this->jqGrid_options, $config); $this->jqGrid_options = array_merge($this->jqGrid_options, $config);

View File

@@ -58,6 +58,10 @@
$protocol = 'http://'; $protocol = 'http://';
echo $html->meta('icon') . "\n"; echo $html->meta('icon') . "\n";
echo $html->css('cake.generic') . "\n";
echo $html->css('layout') . "\n";
echo $html->css('print', null, array('media' => 'print')) . "\n";
echo $html->css('sidemenu') . "\n";
$theme = 'smoothness'; $theme = 'smoothness';
$theme = 'base'; $theme = 'base';
@@ -69,11 +73,7 @@
if (sandbox()) if (sandbox())
$theme = 'darkness'; $theme = 'darkness';
echo $html->css('cake.generic') . "\n";
echo $html->css('themes/'.$theme.'/ui.all') . "\n"; echo $html->css('themes/'.$theme.'/ui.all') . "\n";
echo $html->css('layout') . "\n";
echo $html->css('print', null, array('media' => 'print')) . "\n";
echo $html->css('sidemenu') . "\n";
echo $javascript->link('jquery-1.3.2.min') . "\n"; echo $javascript->link('jquery-1.3.2.min') . "\n";
echo $javascript->link('jquery-ui-1.7.2.custom.min') . "\n"; echo $javascript->link('jquery-ui-1.7.2.custom.min') . "\n";

View File

@@ -10,7 +10,6 @@ $customer = $lease['Customer'];
if (isset($lease['Lease'])) if (isset($lease['Lease']))
$lease = $lease['Lease']; $lease = $lease['Lease'];
//pr(compact('unit', 'customer', 'lease', 'movein'));
/********************************************************************** /**********************************************************************
********************************************************************** **********************************************************************
@@ -26,8 +25,6 @@ Configure::write('debug', '0');
<script type="text/javascript"><!-- <script type="text/javascript"><!--
var lease_charge_through;
// prepare the form when the DOM is ready // prepare the form when the DOM is ready
$(document).ready(function() { $(document).ready(function() {
var options = { var options = {
@@ -65,27 +62,19 @@ function verifyRequest(formData, jqForm, options) {
if (formData[i]['name'] == "data[Transaction][stamp]" && if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') { formData[i]['value'] == '') {
//$("#debug").append('<P>Bad Stamp'); //$("#debug").append('<P>Bad Stamp');
if (formData[i]['value'] != '') alert("Must enter a valid date stamp");
alert(formData[i]['value'] + " is not valid date stamp. Please correct it.");
else
alert("Please enter a valid date stamp first.");
return false; return false;
} }
// Terrible way to accomplish this... // Terrible way to accomplish this...
for (var j = 0; j < 20; ++j) { /* for (var j = 0; j < 20; ++j) { */
if (formData[i]['name'] == "data[Entry]["+j+"][amount]") { /* if (formData[i]['name'] == "data[Entry]["+j+"][amount]" && */
var val = formData[i]['value'].replace(/\$/,''); /* !(formData[i]['value'] > 0)) { */
//$("#debug").append('<P>Bad Amount'); /* //$("#debug").append('<P>Bad Amount'); */
if (!(val > 0)) { /* alert("Must enter a valid amount"); */
if (formData[i]['value'] == '') /* return false; */
alert("Please enter an amount for Charge #"+j+", or remove the Charge completely."); /* } */
else /* } */
alert('"'+formData[i]['value']+'"' + " is not a valid amount for Charge #"+j+". Please correct it.");
return false;
}
}
}
} }
//$("#debug").append('OK'); //$("#debug").append('OK');
@@ -111,13 +100,13 @@ function showResponse(responseText, statusText) {
if (!$("#repeat").attr("checked")) { if (!$("#repeat").attr("checked")) {
window.location.href = window.location.href =
<?php if (empty($movein)): ?> <?php if (empty($movein)): ?>
"<?php echo $html->url(array('controller' => 'customers', "<?php echo $html->url(array('controller' => 'leases',
'action' => 'view')); ?>" 'action' => 'view')); ?>"
+ "/" + $("#customer-id").val(); + "/" + $("#lease-id").val();
<?php else: ?> <?php else: ?>
"<?php echo $html->url(array('controller' => 'customers', "<?php echo $html->url(array('controller' => 'customers',
'action' => 'receipt')); ?>" 'action' => 'receipt')); ?>"
+ "/" + $("#customer-id").val(); + "/" + "<?php echo $customer['id']; ?>";
<?php endif; ?> <?php endif; ?>
return; return;
} }
@@ -144,7 +133,6 @@ function resetForm(nocharge) {
function onRowSelect(grid_id, lease_id) { function onRowSelect(grid_id, lease_id) {
// Set the item id that will be returned with the form // Set the item id that will be returned with the form
$("#lease-id").val(lease_id); $("#lease-id").val(lease_id);
$("#customer-id").val($(grid_id).getCell(lease_id, 'Customer-id'));
$("#invoice-lease").html($(grid_id).getCell(lease_id, 'Lease-number')); $("#invoice-lease").html($(grid_id).getCell(lease_id, 'Lease-number'));
$("#invoice-unit").html($(grid_id).getCell(lease_id, 'Unit-name')); $("#invoice-unit").html($(grid_id).getCell(lease_id, 'Unit-name'));
@@ -154,7 +142,6 @@ function onRowSelect(grid_id, lease_id) {
$("#invoice-deposit").html($(grid_id).getCell(lease_id, 'Lease-deposit') $("#invoice-deposit").html($(grid_id).getCell(lease_id, 'Lease-deposit')
? $(grid_id).getCell(lease_id, 'Lease-deposit') ? $(grid_id).getCell(lease_id, 'Lease-deposit')
: '-'); : '-');
lease_charge_through = $(grid_id).getCell(lease_id, 'Lease-charge_through_date')
// Hide the "no lease" message and show the current lease // Hide the "no lease" message and show the current lease
$(".lease-selection-invalid").hide(); $(".lease-selection-invalid").hide();
@@ -180,78 +167,6 @@ function onGridState(grid_id, state) {
} }
} }
function setNextRent(id) {
var chg_thru;
$('.ChargeForm').each( function(i) {
if ($('.ChargeFormThroughDate', this).attr('id') == 'Entry'+id+'ThroughDate')
return;
if ($('.ChargeFormAccount option:selected', this).val() == <?php echo $rentAccount ?>
&& $('.ChargeFormThroughDate', this).val()) {
var dt = new Date($('.ChargeFormThroughDate', this).val());
//$('#debug').append('Rent in ' + i + '; date ' + dt + '<BR>');
if (chg_thru == null || dt > chg_thru)
chg_thru = dt;
}
});
if (!chg_thru)
chg_thru = new Date(lease_charge_through);
if (chg_thru < dateEOM(chg_thru)) {
// Add a charge to finish out the month
datepickerSet('Entry'+id+'EffectiveDate', dateTomorrow(chg_thru));
datepickerSet('Entry'+id+'ThroughDate', dateEOM(chg_thru));
} else {
// Add a whole month's charge for next month
datepickerSet('Entry'+id+'EffectiveDate', dateNextBOM(chg_thru));
datepickerSet('Entry'+id+'ThroughDate', dateNextEOM(chg_thru));
}
// Now add in the amount owed based on the calculated
// effective and through dates.
prorate(id);
}
function prorate(id) {
var edt = datepickerGet('Entry'+id+'EffectiveDate');
var tdt = datepickerGet('Entry'+id+'ThroughDate');
var rent = $('#invoice-rent').html().replace(/\$/,'');
// Reset the comment. It might wipe out a user comment,
// but it's probably low risk/concern
$('#Entry'+id+'Comment').val('');
if (edt == null || tdt == null) {
alert('Can only prorate with both effective and through dates');
rent = 0;
}
else if (edt > tdt) {
alert('Effective date is later than the Through date');
rent = 0;
}
else if (tdt.getMonth() == edt.getMonth() + 1 &&
edt.getDate() == tdt.getDate() + 1) {
// appears to be anniversary billing, one full cycle
}
else if (edt.getTime() == dateBOM(edt).getTime() &&
tdt.getTime() == dateEOM(edt).getTime()) {
// appears to be one full month
}
else {
var one_day=1000*60*60*24;
var days = Math.ceil((tdt.getTime()-edt.getTime()+1)/(one_day));
var dim =
((edt.getMonth() == tdt.getMonth())
? dateEOM(edt).getDate() // prorated within the month.
: 30); // prorated across months.
rent *= days / dim;
$('#Entry'+id+'Comment').val('Rent proration: '+days+'/'+dim+' days');
}
$('#Entry'+id+'Amount').val(fmtCurrency(rent));
}
function addChargeSource(flash) { function addChargeSource(flash) {
var id = $("#charge-entry-id").val(); var id = $("#charge-entry-id").val();
addDiv('charge-entry-id', 'charge', 'charges', flash, addDiv('charge-entry-id', 'charge', 'charges', flash,
@@ -263,32 +178,26 @@ function addChargeSource(flash) {
echo FormatHelper::phpVarToJavascript echo FormatHelper::phpVarToJavascript
($this->element('form_table', ($this->element('form_table',
array('id' => 'Entry%{id}Form', array('id' => 'Entry%{id}Form',
'class' => "ChargeForm item invoice ledger-entry entry", 'class' => "item invoice ledger-entry entry",
//'with_name_after' => ':', //'with_name_after' => ':',
'field_prefix' => 'Entry.%{id}', 'field_prefix' => 'Entry.%{id}',
'fields' => array 'fields' => array
("account_id" => array('name' => 'Account', ("account_id" => array('name' => 'Account',
'opts' => 'opts' =>
array('class' => 'ChargeFormAccount', array('options' => $chargeAccounts,
'options' => $chargeAccounts,
'value' => $defaultAccount, 'value' => $defaultAccount,
), ),
'between' => '<A HREF="#" ONCLICK="setNextRent(\'%{id}\'); return false;">Rent</A>',
), ),
"effective_date" => array('opts' => "effective_date" => array('opts' =>
array('class' => 'ChargeFormEffectiveDate', array('type' => 'text'),
'type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerBOM(\'TransactionStamp\',\'Entry%{id}EffectiveDate\'); return false;">BOM</A>', 'between' => '<A HREF="#" ONCLICK="datepickerBOM(\'TransactionStamp\',\'Entry%{id}EffectiveDate\'); return false;">BOM</A>',
), ),
"through_date" => array('opts' => "through_date" => array('opts' =>
array('class' => 'ChargeFormThroughDate', array('type' => 'text'),
'type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>', 'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>',
), ),
"amount" => array('opts' => array('class' => 'ChargeFormAmount invoice amount'), "amount" => array('opts' => array('class' => 'invoice amount')),
'between' => '<A HREF="#" ONCLICK="prorate(\'%{id}\'); return false;">Prorate</A>', "comment" => array('opts' => array('size' => 50)),
),
"comment" => array('opts' => array('class' => 'ChargeFormComment', 'size' => 50)),
), ),
))) . "+\n"; ))) . "+\n";
?> ?>
@@ -324,8 +233,7 @@ if (empty($movein))
array('gridstate' => array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'), 'onGridState("#"+$(this).attr("id"), gridstate)'),
), ),
'include' => array('Charge-Thru'), 'exclude' => array('Closed'),
'exclude' => array('Closed', 'Paid-Thru'),
'action' => 'active', 'action' => 'active',
'nolinks' => true, 'nolinks' => true,
'limit' => 10, 'limit' => 10,
@@ -363,10 +271,11 @@ echo $form->input("Lease.id",
'type' => 'hidden', 'type' => 'hidden',
'value' => 0)); 'value' => 0));
echo $form->input("Customer.id", if (!empty($movein))
echo $form->input("Customer.id",
array('id' => 'customer-id', array('id' => 'customer-id',
'type' => 'hidden', 'type' => 'hidden',
'value' => 0)); 'value' => $customer['id']));
/* echo '<fieldset CLASS="invoice">' . "\n"; */ /* echo '<fieldset CLASS="invoice">' . "\n"; */
/* echo ' <legend>Invoice</legend>' . "\n"; */ /* echo ' <legend>Invoice</legend>' . "\n"; */
@@ -421,46 +330,16 @@ Configure::write('debug', '0');
$('tr td:nth-child('+col+'), tr th:nth-child('+col+')', this).remove(); $('tr td:nth-child('+col+'), tr th:nth-child('+col+')', this).remove();
}; };
function addHidden(id, fld, name) {
$('#Entry'+id+fld).after
('<input type="hidden"' +
' name="data[Entry]['+id+']['+name+']"' +
' value="' + $('#Entry'+id+fld).val() + '">');
}
$(document).ready(function(){ $(document).ready(function(){
datepicker('TransactionStamp'); datepicker('TransactionStamp');
<?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
$("#customer-id").val(<?php echo $customer['id']; ?>);
$("#invoice-lease").html("<?php echo '#'.$lease['number']; ?>");
$("#invoice-unit").html("<?php echo $unit['name']; ?>");
$("#invoice-customer").html("<?php echo $customer['name']; ?>");
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['rent']); ?>");
$("#invoice-late").html("<?php echo FormatHelper::currency($defaultLate); ?>");
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['deposit']); ?>");
lease_charge_through = <?php
if ($lease['charge_through_date'])
echo 'new Date("'.date('m/d/Y', strtotime($lease['charge_through_date'])).'")';
elseif ($lease['paid_through_date'])
echo 'new Date("'.date('m/d/Y', strtotime($lease['paid_through_date'])).'")';
else
echo 'dateYesterday("'.date('m/d/Y', strtotime($lease['movein_date'])).'")';
?>;
<?php else: ?>
$("#lease-id").val(0); $("#lease-id").val(0);
$("#customer-id").val(<?php echo empty($movein) ? 0 : $customer['id']; ?>);
$("#invoice-lease").html("INTERNAL ERROR"); $("#invoice-lease").html("INTERNAL ERROR");
$("#invoice-unit").html("INTERNAL ERROR"); $("#invoice-unit").html("INTERNAL ERROR");
$("#invoice-customer").html("INTERNAL ERROR"); $("#invoice-customer").html("INTERNAL ERROR");
$("#invoice-rent").html("INTERNAL ERROR"); $("#invoice-rent").html("INTERNAL ERROR");
$("#invoice-late").html("INTERNAL ERROR"); $("#invoice-late").html("INTERNAL ERROR");
$("#invoice-deposit").html("INTERNAL ERROR"); $("#invoice-deposit").html("INTERNAL ERROR");
<?php endif; ?>
<?php if (empty($movein)): ?> <?php if (empty($movein)): ?>
@@ -477,7 +356,7 @@ Configure::write('debug', '0');
$('#TransactionStamp').after $('#TransactionStamp').after
('<input type="hidden"' + ('<input type="hidden"' +
' name="data[Transaction][stamp]"' + ' name="data[Transaction][stamp]"' +
' value="' + $("#TransactionStamp").val() + '">'); ' value="<?php echo date('m/d/Y', $movein['time']); ?>">');
$("#TransactionComment").val('Move-In Charges'); $("#TransactionComment").val('Move-In Charges');
<?php if ($movein['deposit'] != 0): ?> <?php if ($movein['deposit'] != 0): ?>
@@ -485,28 +364,61 @@ Configure::write('debug', '0');
$('#Entry'+id+'Form').removeCol(2); $('#Entry'+id+'Form').removeCol(2);
$('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true); $('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true);
$('#Entry'+id+'EffectiveDate').val("<?php echo date('m/d/Y', $movein['effective_time']); ?>"); $('#Entry'+id+'EffectiveDate').val("<?php echo date('m/d/Y', $movein['effective_time']); ?>");
addHidden(id, 'EffectiveDate', 'effective_date'); $('#Entry'+id+'EffectiveDate').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][effective_date]"' +
' value="<?php echo date('m/d/Y', $movein['effective_time']); ?>">');
$('#Entry'+id+'AccountId').val(<?php echo $securityDepositAccount; ?>); $('#Entry'+id+'AccountId').val(<?php echo $securityDepositAccount; ?>);
addHidden(id, 'AccountId', 'account_id'); $('#Entry'+id+'AccountId').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][account_id]"' +
' value="<?php echo $securityDepositAccount; ?>">');
$('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['deposit']); ?>"); $('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['deposit']); ?>");
addHidden(id, 'Amount', 'amount'); $('#Entry'+id+'Amount').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][amount]"' +
' value="<?php echo FormatHelper::currency($movein['deposit']); ?>">');
//$('#Entry'+id+'Comment').val('Move-In Security Deposit');
$('#Entry'+id+'Comment').removeAttr('disabled'); $('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?> <?php endif; ?>
id = addChargeSource(false); id = addChargeSource(false);
$('#Entry'+id+'Form').removeCol(2); $('#Entry'+id+'Form').removeCol(2);
$('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true); $('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true);
setNextRent(id); $('#Entry'+id+'EffectiveDate').val("<?php echo date('m/d/Y', $movein['effective_time']); ?>");
addHidden(id, 'EffectiveDate', 'effective_date'); $('#Entry'+id+'EffectiveDate').after
addHidden(id, 'ThroughDate', 'through_date'); ('<input type="hidden"' +
addHidden(id, 'AccountId', 'account_id'); ' name="data[Entry]['+id+'][effective_date]"' +
addHidden(id, 'Amount', 'amount'); ' value="<?php echo date('m/d/Y', $movein['effective_time']); ?>">');
$('#Entry'+id+'ThroughDate').val("<?php echo date('m/d/Y', $movein['through_time']); ?>");
$('#Entry'+id+'ThroughDate').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][through_date]"' +
' value="<?php echo date('m/d/Y', $movein['through_time']); ?>">');
$('#Entry'+id+'AccountId').val(<?php echo $rentAccount; ?>);
$('#Entry'+id+'AccountId').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][account_id]"' +
' value="<?php echo $rentAccount; ?>">');
$('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['prorated_rent']); ?>");
$('#Entry'+id+'Amount').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][amount]"' +
' value="<?php echo FormatHelper::currency($movein['prorated_rent']); ?>">');
$('#Entry'+id+'Comment').val("<?php echo($movein['prorated'] ? 'Move-In Rent (Prorated)' : ''); ?>");
$('#Entry'+id+'Comment').removeAttr('disabled'); $('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?> <?php endif; ?>
<?php if (isset($lease['id'])): ?> <?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
$("#invoice-lease").html("<?php echo '#'.$lease['number']; ?>");
$("#invoice-unit").html("<?php echo $unit['name']; ?>");
$("#invoice-customer").html("<?php echo $customer['name']; ?>");
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['rent']); ?>");
$("#invoice-late").html("<?php echo FormatHelper::currency($defaultLate); ?>");
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['deposit']); ?>");
onGridState(null, 'hidden'); onGridState(null, 'hidden');
<?php else: ?> <?php else: ?>
onGridState(null, 'visible'); onGridState(null, 'visible');

View File

@@ -1,74 +0,0 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="lease overview">' . "\n";
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Overview Main Section
*/
/*
$rows = array();
$rows[] = array('', FormatHelper::currency($overview['']));
echo $this->element('table',
array('class' => 'item lease detail',
'caption' => '',
'rows' => $rows,
'column_class' => array('field', 'value')));
*/
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Supporting Elements Section
*/
echo '<div CLASS="detail supporting">' . "\n";
$headers = array('', 'Count');
$row_class = array();
$rows = array();
foreach ($overview['months'] AS $month) {
$row_class[] = 'subheader';
$rows[] = array($month['name']);
$odd = 1;
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array('Beginning of Month', $month['start']); $odd = !$odd;
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array('+ Move-Ins', $month['movein']); $odd = !$odd;
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array('- Move-Outs', $month['moveout']); $odd = !$odd;
$row_class[] = 'grand';
$rows[] = array('End of ' . $month['name'], $month['finish']);
}
echo $this->element('table',
array('class' => 'item lease-overview overview list',
'caption' => 'Leased Units By Month',
'headers' => $headers,
'rows' => $rows,
'row_class' => $row_class,
'suppress_alternate_rows' => true
));
?>
<script type="text/javascript"><!--
jQuery(document).ready(function(){
jQuery('table.overview td.subheader').attr('colSpan', 2);
});
--></script>
<?php
/* End "detail supporting" div */
echo '</div>' . "\n";
/* End page div */
echo '</div>' . "\n";

View File

@@ -78,21 +78,6 @@ echo '</div>' . "\n";
echo '<div CLASS="detail supporting">' . "\n"; echo '<div CLASS="detail supporting">' . "\n";
/**********************************************************************
* Unpaid Charges
*/
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Outstanding Charges',
'limit' => 10,
'action' => 'unreconciled',
'filter' => array('StatementEntry.lease_id' => $lease['id']),
'exclude' => array('Customer', 'Unit'),
)));
/********************************************************************** /**********************************************************************
* Lease Account History * Lease Account History
*/ */
@@ -107,6 +92,24 @@ echo $this->element('statement_entries', array
))); )));
/**********************************************************************
* Receipt History
*/
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('caption' => 'Customer Receipts',
'filter' => array('Customer.id' => $customer['id'],
'Transaction.type' => 'RECEIPT',
'Tender.id !=' => null,
//'Account.id !=' => '-AR-'
),
'include' => array('Transaction'),
'exclude' => array('Entry', 'Account', 'Cr/Dr'),
)));
/* End "detail supporting" div */ /* End "detail supporting" div */
echo '</div>' . "\n"; echo '</div>' . "\n";

View File

@@ -1,69 +0,0 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="statement_entry overview">' . "\n";
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Overview Main Section
*/
$rows = array();
$rows[] = array("$months Month Charges", FormatHelper::currency($overview['charges']));
echo $this->element('table',
array('class' => 'item statement_entry detail',
'caption' => 'Monthly Charges',
'rows' => $rows,
'column_class' => array('field', 'value')));
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Supporting Elements Section
*/
echo '<div CLASS="detail supporting">' . "\n";
$headers = array('Account', 'Amount');
$row_class = array();
$rows = array();
foreach ($overview['months'] AS $month) {
$row_class[] = 'subheader';
$rows[] = array($month['name']);
$odd = 1;
foreach ($month['subs'] AS $sub) {
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array($sub['name'], FormatHelper::currency($sub['charges']));
$odd = !$odd;
}
$row_class[] = 'grand';
$rows[] = array('Total for '.$month['name'], FormatHelper::currency($month['charges']));
}
echo $this->element('table',
array('class' => 'item statement_entry-overview overview list',
'caption' => 'Months',
'headers' => $headers,
'rows' => $rows,
'row_class' => $row_class,
'suppress_alternate_rows' => true
));
?>
<script type="text/javascript"><!--
jQuery(document).ready(function(){
jQuery('table.overview td.subheader').attr('colSpan', 2);
});
--></script>
<?php
/* End "detail supporting" div */
echo '</div>' . "\n";
/* End page div */
echo '</div>' . "\n";

View File

@@ -33,10 +33,8 @@ for ($i=1; $i<=4; ++$i)
if (!empty($ttype["data{$i}_name"])) if (!empty($ttype["data{$i}_name"]))
$rows[] = array($ttype["data{$i}_name"], $tender["data{$i}"]); $rows[] = array($ttype["data{$i}_name"], $tender["data{$i}"]);
$rows[] = array('Deposit', if (!empty($tender['deposit_transaction_id']))
empty($tender['deposit_transaction_id']) $rows[] = array('Deposit', $html->link('#'.$tender['deposit_transaction_id'],
? "-"
: $html->link('#'.$tender['deposit_transaction_id'],
array('controller' => 'transactions', array('controller' => 'transactions',
'action' => 'deposit_slip', 'action' => 'deposit_slip',
$tender['deposit_transaction_id']))); $tender['deposit_transaction_id'])));

View File

@@ -1,128 +0,0 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="unit overview">' . "\n";
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Overview Main Section
*/
$rows = array();
$rows[] = array('Total Units', $overview['count']);
$rows[] = array('Gross Scheduled Rent', FormatHelper::currency($overview['rents']));
echo $this->element('table',
array('class' => 'item unit detail',
'caption' => 'Unit Overview',
'rows' => $rows,
'column_class' => array('field', 'value')));
/**********************************************************************
* Unit Overview Info Box
echo '<div class="infobox">' . "\n";
$rows = array();
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
$rows[] = array('Balance:', FormatHelper::currency($outstandingBalance));
echo $this->element('table',
array('class' => 'summary',
'rows' => $rows,
'column_class' => array('field', 'value'),
'suppress_alternate_rows' => true,
));
echo '</div>' . "\n";
*/
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Supporting Elements Section
*/
echo '<div CLASS="detail supporting">' . "\n";
/*
foreach ($overview['types'] AS $type) {
$headers = array('Status', 'Count', 'Rent',
'Physical', 'Economic', 'Physical (Facility)', 'Economic (Facility)');
$row_class = array();
$rows = array();
foreach ($type['subs'] AS $sub) {
$row_class[] = array();
$rows[] = array($sub['name'], $sub['count'], FormatHelper::currency($sub['rents']),
FormatHelper::percent($sub['phys_subpct'], 1),
FormatHelper::percent($sub['econ_subpct'], 1),
FormatHelper::percent($sub['phys_totpct'], 1),
FormatHelper::percent($sub['econ_totpct'], 1));
}
$row_class[] = 'grand';
$rows[] = array('Total '.$type['name'], $type['count'], FormatHelper::currency($type['rents']),
FormatHelper::percent(1, 1),
FormatHelper::percent(1, 1),
FormatHelper::percent($type['phys_pct'], 1),
FormatHelper::percent($type['econ_pct'], 1));
echo $this->element('table',
array('class' => 'item unit-overview overview list',
'caption' => $type['name'],
'headers' => $headers,
'rows' => $rows,
'row_class' => $row_class
));
}
*/
$headers = array('Status', 'Count', 'Rent',
'Physical', 'Economic', 'Physical<BR>(Facility)', 'Economic<BR>(Facility)');
$row_class = array();
$rows = array();
foreach ($overview['types'] AS $type) {
$row_class[] = 'subheader';
$rows[] = array($type['name']);
$odd = 1;
foreach ($type['subs'] AS $sub) {
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array($sub['name'], $sub['count'], FormatHelper::currency($sub['rents']),
FormatHelper::percent($sub['phys_subpct'], 1),
FormatHelper::percent($sub['econ_subpct'], 1),
FormatHelper::percent($sub['phys_totpct'], 1),
FormatHelper::percent($sub['econ_totpct'], 1));
$odd = !$odd;
}
$row_class[] = 'grand';
$rows[] = array('Total '.$type['name'], $type['count'], FormatHelper::currency($type['rents']),
FormatHelper::percent(1, 1),
FormatHelper::percent(1, 1),
FormatHelper::percent($type['phys_pct'], 1),
FormatHelper::percent($type['econ_pct'], 1));
}
echo $this->element('table',
array('class' => 'item unit-overview overview list',
'caption' => 'Unit Types',
'headers' => $headers,
'rows' => $rows,
'row_class' => $row_class,
'suppress_alternate_rows' => true
));
?>
<script type="text/javascript"><!--
jQuery(document).ready(function(){
jQuery('table.overview td.subheader').attr('colSpan', 7);
});
--></script>
<?php
/* End "detail supporting" div */
echo '</div>' . "\n";
/* End page div */
echo '</div>' . "\n";

View File

@@ -76,6 +76,26 @@ echo $this->element('leases', array
))); )));
/**********************************************************************
* Current Customer Lease Account History
*/
if (isset($current_lease['id'])) {
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
(
'caption' =>
('Current Lease Statement ('
. $current_lease['Customer']['name']
. ')'),
'filter' => array('Lease.id' => $current_lease['id']),
'include' => array('Through'),
'exclude' => array('Customer', 'Lease', 'Unit'),
)));
}
/* End "detail supporting" div */ /* End "detail supporting" div */
echo '</div>' . "\n"; echo '</div>' . "\n";

View File

@@ -19,10 +19,6 @@ td#pagecolumn { padding-left: 4mm; }
td#sidecolumn { width: 1% } td#sidecolumn { width: 1% }
/* Ignore themes that want to increase font size */
.ui-widget { font-size : 1.0em }
/************************************************************ /************************************************************
************************************************************ ************************************************************
* Panel captions * Panel captions
@@ -270,16 +266,6 @@ form#collected-form input[type=button] { float : left;
/* NSF items */ /* NSF items */
.nsf-tender { text-decoration: line-through; } .nsf-tender { text-decoration: line-through; }
/* Overview lists */
table.overview td.grand { border-top : 4px double #000; }
table.overview td.subheader { padding-top: 1em; padding-left: 0.5em; font-size: 150%; }
table.overview td:first-child.subitem { padding-left: 2em; }
table.overview td:first-child { text-align: left; }
table.overview td { text-align: right; }
table.overview td.oddrow { background : #f4f4f4; }
table.statement_entry-overview { width : 50% }
table.lease-overview { width : 50% }
/************************************************************ /************************************************************
************************************************************ ************************************************************

View File

@@ -16,14 +16,6 @@ div#debug-kit-toolbar
{ display: none; } { display: none; }
/************************************************************
* Form inputs
*/
/* The "page N / M" input box... make it look like normal text */
input[type='button'], input[type='submit'], input[type='reset']
{ display: none; }
/************************************************************ /************************************************************
* Grid display * Grid display
*/ */

View File

@@ -67,17 +67,7 @@ function dump(element, limit, depth) {
if (props.length == 0) if (props.length == 0)
return ''; return '';
if (typeof dump.dumpid == 'undefined') return pad + '<ol><li>' + props.join("</li>\n" + pad + pad1 + "<li>") + "</li>\n" + pad + "</ol>";
dump.dumpid = 0;
++dump.dumpid;
return (pad
+ '<A HREF="#" ONCLICK="$(\'#dumpid-'+dump.dumpid+'\').toggle(); return false;">(hide members)</A><BR>'
+ '<ol id="dumpid-'+dump.dumpid+'" STYLE="padding-top:0; margin-top:0;">'
+ '<li>'
+ props.join("</li>\n" + pad + pad1 + '<li id="dumpid-'+dump.dumpid+'">')
+ "</li>\n"
+ pad + "</ol>");
} }
function dump_window(element, limit) { function dump_window(element, limit) {
@@ -168,103 +158,70 @@ function datepicker(id) {
} }
} }
function datepickerGet(id) {
if (id == null)
dt = new Date();
else {
if ($("#"+id).datepicker != null && $("#"+id).datepicker('getDate') != null)
dt = new Date($("#"+id).datepicker('getDate'));
else if ($("#"+id).val())
dt = new Date($("#"+id).val());
else
dt = null;
}
return dt;
}
function datepickerStr(id) {
return dateStr(datepickerGet(id));
}
function datepickerSet(id, dt_or_str, usetime) {
if ($("#"+id).datepicker != null && $("#"+id).datepicker('getDate') != null) {
// datepicker seems to squash the time portion,
// so we have to pass in a copy of dt instead.
$("#"+id).datepicker('setDate', new Date(dt_or_str));
if (usetime)
$("#"+id).val($("#"+id).val() + ' ' + timeStr(dt_or_str));
}
else {
$("#"+id).val(dateStr(dt_or_str), usetime);
}
}
function datepickerNow(id, usetime) { function datepickerNow(id, usetime) {
datepickerSet(id, new Date(), usetime == null ? true : usetime); var now = new Date();
if ($("#"+id).datepicker != null) {
// datepicker seems to squash the time portion,
// so we have to pass in a copy of now instead.
$("#"+id).datepicker('setDate', new Date(now));
}
else {
$("#"+id).val(((now.getMonth()+1) < 10 ? '0' : '')
+ (now.getMonth()+1) + '/'
+ (now.getDate() < 10 ? '0' : '')
+ now.getDate() + '/'
+ now.getFullYear());
}
if (usetime == null)
usetime = true;
$("#"+id).val($("#"+id).val() +
(usetime
? (' '
+ (now.getHours() < 10 ? '0' : '')
+ now.getHours() + ':'
+ (now.getMinutes() < 10 ? '0' : '')
+ now.getMinutes())
: ''));
} }
function dateStr(dt_or_str, usetime) { function datepickerSet(fromid, id, a, b) {
var dt = new Date(dt_or_str); var dt;
if (fromid == null)
dt = new Date();
else {
if ($("#"+id).datepicker != null)
dt = new Date($("#"+fromid).datepicker('getDate'));
else
dt = new Date($("#"+fromid).val());
}
return (((dt.getMonth()+1) < 10 ? '0' : '') if (a != null)
dt.setDate(a);
if (b != null)
dt.setDate(b);
if ($("#"+id).datepicker != null)
$("#"+id).datepicker('setDate', dt);
else {
$("#"+id).val(((dt.getMonth()+1) < 10 ? '0' : '')
+ (dt.getMonth()+1) + '/' + (dt.getMonth()+1) + '/'
+ (dt.getDate() < 10 ? '0' : '') + (dt.getDate() < 10 ? '0' : '')
+ dt.getDate() + '/' + dt.getDate() + '/'
+ dt.getFullYear() + dt.getFullYear());
+ (usetime ? ' ' + timeStr(dt) : '')); }
} }
function timeStr(dt_or_str) { function datepickerBOM(fromid, id) {
var dt = new Date(dt_or_str); datepickerSet(fromid, id, 1);
return ((dt.getHours() < 10 ? '0' : '')
+ dt.getHours() + ':'
+ (dt.getMinutes() < 10 ? '0' : '')
+ dt.getMinutes());
} }
function dateAdd(dt_or_str, a, b, m, d) { function datepickerEOM(fromid, id) {
var dt = new Date(dt_or_str); datepickerSet(fromid, id, 32, 0);
if (m != null) {
dt.setDate(1);
dt.setMonth(dt.getMonth() + m);
//$('#debug').append('set month ('+m+') ' + (dt.getMonth() + m) + '= ' + dt + '<BR>');
}
if (d != null) {
dt.setDate(dt.getDate() + d);
//$('#debug').append('set day ('+d+') ' + (dt.getDate() + d) + '= ' + dt + '<BR>');
}
if (a != null) {
dt.setDate(a);
//$('#debug').append('set date ('+a+') = ' + dt + '<BR>');
}
if (b != null) {
dt.setDate(b);
//$('#debug').append('set date ('+b+') = ' + dt + '<BR>');
}
return dt;
} }
function dateYesterday(dt) { return dateAdd(dt,null,null,null,-1); }
function dateTomorrow(dt) { return dateAdd(dt,null,null,null,1); }
function dateBOM(dt) { return dateAdd(dt,1); }
function dateNextBOM(dt) { return dateAdd(dt,1,null,1); }
function dateEOM(dt) { return dateAdd(dt,32,0); }
function dateNextEOM(dt) { return dateAdd(dt,32,0,1); }
function datepickerBOM(fromid, id)
{ datepickerSet(id, dateBOM(datepickerGet(fromid))); }
function datepickerEOM(fromid, id)
{ datepickerSet(id, dateEOM(datepickerGet(fromid))); }
function datepickerNextBOM(fromid, id)
{ datepickerSet(id, dateNextBOM(datepickerGet(fromid))); }
function datepickerNextEOM(fromid, id)
{ datepickerSet(id, dateNextEOM(datepickerGet(fromid))); }
// REVISIT <AP>: 20090617 // REVISIT <AP>: 20090617
// I would rather use XML to pass from JS to PHP, but at the // I would rather use XML to pass from JS to PHP, but at the

223
todo.notes Normal file
View File

@@ -0,0 +1,223 @@
When performing a move-in, the receipt page is broken
when trying to enter a concession. javascript complains about
an invalid value, and the page is not submitted.
- Allegedly. I believe Shirley's browser was acting up
on her, and based on the logs, it seems that indeed
what ultimately worked just fine for a concession entry
was really the exact same page that was stuck. While
on the phone it was evident that here browser was
doing a javascript wig-out, and it wasn't related to
a slow internet connection.
Reversing a rent charge is not considered as part of the
"charged-through" date on the lease. Consequently, the
reversal itself ensures the charge is fully "paid", and
the "paid-through" date is also out of whack.
Add invoice rent helpers
- monthly proration tool
- select from/to dates, and hit "prorate"
- charge through date
- enter charge through date, and the invoice
will automatically have charges for each month
from the current charge-through date to the
new charge-through date.
- charge N months
- enter number of months, and the invoice
will automatically have charges for each month
from the current charge-through date for N months
- next rent
- same as, or instead of, "charge N months", where
N is 1
Add NSF Fee to the NSF entry page (It's hardcoded right now
in Transaction to $35).
NSF of an item with customer credit is broken.
Sub-Total is broken, since it will only subtotal the current
page of the grid. It needs to be implemented in SQL as it
was in early (VERY early) implementations. At that time, I
had to a use temporary variable to keep a running total. It
worked, but was MySQL specific.
Add a move-out charges field to the move-out page.
Otherwise, if the balance is zero, the lease will automatically
be closed and no more charges are possible. The other option
would just be a checkbox to say "close lease (no more charges)",
or let them clear it and have them close the lease manually.
Invoice
- Have some sort of rent-proration tool
- Have Rent automatically populate the Effective/Through
as well as rent (pro-rating if necessary). The dates
should take into account the customer charge through
date, as well as any other rents on the invoice.
Allow waiving a complete charge, even if it already has payments
applied (at the moment, we just can waive the charge balance).
Get Petty Cash working. We'll need to add one or more expense
accounts. We'll also need to implement purchase order
functionality, or at least simple an expense page.
Have a report indicating Needs-to-be-Locked. Allow manager
to go through this list and check off the units actually
locked (which will update the unit status).
Same as above, except needs-to-be-unlocked.
Make the default (initial) jqGrid sort order for balance be DESC.
Change menu to be
'Reports' (or 'Overview', or 'Summary')
'Activities'
- New Receipt
- New Customer
- Move-in
Add dynamic check to see if customer already exists before being
created. Ideally, check +/- a few characters to check for
alternate spellings. Same for contact.
Reduce the number of cached items. Figure out how to get Cake to
automatically make CONCAT(TenderType.name, ' #', Tender.id) part
of each returned query.
Add the opposite of the "collected" report, which provides a set of
checkboxes for the different incomes, and returns a list of where
the received monies were disbursed for the selected period.
MUST reports:
- Delinquent customers
- Locked out units / customers
- To-Lock units
- Paid up until
WANT reports:
- ???
----------------------------------------------------------------------
----------------------------------------------------------------------
----------------------------------------------------------------------
----------------------------------------------------------------------
----------------------------------------------------------------------
-- DONE !
VERIFY THAT OUR NEW BALANCE QUERY WORKS.
(The one that was added to lease). It works for
folks that have ledger entries, but I fear that the
inner join will prevent customers from showing up
in the list if they don't yet have any ledger entries
in account receivable. To resolve this we'll have to
go back to LEFT JOIN and check for NULL in our SUM()
statement.
Fix sorting on Lease list by Lease Number. Have it
reference ID instead.
Figure out why Brenda Harmon's lease #44, unit #B04, lists
the security deposit as $150. She's only paid $25, so it must
be a lease issue.
Modify LedgerEntry to have through_date, since a single
invoice could have charges for several months rent. It's
not clear whether due_date should also be moved to
LedgerEntry, since some charges could have different due
dates. The problem is that I can't picture an invoice
having more than one due date.
Consider adding a from_date to LedgerEntry as well.
Fix Customers index list. To replicate, add a brand
new customer. Select Customers. Notice it says
'Current Customers', but actually includes the new
one in the list.
There seems to be a problem with the account ledger for the
customer. To replicate, see Mancini's account (#47). There
are 4 entries in the Account ledger. One of them is was from
5/1/09. It's a receipt (Transaction #610, Entry #702). The
Transaction is for $111.33 as indicated, but the entry is only
for $16.33.
-- This was a problem with using notxgroup, the experimental
-- field that used to be hardcoded to false in ledger_entries.ctp
-- My rework eliminated that field, and everything was getting
-- grouped by transaction.
Figure out how to utilize the security deposit, whether
as part of move-out only, or as one of the payment options.
Having a grid of ledger entries grouped by transaction appears
to work, from the financial aspect, but the count of entries
is incorrect. The problem is the grouping only occurs after
the count, which it has to in order for the count to work. We
need to obliterate the group_by_tx parameter, and simply use
the transanction controller to generate the grid instead of
ledger_entries.
Handle a credit, ensuring that it's applied to new charges
- either automatically;
- by user opt-in to use credits when invoicing
- by user opt-in when entering a receipt
- by manually allowing a receipt of credits
Reconcile all entries of a ledger to the c/f entry when
"closing" the ledger and creating a new one.
Determine when each unit is paid up until. There is actually
two things here: invoiced up until, and paid up until. One or
both of these should be displayed on the Lease view page.
20090729: New Ledger doesn't seem to give a balance forward entry.
Sorting by Customer ID is broken. It must think it's already
sorted by ID because the first click shows the arrow as
DESC even though the sort is ASC. Subsequent clicks don't
change anything. You must sort on a different column first
then everything works.
- Not actually fixed in the app, although it's solved by
using jqGrid 3.5
Seems like security deposit is suddenly broken. I believe
the customer/lease infobox used to report only PAID
security deposits, but it now seems like it's reporting ALL
security deposits charged.
Customer Selection on the Receipt Page is broken.
(Selecting a row and waiting for the update).
Automatic assessment of rents, or at least for now, one
click manual mechanism to assess rents correctly for all
tenants.
Automatic assessment of late fees, or at least for now, one
click manual mechanism to assess late fees correctly for all
tenants.
Fix ACH deposits into bank. Make it happen automatically,
perhaps after 3 days. Without this, we cannot NSF an ACH
transaction.
Change the menu structure to be $menu['section']['item'], so that
items don't have to be added in order of section. Perhaps even
array(array(name, priority, items => array(name, priority, link)))
Change New Customer form to have contact 'New' radio pre-checked
Add explanatory information on the New Customer page
- Customer name can be omitted and will come from primary tenant.
- Phone numbers, etc can be added later directly to the contact
Unit Size has no controller. Either remove the link from the
units grid, or implement the controller.