Compare commits
119 Commits
statement_
...
surplus_ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90ecbda541 | ||
|
|
4afe0bd77b | ||
|
|
8440a7c833 | ||
|
|
00d509f23d | ||
|
|
080c82fc10 | ||
|
|
1b02be19f0 | ||
|
|
366d59a5e6 | ||
|
|
2634cf824a | ||
|
|
1429fe720b | ||
|
|
754cdb8522 | ||
|
|
a1a68f3209 | ||
|
|
8843d24baa | ||
|
|
892618db36 | ||
|
|
3decfff33b | ||
|
|
945221d565 | ||
|
|
a968d7abe6 | ||
|
|
8b6b8884f7 | ||
|
|
14805190fc | ||
|
|
a1bdecfcaa | ||
|
|
4896834a96 | ||
|
|
a9c3c40053 | ||
|
|
4125d7ba16 | ||
|
|
26d9b1bc38 | ||
|
|
f30e536e47 | ||
|
|
96a030e340 | ||
|
|
460e9a2e64 | ||
|
|
6e63365604 | ||
|
|
4f85dc243e | ||
|
|
30f755cf42 | ||
|
|
170ba466de | ||
|
|
d2d1bb3fc4 | ||
|
|
d024d333d2 | ||
|
|
778bb43895 | ||
|
|
41321481c7 | ||
|
|
fe9f6ce949 | ||
|
|
f81bfdecc2 | ||
|
|
8dd6fc957d | ||
|
|
d92acf12de | ||
|
|
43d1d2ccf5 | ||
|
|
c06399cf86 | ||
|
|
d1187f9bdd | ||
|
|
b7a77757f9 | ||
|
|
5f199d97fe | ||
|
|
fc292e3366 | ||
|
|
94e300a129 | ||
|
|
791b2d8ab1 | ||
|
|
091920d80a | ||
|
|
1511986ed0 | ||
|
|
1e88e1fce2 | ||
|
|
a2014a916e | ||
|
|
bd52030984 | ||
|
|
f23726783e | ||
|
|
1d27b4dcb5 | ||
|
|
e74f8987d9 | ||
|
|
9c55a047a8 | ||
|
|
6f2038f7b0 | ||
|
|
ec22f4b003 | ||
|
|
70629e360b | ||
|
|
fc4e812d67 | ||
|
|
b6ee958c35 | ||
|
|
f82df229f2 | ||
|
|
96c499786c | ||
|
|
52e0181bfb | ||
|
|
b65c5c1dbf | ||
|
|
72af3f3247 | ||
|
|
f0693bdc05 | ||
|
|
15f885ab8a | ||
|
|
b1a7f41934 | ||
|
|
4f11e27a76 | ||
|
|
f8aef6e794 | ||
|
|
e100c9a88f | ||
|
|
1ce71a3936 | ||
|
|
19f8c18ce9 | ||
|
|
eb28852b87 | ||
|
|
98f3dd7688 | ||
|
|
c33a823e50 | ||
|
|
1f97e8db35 | ||
|
|
76df8c924f | ||
|
|
598ce5784b | ||
|
|
cdb7d4b15c | ||
|
|
07a2be05f7 | ||
|
|
fd1a1f43d4 | ||
|
|
2e2147b238 | ||
|
|
a0c00f1a35 | ||
|
|
868e23b982 | ||
|
|
e6b0313523 | ||
|
|
654eb0960e | ||
|
|
2e36d46329 | ||
|
|
1dd0b14861 | ||
|
|
d75cd10f49 | ||
|
|
a69a56c715 | ||
|
|
8f7cf202e5 | ||
|
|
58c4f28956 | ||
|
|
f3eaa40ea5 | ||
|
|
e784931fa8 | ||
|
|
5a7b087ddc | ||
|
|
4d62d7da73 | ||
|
|
cca698d437 | ||
|
|
5247bb8db6 | ||
|
|
cb969ba340 | ||
|
|
094e15ddf9 | ||
|
|
670f0894ea | ||
|
|
9e20473b3b | ||
|
|
11d5deac85 | ||
|
|
67280c89e7 | ||
|
|
1afed6a6e0 | ||
|
|
0ff91bf4d8 | ||
|
|
4d4e96fe1c | ||
|
|
32a98b4b6e | ||
|
|
817b74b085 | ||
|
|
dc1bb56188 | ||
|
|
4707f3314d | ||
|
|
ac2b1530fc | ||
|
|
a5d3ff0b70 | ||
|
|
adc87c0763 | ||
|
|
7d81b9766b | ||
|
|
1aa6273ade | ||
|
|
2c08405d5a | ||
|
|
e2ed6ed1c7 |
129
db/schema.sql
129
db/schema.sql
@@ -471,7 +471,6 @@ CREATE TABLE `pmgr_units` (
|
||||
'DIRTY',
|
||||
'VACANT',
|
||||
'OCCUPIED',
|
||||
'LATE', -- NOT SURE
|
||||
'LOCKED',
|
||||
'LIENED')
|
||||
NOT NULL DEFAULT 'VACANT',
|
||||
@@ -644,6 +643,17 @@ CREATE TABLE `pmgr_customers` (
|
||||
-- contacts_customers table?
|
||||
`primary_contact_id` INT(10) UNSIGNED NOT NULL,
|
||||
|
||||
-- Number of different leases for this customer.
|
||||
-- It's not good to have redundant information,
|
||||
-- but these fields change infrequently, and make
|
||||
-- certain queries much easier, most notably for
|
||||
-- the grid query, in which linking customer to
|
||||
-- lease results in repeated statement entries
|
||||
-- when a customer has more than one lease.
|
||||
`lease_count` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`current_lease_count` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`past_lease_count` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
|
||||
`comment` VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
@@ -714,6 +724,9 @@ CREATE TABLE `pmgr_leases` (
|
||||
`notice_received_date` DATE DEFAULT NULL,
|
||||
`close_date` DATE DEFAULT NULL,
|
||||
|
||||
`charge_through_date` DATE DEFAULT NULL,
|
||||
`paid_through_date` DATE DEFAULT NULL,
|
||||
|
||||
`deposit` FLOAT(12,2) DEFAULT NULL,
|
||||
`rent` FLOAT(12,2) DEFAULT NULL,
|
||||
|
||||
@@ -844,8 +857,8 @@ CREATE TABLE `pmgr_accounts` (
|
||||
-- normal circumstances, when a debit occurs.
|
||||
-- `trackable` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
|
||||
`deposits` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, -- Can be used for deposits?
|
||||
`charges` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, -- Can be used for charges?
|
||||
`payments` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, -- Can be used for payments?
|
||||
`invoices` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, -- Can be used for invoices?
|
||||
`receipts` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, -- Can be used for receipts?
|
||||
`refunds` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, -- Can be used for refunds?
|
||||
|
||||
-- Security Level
|
||||
@@ -861,46 +874,46 @@ CREATE TABLE `pmgr_accounts` (
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
LOCK TABLES `pmgr_accounts` WRITE;
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `level`)
|
||||
VALUES
|
||||
('EQUITY', 'Equity', 1),
|
||||
('LIABILITY', 'Loan', 1);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`)
|
||||
VALUES
|
||||
('ASSET', 'A/R' ),
|
||||
-- REVISIT <AP>: 20090710 : We don't really need NSF, as it
|
||||
-- will always run a zero balance. However, it will help
|
||||
-- us identify how serious the NSF situation is.
|
||||
('LIABILITY', 'A/P' ),
|
||||
('LIABILITY', 'Customer Credit' );
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `receipts`)
|
||||
VALUES
|
||||
('ASSET', 'Cash', 1),
|
||||
('ASSET', 'Check', 1),
|
||||
('ASSET', 'Money Order', 1),
|
||||
('ASSET', 'ACH', 1),
|
||||
('EXPENSE', 'Concession', 1);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`)
|
||||
VALUES
|
||||
('ASSET', 'NSF' ),
|
||||
('LIABILITY', 'A/P' );
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `payments`, `refunds`)
|
||||
('EXPENSE', 'Waiver' ),
|
||||
('EXPENSE', 'Bad Debt' );
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `invoices`)
|
||||
VALUES
|
||||
('ASSET', 'Cash', 1, 1),
|
||||
('ASSET', 'Check', 1, 0),
|
||||
('ASSET', 'Money Order', 1, 0),
|
||||
('ASSET', 'ACH', 1, 0),
|
||||
('ASSET', 'Closing', 0, 0), -- REVISIT <AP>: Temporary
|
||||
('EXPENSE', 'Concession', 1, 0);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `refunds`, `deposits`)
|
||||
VALUES
|
||||
-- REVISIT <AP>: 20090710 : We probably don't really want petty cash depositable.
|
||||
-- This is just for testing our deposit code
|
||||
('ASSET', 'Petty Cash', 1, 1);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `charges`)
|
||||
VALUES
|
||||
('LIABILITY', 'Tax', 1),
|
||||
('LIABILITY', 'Tax', 0),
|
||||
('LIABILITY', 'Security Deposit', 1),
|
||||
('INCOME', 'Rent', 1),
|
||||
('INCOME', 'Late Charge', 1),
|
||||
('INCOME', 'NSF Charge', 1),
|
||||
('INCOME', 'Cleaning', 1),
|
||||
('INCOME', 'Damage', 1);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `deposits`, `refunds`)
|
||||
VALUES
|
||||
('ASSET', 'Bank', 1, 1);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`)
|
||||
VALUES
|
||||
('EXPENSE', 'Bad Debt' ),
|
||||
('EXPENSE', 'Maintenance' );
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `refunds`)
|
||||
VALUES
|
||||
('ASSET', 'Petty Cash', 1);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `level`, `deposits`, `refunds`)
|
||||
VALUES
|
||||
('ASSET', 'Bank', 6, 1, 1);
|
||||
INSERT INTO `pmgr_accounts` (`type`, `name`, `level`)
|
||||
VALUES
|
||||
('ASSET', 'Closing', 6),
|
||||
('LIABILITY', 'Loan', 1),
|
||||
('EQUITY', 'Equity', 1);
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
||||
@@ -949,14 +962,20 @@ DROP TABLE IF EXISTS `pmgr_transactions`;
|
||||
CREATE TABLE `pmgr_transactions` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
`type` ENUM('INVOICE',
|
||||
'RECEIPT',
|
||||
-- REVISIT <AP>: 20090804
|
||||
-- I'm not sure about most of these terms.
|
||||
-- Just as long as they're distinct though... I can rename them later
|
||||
`type` ENUM('INVOICE', -- Sales Invoice
|
||||
'RECEIPT', -- Actual receipt of monies
|
||||
'PURCHASE_INVOICE', -- Committment to pay
|
||||
'CREDIT_NOTE', -- Inverse of Sales Invoice
|
||||
'PAYMENT', -- Actual payment
|
||||
'DEPOSIT',
|
||||
'CLOSE',
|
||||
'WITHDRAWAL',
|
||||
'CLOSE', -- Essentially an internal (not accounting) transaction
|
||||
-- 'CREDIT',
|
||||
-- 'REFUND',
|
||||
-- 'WAIVER',
|
||||
'TRANSFER')
|
||||
'TRANSFER') -- Unsure of TRANSFERs use
|
||||
NOT NULL,
|
||||
|
||||
`stamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
@@ -981,10 +1000,6 @@ CREATE TABLE `pmgr_transactions` (
|
||||
-- (e.g. A/R, Bank, etc)
|
||||
`account_id` INT(10) UNSIGNED DEFAULT NULL,
|
||||
`ledger_id` INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- For convenience. Actually, INVOICE will always set crdr
|
||||
-- to DEBIT, RECEIPT will use CREDIT, and DEPOSIT will use
|
||||
-- DEBIT
|
||||
`crdr` ENUM('DEBIT',
|
||||
'CREDIT')
|
||||
DEFAULT NULL,
|
||||
@@ -1013,9 +1028,6 @@ CREATE TABLE `pmgr_ledger_entries` (
|
||||
-- The account/ledger of the entry
|
||||
`account_id` INT(10) UNSIGNED NOT NULL,
|
||||
`ledger_id` INT(10) UNSIGNED NOT NULL,
|
||||
|
||||
-- For convenience. Actually, CHARGE will always set crdr
|
||||
-- to CREDIT and PAYMENT will use DEBIT.
|
||||
`crdr` ENUM('DEBIT',
|
||||
'CREDIT')
|
||||
NOT NULL,
|
||||
@@ -1061,19 +1073,27 @@ DROP TABLE IF EXISTS `pmgr_statement_entries`;
|
||||
CREATE TABLE `pmgr_statement_entries` (
|
||||
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
||||
`type` ENUM('CHARGE',
|
||||
'PAYMENT',
|
||||
'SURPLUS',
|
||||
-- REVISIT <AP>: 20090804
|
||||
-- I'm not sure about most of these terms.
|
||||
-- Just as long as they're distinct though... I can rename them later
|
||||
`type` ENUM('CHARGE', -- Invoiced Charge to Customer
|
||||
'DISBURSEMENT', -- Disbursement of Receipt Funds
|
||||
'REVERSAL', -- Reversal of a charge
|
||||
'WRITEOFF', -- Write-off bad debt
|
||||
'VOUCHER', -- Agreement to pay
|
||||
'PAYMENT', -- Payment of a Voucher
|
||||
'REFUND', -- Payment due to refund
|
||||
'SURPLUS', -- Surplus Receipt Funds
|
||||
'WAIVER', -- Waived Charge
|
||||
-- REVISIT <AP>: 20090730
|
||||
-- VOID is just to test out a theory
|
||||
-- for handling NSF and charge reversals
|
||||
'WAIVE',
|
||||
-- VOID is used for handling NSF and perhaps charge reversals.
|
||||
-- It's not clear this is the best way to handle these things.
|
||||
'VOID')
|
||||
NOT NULL,
|
||||
|
||||
`transaction_id` INT(10) UNSIGNED NOT NULL,
|
||||
|
||||
-- Effective date is when the charge/payment/transfer actually
|
||||
-- Effective date is when the charge/disbursement/transfer actually
|
||||
-- takes effect (since it may not be at the time of the transaction).
|
||||
-- Through date is used if/when a charge covers a certain time period,
|
||||
-- like rent. A security deposit, for example, would not use the
|
||||
@@ -1098,9 +1118,12 @@ CREATE TABLE `pmgr_statement_entries` (
|
||||
-- in the statement. Keeping it for now...
|
||||
`account_id` INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- Allow the payment to reconcile against the charge
|
||||
-- Allow the disbursement to reconcile against the charge
|
||||
`charge_entry_id` INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
-- The transaction that reversed this charge, if any
|
||||
`reverse_transaction_id` INT(10) UNSIGNED DEFAULT NULL,
|
||||
|
||||
`comment` VARCHAR(255) DEFAULT NULL,
|
||||
|
||||
PRIMARY KEY (`id`)
|
||||
@@ -1137,6 +1160,12 @@ CREATE TABLE `pmgr_tender_types` (
|
||||
`data3_name` VARCHAR(80) DEFAULT NULL,
|
||||
`data4_name` VARCHAR(80) DEFAULT NULL,
|
||||
|
||||
-- The field from pmgr_tenders that is used for helping
|
||||
-- to name the tender. For example, a Check tender type
|
||||
-- might specify data1 as the field, so that tenders
|
||||
-- would be named "Check #0000"
|
||||
`naming_field` VARCHAR(80) DEFAULT 'id',
|
||||
|
||||
-- When we accept legal tender of this form, where does
|
||||
-- it go? Each type of legal tender can specify an
|
||||
-- account, either distinct or non-distinct from others
|
||||
|
||||
85
db/scratch.sql
Normal file
85
db/scratch.sql
Normal file
@@ -0,0 +1,85 @@
|
||||
-- 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;
|
||||
|
||||
|
||||
-- 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')
|
||||
|
||||
@@ -50,19 +50,19 @@ Operations to be functional
|
||||
X - Assess NSF Fees
|
||||
X - Determine Lease Paid-Through status
|
||||
- Report: List of customers overdue
|
||||
- Flag unit as overlocked
|
||||
- Flag unit as evicting
|
||||
- Flag unit as normal status
|
||||
- Flag unit as dirty
|
||||
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
|
||||
? - Record utilization of Security Deposit
|
||||
- Record issuing of a refund
|
||||
X - Record utilization of Security Deposit
|
||||
X - Record issuing of a refund
|
||||
- Record Deposit into Petty Cash
|
||||
- Record Payment from Petty Cash to expenses
|
||||
- Record Petty Cash to refund.
|
||||
? - Write Off Bad Debt
|
||||
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.
|
||||
|
||||
@@ -5,6 +5,7 @@ use Data::Dumper;
|
||||
use File::Copy;
|
||||
|
||||
my $closing_one_transaction = 0;
|
||||
my $work_from_scratch = 0;
|
||||
|
||||
# Internally adjust all numbers coming from the database to
|
||||
# be in inches. Not necessary to go to this detail, but the
|
||||
@@ -543,17 +544,18 @@ foreach my $tender_name ('Cash', 'Check', 'Money Order', 'ACH',
|
||||
) {
|
||||
my ($tillable, $fields) = (0, 0);
|
||||
my ($name1, $name2, $name3, $name4);
|
||||
my ($name_field) = ('id');
|
||||
|
||||
$tillable = 1
|
||||
if ($tender_name =~ /^Cash|Check|Money Order$/);
|
||||
|
||||
($name1) = ('Check Number')
|
||||
($name1, $name_field) = ('Check Number', 'data1')
|
||||
if ($tender_name eq 'Check');
|
||||
|
||||
($name1) = ('Money Order Number')
|
||||
($name1, $name_field) = ('Money Order Number', 'data1')
|
||||
if ($tender_name eq 'Money Order');
|
||||
|
||||
($name1, $name2) = ('Routing Number', 'Account Number')
|
||||
($name1, $name2, $name3, $name_field) = ('Routing Number', 'Account Number', 'Batch Number', 'data3')
|
||||
if ($tender_name eq 'ACH');
|
||||
|
||||
($name1, $name2) = ('Debit Card Number', 'Expiration Date')
|
||||
@@ -570,6 +572,7 @@ foreach my $tender_name ('Cash', 'Check', 'Money Order', 'ACH',
|
||||
'data2_name' => $name2,
|
||||
'data3_name' => $name3,
|
||||
'data4_name' => $name4,
|
||||
'naming_field' => $name_field,
|
||||
});
|
||||
|
||||
$newdb{'lookup'}{'tender_type'}{$tender_name}
|
||||
@@ -961,7 +964,7 @@ foreach $row (@{query($sdbh, $query)}) {
|
||||
'lease_date' => datefmt($row->{'DateIn'}),
|
||||
'movein_date' => datefmt($row->{'DateIn'}),
|
||||
'moveout_date' => datefmt($row->{'DateOut'}),
|
||||
'close_date' => datefmt($row->{'DateClosed'}),
|
||||
#'close_date' => datefmt($row->{'DateClosed'}),
|
||||
'rent' => $row->{'Rent'},
|
||||
#'comment' => "LedgerID: $row->{'LedgerID'}",
|
||||
});
|
||||
@@ -1205,8 +1208,6 @@ foreach $row (@{query($sdbh, $query)}) {
|
||||
= $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'};
|
||||
|
||||
if ($SITELINK_ACCOUNT_TYPE{$row->{'PaymentType'}} eq 'Check') {
|
||||
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'name'}
|
||||
= 'Check #' . $row->{'CheckNum'};
|
||||
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'data1'}
|
||||
= $row->{'CheckNum'};
|
||||
}
|
||||
@@ -1308,18 +1309,13 @@ foreach $row (@{query($sdbh, $query)})
|
||||
# 'effective_date' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'effective_date'},
|
||||
# 'effective_date' => $effective_date;
|
||||
# 'through_date' => $through_date;
|
||||
'lease_id' => ($row->{'entry_type'} eq 'CREDIT'
|
||||
? 0
|
||||
: $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_id'}),
|
||||
'lease_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_id'},
|
||||
'customer_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_id'},
|
||||
'amount' => $reconcile_amount,
|
||||
|
||||
'account_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'debit_account_id'},
|
||||
};
|
||||
|
||||
$row->{'ChargeID'} = undef
|
||||
if $row->{'entry_type'} eq 'CREDIT';
|
||||
|
||||
# Update the receipt & tender customer_id, now that we have payment info
|
||||
$newdb{'tables'}{'transactions'}{'rows'}[
|
||||
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'receipt_id'}
|
||||
@@ -1336,7 +1332,7 @@ foreach $row (@{query($sdbh, $query)})
|
||||
# Add the Payment Statement Entry
|
||||
addRow('statement_entries', {
|
||||
'transaction_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'receipt_id'},
|
||||
'type' => $row->{'entry_type'} || 'PAYMENT',
|
||||
'type' => 'DISBURSEMENT',
|
||||
# 'effective_date' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'effective_date'},
|
||||
# 'through_date' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'through_date'},
|
||||
'effective_date' => $effective_date,
|
||||
@@ -1471,6 +1467,30 @@ addRow('double_entries', {
|
||||
});
|
||||
|
||||
|
||||
######################################################################
|
||||
## Debug ... work from scratch
|
||||
if ($work_from_scratch) {
|
||||
# delete $newdb{'tables'}{'contacts'}{'rows'};
|
||||
# delete $newdb{'tables'}{'contacts_methods'}{'rows'};
|
||||
# delete $newdb{'tables'}{'contacts_addresses'}{'rows'};
|
||||
# delete $newdb{'tables'}{'contacts_emails'}{'rows'};
|
||||
# delete $newdb{'tables'}{'contacts_phones'}{'rows'};
|
||||
delete $newdb{'tables'}{'contacts_customers'}{'rows'};
|
||||
delete $newdb{'tables'}{'customers'}{'rows'};
|
||||
delete $newdb{'tables'}{'double_entries'}{'rows'};
|
||||
delete $newdb{'tables'}{'leases'}{'rows'};
|
||||
delete $newdb{'tables'}{'ledger_entries'}{'rows'};
|
||||
delete $newdb{'tables'}{'statement_entries'}{'rows'};
|
||||
delete $newdb{'tables'}{'tenders'}{'rows'};
|
||||
delete $newdb{'tables'}{'transactions'}{'rows'};
|
||||
|
||||
foreach (@{$newdb{'tables'}{'units'}{'rows'}}) {
|
||||
$_->{'status'} = 'VACANT'
|
||||
if defined $_ && ($_->{'status'} =~ /^(OCCUPIED)$/ || $_->{'name'} =~ /^Y/);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
######################################################################
|
||||
## Build the Database
|
||||
|
||||
@@ -1530,6 +1550,21 @@ $query = "UPDATE pmgr_units U, pmgr_leases L
|
||||
WHERE L.unit_id = U.id AND L.close_date IS NULL";
|
||||
query($db_handle, $query);
|
||||
|
||||
# All current_lease_counts will be zero at the moment, since
|
||||
# everything was just created. This will update any customers
|
||||
# that have ever leased anything.
|
||||
$query = "UPDATE pmgr_customers C,
|
||||
(SELECT L.customer_id,
|
||||
SUM(IF(L.close_date IS NULL, 1, 0)) AS current,
|
||||
SUM(IF(L.close_date IS NULL, 0, 1)) AS closed
|
||||
FROM pmgr_leases L
|
||||
GROUP BY L.customer_id) AS X
|
||||
SET C.`lease_count` = X.current + X.closed,
|
||||
C.`current_lease_count` = X.current,
|
||||
C.`past_lease_count` = X.closed
|
||||
WHERE X.customer_id = C.id";
|
||||
query($db_handle, $query);
|
||||
|
||||
|
||||
######################################################################
|
||||
## Invoice/Receipt totals
|
||||
@@ -1541,3 +1576,26 @@ $query = "UPDATE pmgr_transactions T, pmgr_ledger_entries E
|
||||
WHERE E.transaction_id = T.id AND E.account_id = T.account_id";
|
||||
query($db_handle, $query);
|
||||
|
||||
|
||||
######################################################################
|
||||
## Tender Names
|
||||
|
||||
print("Set Tender Names...\n");
|
||||
|
||||
$query = "UPDATE pmgr_tenders T, pmgr_tender_types TT
|
||||
SET T.`name` = CONCAT(T.`name`, ' #',
|
||||
IF(T.tender_type_id IN (2,3), T.data1, T.id))
|
||||
WHERE T.tender_type_id IS NULL OR TT.id = T.tender_type_id";
|
||||
query($db_handle, $query);
|
||||
|
||||
|
||||
######################################################################
|
||||
## Invoice date fixes
|
||||
|
||||
# print("Fix Invoice Dates...\n");
|
||||
|
||||
# $query = "UPDATE pmgr_transactions T, pmgr_statement_entries E
|
||||
# SET T.`stamp` =
|
||||
# WHERE E.transaction_id = T.id AND E.account_id = T.account_id";
|
||||
# query($db_handle, $query);
|
||||
|
||||
|
||||
@@ -38,26 +38,95 @@ class AppController extends Controller {
|
||||
var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid');
|
||||
var $components = array('DebugKit.Toolbar');
|
||||
|
||||
function __construct() {
|
||||
$this->params['dev'] = false;
|
||||
$this->params['admin'] = false;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
function sideMenuLinks() {
|
||||
return array(
|
||||
array('name' => 'Common', 'header' => true),
|
||||
array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)),
|
||||
array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')),
|
||||
array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index')),
|
||||
array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')),
|
||||
array('name' => 'Accounts', 'url' => array('controller' => 'accounts', 'action' => 'index')),
|
||||
array('name' => 'Debug', 'header' => true),
|
||||
array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index')),
|
||||
array('name' => 'Ledgers', 'url' => array('controller' => 'ledgers', 'action' => 'index')),
|
||||
array('name' => 'New Ledgers', 'url' => array('controller' => 'accounts', 'action' => 'newledger')),
|
||||
array('name' => 'RESET DATA', 'url' => array('controller' => 'accounts', 'action' => 'reset_data')),
|
||||
);
|
||||
// Stupid Cake... our constructor sets admin/dev,
|
||||
// but cake stomps it somewhere along the way
|
||||
// after constructing the CakeError controller.
|
||||
if ($this->name === 'CakeError') {
|
||||
$this->params['dev'] = false;
|
||||
$this->params['admin'] = false;
|
||||
}
|
||||
|
||||
$menu = array();
|
||||
$menu[] = array('name' => 'Common', 'header' => true);
|
||||
$menu[] = array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1));
|
||||
$menu[] = array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Deposits', 'url' => array('controller' => 'transactions', 'action' => 'deposit'));
|
||||
|
||||
if ($this->params['admin']) {
|
||||
$menu[] = array('name' => 'Admin', 'header' => true);
|
||||
$menu[] = array('name' => 'Accounts', 'url' => array('controller' => 'accounts', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Ledgers', 'url' => array('controller' => 'ledgers', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Tenders', 'url' => array('controller' => 'tenders', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Transactions', 'url' => array('controller' => 'transactions', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Ldgr Entries', 'url' => array('controller' => 'ledger_entries', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'Stmt Entries', 'url' => array('controller' => 'statement_entries', 'action' => 'index'));
|
||||
$menu[] = array('name' => 'New Ledgers', 'url' => array('controller' => 'accounts', 'action' => 'newledger'));
|
||||
$menu[] = array('name' => 'Assess Charges', 'url' => array('controller' => 'leases', 'action' => 'assess_all'));
|
||||
}
|
||||
|
||||
if ($this->params['dev']) {
|
||||
$menu[] = array('name' => 'Development', 'header' => true);
|
||||
$menu[] = array('name' => 'Un-Nuke', 'url' => '#', 'htmlAttributes' =>
|
||||
array('onclick' => '$(".pr-section").show(); return false;'));
|
||||
$menu[] = array('name' => 'New Ledgers', 'url' => array('controller' => 'accounts', 'action' => 'newledger'));
|
||||
//array('name' => 'RESET DATA', 'url' => array('controller' => 'accounts', 'action' => 'reset_data'));
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
function beforeFilter() {
|
||||
$this->params['dev'] =
|
||||
(!empty($this->params['dev_route']));
|
||||
$this->params['admin'] =
|
||||
(!empty($this->params['admin_route']) || !empty($this->params['dev_route']));
|
||||
|
||||
if (!$this->params['dev'])
|
||||
Configure::write('debug', '0');
|
||||
}
|
||||
|
||||
function beforeRender() {
|
||||
$this->set('sidemenu', $this->sideMenuLinks());
|
||||
}
|
||||
|
||||
function redirect($url, $status = null, $exit = true) {
|
||||
// OK, since the controller will not be able to
|
||||
// utilize our overriden url function in AppHelper,
|
||||
// we'll have to do it manually here.
|
||||
App::import('Helper', 'Html');
|
||||
$url = HtmlHelper::url($url, true);
|
||||
|
||||
if (headers_sent()) {
|
||||
// If we've already sent the headers, it's because
|
||||
// we're debugging, and our debug output has gotten
|
||||
// out before the redirect. That's probably a good
|
||||
// thing, as we don't typically want pages to be
|
||||
// jerked out from under us while trying to read
|
||||
// the debug output. So, since we can't redirect
|
||||
// anyway, we may as well go with the flow and just
|
||||
// render this page instead, using an empty template
|
||||
$this->set('message',
|
||||
("Intended redirect:<P><BR>" .
|
||||
'<A HREF="'.$url.'">'.$url.'</A>'));
|
||||
|
||||
echo $this->render('/empty');
|
||||
if ($exit)
|
||||
$this->_stop();
|
||||
}
|
||||
|
||||
return parent::redirect($url, $status, $exit);
|
||||
}
|
||||
|
||||
function reset_data() {
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
@@ -159,16 +228,10 @@ class AppController extends Controller {
|
||||
}
|
||||
|
||||
function gridDataSetup(&$params) {
|
||||
// Assume we're debugging.
|
||||
// The actual grid request will set this to false
|
||||
$debug = true;
|
||||
// Debug only if requested
|
||||
$params['debug'] = !empty($this->passedArgs['debug']);
|
||||
|
||||
if (isset($this->passedArgs['debug']))
|
||||
$debug = $this->passedArgs['debug'];
|
||||
|
||||
$params['debug'] = $debug;
|
||||
|
||||
if ($debug) {
|
||||
if ($params['debug']) {
|
||||
ob_start();
|
||||
}
|
||||
else {
|
||||
@@ -187,17 +250,26 @@ class AppController extends Controller {
|
||||
// This SHOULD always be set, except when debugging
|
||||
if (isset($params['post']))
|
||||
$params['post'] = unserialize($params['post']);
|
||||
else
|
||||
$params['post'] = array();
|
||||
|
||||
// Unserialize our complex structure of dynamic post data
|
||||
if (isset($params['dynamic_post']))
|
||||
$params['dynamic_post'] = unserialize($params['dynamic_post']);
|
||||
else
|
||||
$params['dynamic_post'] = null;
|
||||
|
||||
// Unserialize our complex structure of dynamic post data
|
||||
if (isset($params['dynamic_post_replace']))
|
||||
$params['dynamic_post_replace'] = unserialize($params['dynamic_post_replace']);
|
||||
else
|
||||
$params['dynamic_post_replace'] = null;
|
||||
|
||||
// Merge the static and dynamic post data
|
||||
if (empty($params['post']) && !empty($params['dynamic_post']))
|
||||
$params['post'] = $params['dynamic_post'];
|
||||
elseif (!empty($params['post']) && !empty($params['dynamic_post']))
|
||||
//$params['post'] = array_merge($params['post'], $params['dynamic_post']);
|
||||
if (!empty($params['dynamic_post']))
|
||||
$params['post'] = array_merge_recursive($params['post'], $params['dynamic_post']);
|
||||
if (!empty($params['dynamic_post_replace']))
|
||||
$params['post'] = array_merge($params['post'], $params['dynamic_post_replace']);
|
||||
|
||||
// This SHOULD always be set, except when debugging
|
||||
if (!isset($params['post']['fields']))
|
||||
@@ -641,7 +713,7 @@ class AppController extends Controller {
|
||||
foreach ($records AS &$record) {
|
||||
// Add the calculated fields (if any), to the model fields
|
||||
if (isset($record[0])) {
|
||||
$record[$model_alias] += $record[0];
|
||||
$record[$model_alias] = $record[0] + $record[$model_alias];
|
||||
unset($record[0]);
|
||||
}
|
||||
}
|
||||
@@ -680,12 +752,15 @@ class AppController extends Controller {
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
// Don't create any links if ordered not to.
|
||||
if (isset($params['nolinks']))
|
||||
if (isset($params['post']['nolinks']))
|
||||
return;
|
||||
|
||||
App::import('Helper', 'Html');
|
||||
|
||||
foreach ($links AS $table => $fields) {
|
||||
$special = array('controller', 'id');
|
||||
$special = array('controller', 'action', 'id');
|
||||
$controller = Inflector::pluralize(Inflector::underscore($table));
|
||||
$action = 'view';
|
||||
$id = 'id';
|
||||
extract(array_intersect_key($fields, array_flip($special)));
|
||||
foreach ($records AS &$record) {
|
||||
@@ -700,9 +775,9 @@ class AppController extends Controller {
|
||||
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
|
||||
$record[$table][$field] =
|
||||
'<A HREF="' .
|
||||
Router::url(array('controller' => $controller,
|
||||
'action' => 'view',
|
||||
$record[$table][$id])) .
|
||||
HtmlHelper::url(array('controller' => $controller,
|
||||
'action' => $action,
|
||||
$record[$table][$id])) .
|
||||
'">' .
|
||||
$record[$table][$field] .
|
||||
'</A>';
|
||||
@@ -792,5 +867,15 @@ class AppController extends Controller {
|
||||
echo " <cell><![CDATA[$data]]></cell>\n";
|
||||
}
|
||||
|
||||
function INTERNAL_ERROR($msg, $depth = 0) {
|
||||
INTERNAL_ERROR($msg, false, $depth+1);
|
||||
$this->render_empty();
|
||||
$this->_stop();
|
||||
}
|
||||
|
||||
function render_empty() {
|
||||
$this->render('/empty');
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -37,5 +37,14 @@ App::import('Core', 'Helper');
|
||||
* @subpackage cake.cake
|
||||
*/
|
||||
class AppHelper extends Helper {
|
||||
|
||||
function url($url = null, $full = false) {
|
||||
foreach(array('admin_route', 'dev_route') AS $mod) {
|
||||
if (isset($this->params[$mod]) && is_array($url) && !isset($url[$mod]))
|
||||
$url[$mod] = $this->params[$mod];
|
||||
}
|
||||
return parent::url($url, $full);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -114,20 +114,48 @@ class AppModel extends Model {
|
||||
$line = $caller['line'];
|
||||
|
||||
// So, this caller holds the calling function name
|
||||
$caller = array_shift($trace);
|
||||
$caller = $trace[0];
|
||||
$function = $caller['function'];
|
||||
$class = $caller['class'];
|
||||
//$class = $this->name;
|
||||
|
||||
// Adjust the log level from default, if necessary
|
||||
// Use class or function specific log level if available
|
||||
if (isset($this->class_log_level[$class]))
|
||||
$log_level = $this->class_log_level[$class];
|
||||
if (isset($this->function_log_level["{$class}-{$function}"]))
|
||||
$log_level = $this->function_log_level["{$class}-{$function}"];
|
||||
if (isset($this->min_log_level))
|
||||
$log_level = max($log_level, $this->min_log_level);
|
||||
if (isset($this->max_log_level))
|
||||
$log_level = min($log_level, $this->max_log_level);
|
||||
|
||||
// Establish log level minimums
|
||||
$min_log_level = $this->min_log_level;
|
||||
if (is_array($this->min_log_level)) {
|
||||
$min_show_level = $min_log_level['show'];
|
||||
$min_log_level = $min_log_level['log'];
|
||||
}
|
||||
|
||||
// Establish log level maximums
|
||||
$max_log_level = $this->max_log_level;
|
||||
if (is_array($this->max_log_level)) {
|
||||
$max_show_level = $max_log_level['show'];
|
||||
$max_log_level = $max_log_level['log'];
|
||||
}
|
||||
|
||||
// Determine the applicable log and show levels
|
||||
if (is_array($log_level)) {
|
||||
$show_level = $log_level['show'];
|
||||
$log_level = $log_level['log'];
|
||||
}
|
||||
|
||||
// Adjust log level up/down to min/max
|
||||
if (isset($min_log_level))
|
||||
$log_level = max($log_level, $min_log_level);
|
||||
if (isset($max_log_level))
|
||||
$log_level = min($log_level, $max_log_level);
|
||||
|
||||
// Adjust show level up/down to min/max
|
||||
if (isset($min_show_level))
|
||||
$show_level = max($show_level, $min_show_level);
|
||||
if (isset($max_show_level))
|
||||
$show_level = min($show_level, $max_show_level);
|
||||
|
||||
// If the level is insufficient, bail out
|
||||
if ($level > $log_level)
|
||||
@@ -141,13 +169,87 @@ class AppModel extends Model {
|
||||
$mixed = $chk + array($mixed);
|
||||
}
|
||||
|
||||
echo '<DIV CLASS="pr-caller">';
|
||||
echo '<strong>' . substr(str_replace(ROOT, '', $file), 1) . '</strong>';
|
||||
echo ' (line <strong>' . $line . '</strong>)';
|
||||
echo ' : level-' . $level;
|
||||
echo '</DIV>' . "\n";
|
||||
static $pr_unique_number = 0;
|
||||
$pr_id = 'pr-section-class-' . $class . '-print-' . (++$pr_unique_number);
|
||||
$pr_trace_id = $pr_id . '-trace';
|
||||
$pr_output_id = $pr_id . '-output';
|
||||
|
||||
pr(array("{$class}::{$function}()" => $mixed), false, false);
|
||||
$pr_entire_base_class = "pr-section";
|
||||
$pr_entire_class_class = $pr_entire_base_class . '-class-' . $class;
|
||||
$pr_entire_function_class = $pr_entire_class_class . '-function-' . $function;
|
||||
$pr_entire_class = "$pr_entire_base_class $pr_entire_class_class $pr_entire_function_class";
|
||||
$pr_header_class = "pr-caller";
|
||||
$pr_trace_class = "pr-trace";
|
||||
$pr_output_base_class = 'pr-output';
|
||||
$pr_output_class_class = $pr_output_base_class . '-class-' . $class;
|
||||
$pr_output_function_class = $pr_output_class_class . '-function-' . $function;
|
||||
$pr_output_class = "$pr_output_base_class $pr_output_class_class $pr_output_function_class";
|
||||
|
||||
echo '<DIV class="'.$pr_entire_class.'" id="'.$pr_id.'">'."\n";
|
||||
echo '<DIV class="'.$pr_header_class.'">'."\n";
|
||||
echo '<DIV class="'.$pr_trace_class.'" id="'.$pr_trace_id.'" style="display:none;">'."\n";
|
||||
echo '<HR />' . "\n";
|
||||
|
||||
// Flip trace around so the sequence flows from top to bottom
|
||||
// Then print out the entire stack trace (in hidden div)
|
||||
$trace = array_reverse($trace);
|
||||
for ($i = 0; $i < count($trace); ++$i) {
|
||||
$bline = $trace[$i]['line'];
|
||||
$bfile = $trace[$i]['file'];
|
||||
$bfile = str_replace(ROOT.DS, '', $bfile);
|
||||
$bfile = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $bfile);
|
||||
|
||||
if ($i > 0) {
|
||||
$bfunc = $trace[$i-1]['function'];
|
||||
$bclas = $trace[$i-1]['class'];
|
||||
} else {
|
||||
$bfunc = null;
|
||||
$bclas = null;
|
||||
}
|
||||
|
||||
echo("$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")<BR>\n");
|
||||
//echo(($bclas ? "$bclas::$bfunc" : "entry point") . "; $bfile : $bline<BR>\n");
|
||||
}
|
||||
echo '</DIV>' . "\n"; // End pr_trace_class
|
||||
$file = str_replace(ROOT.DS, '', $file);
|
||||
$file = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $file);
|
||||
|
||||
echo "<strong>$file:$line ($class::$function)</strong>" . ";\n";
|
||||
/* $log_show_level = isset($show_level) ? $show_level : '?'; */
|
||||
/* echo ' L' . $level . "({$log_level}/{$log_show_level})" . ";\n"; */
|
||||
echo ' L' . $level . ";\n";
|
||||
echo ' <A HREF="#" onclick="$' . "('#{$pr_trace_id}').slideToggle(); return false;" . '">stack</A>'.";\n";
|
||||
|
||||
echo " this ";
|
||||
echo '<A HREF="#" onclick="$' . "('#{$pr_output_id}').slideToggle(); return false;" . '">t</A>'."/";
|
||||
echo '<A HREF="#" onclick="$' . "('#{$pr_id}').hide(); return false;" . '">n</A>'.";\n";
|
||||
|
||||
echo " $class ";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_class_class}').slideDown(); return false;" . '">s</A>'."/";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_class_class}').slideUp(); return false;" . '">h</A>'."/";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_class_class}').hide(); return false;" . '">n</A>'.";\n";
|
||||
|
||||
echo " $function ";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_function_class}').slideDown(); return false;" . '">s</A>'."/";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_function_class}').slideUp(); return false;" . '">h</A>'."/";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_function_class}').hide(); return false;" . '">n</A>'.";\n";
|
||||
|
||||
echo " all ";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_base_class}').show(); return false;" . '">s</A>'."/";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_base_class}').hide(); return false;" . '">h</A>'."/";
|
||||
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_base_class}').hide(); return false;" . '">n</A>'."\n";
|
||||
|
||||
echo '</DIV>' . "\n"; // End pr_header_class
|
||||
|
||||
if (isset($show_level) && $level > $show_level)
|
||||
$display = 'none';
|
||||
else
|
||||
$display = 'block';
|
||||
|
||||
echo '<DIV class="'.$pr_output_class.'" id="'.$pr_output_id.'" style="display:'.$display.';">'."\n";
|
||||
pr($mixed, false, false);
|
||||
echo '</DIV>' . "\n"; // End pr_output_class
|
||||
echo '</DIV>' . "\n"; // End pr_entire_class
|
||||
}
|
||||
|
||||
function pr($level, $mixed, $checkpoint = null) {
|
||||
@@ -300,6 +402,10 @@ class AppModel extends Model {
|
||||
}
|
||||
|
||||
|
||||
function filter_null($array) {
|
||||
return array_diff_key($array, array_filter($array, 'is_null'));
|
||||
}
|
||||
|
||||
function recursive_array_replace($find, $replace, &$data) {
|
||||
if (!isset($data))
|
||||
return;
|
||||
@@ -374,4 +480,12 @@ class AppModel extends Model {
|
||||
return date('Y-m-d', strtotime($dateString));
|
||||
}
|
||||
|
||||
function INTERNAL_ERROR($msg, $depth = 0) {
|
||||
INTERNAL_ERROR($msg, false, $depth+1);
|
||||
echo $this->requestAction(array('controller' => 'accounts',
|
||||
'action' => 'render_empty'),
|
||||
array('return', 'bare' => false)
|
||||
);
|
||||
$this->_stop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,46 @@
|
||||
* You can also use this to include or require any files in your application.
|
||||
*
|
||||
*/
|
||||
|
||||
function INTERNAL_ERROR($message, $exit = true, $drop = 0) {
|
||||
echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">' . "\n";
|
||||
echo '<H1 style="color:#000; margin-bottom:0.2em; font-size:2em;">INTERNAL ERROR:</H1>' . "\n";
|
||||
echo '<H2 style="color:#000; margin-top:0; margin-left:1.5em; font-size:1.5em">' . $message . '</H2>' . "\n";
|
||||
echo '<H4 style="color:#000;">This error was not caused by anything that you did wrong.' . "\n";
|
||||
echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>' . "\n";
|
||||
|
||||
// Print out the entire stack trace
|
||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nStack Trace:\n";
|
||||
echo '<OL style="margin-left:1.5em";>' . "\n";
|
||||
$trace = array_slice(debug_backtrace(false), $drop);
|
||||
for ($i = 0; $i < count($trace); ++$i) {
|
||||
$bline = $trace[$i]['line'];
|
||||
$bfile = $trace[$i]['file'];
|
||||
$bfile = str_replace(ROOT.DS, '', $bfile);
|
||||
$bfile = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $bfile);
|
||||
|
||||
if ($i < count($trace)-1) {
|
||||
$bfunc = $trace[$i+1]['function'];
|
||||
$bclas = $trace[$i+1]['class'];
|
||||
} else {
|
||||
$bfunc = null;
|
||||
$bclas = null;
|
||||
}
|
||||
|
||||
echo("<LI>$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")</LI>\n");
|
||||
}
|
||||
echo "</OL>\n";
|
||||
|
||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nHTTP Request:\n";
|
||||
echo '<P><PRE style="color:#000; background:#c22;">' . "\n";
|
||||
print_r($_REQUEST);
|
||||
echo "\n</PRE>\n";
|
||||
|
||||
echo '</DIV>';
|
||||
if ($exit)
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings below can be used to set additional paths to models, views and controllers.
|
||||
* This is related to Ticket #470 (https://trac.cakephp.org/ticket/470)
|
||||
|
||||
@@ -32,6 +32,20 @@
|
||||
* It's hardcoded to map #1, but at some point we'll implement
|
||||
* a login mechanism and the default path will be to log on instead.
|
||||
*/
|
||||
Router::connect('/', array('controller' => 'maps', 'action' => 'view', '1'));
|
||||
Router::connect('/', array('controller' => 'maps', 'action' => 'view', '1'));
|
||||
|
||||
/*
|
||||
* Route for admin functionality
|
||||
*/
|
||||
Router::connect('/admin/:controller/:action/*',
|
||||
array('action' => null, 'admin_route' => true)
|
||||
);
|
||||
|
||||
/*
|
||||
* Route for development functionality
|
||||
*/
|
||||
Router::connect('/dev/:controller/:action/*',
|
||||
array('action' => null, 'dev_route' => true)
|
||||
);
|
||||
|
||||
?>
|
||||
@@ -12,9 +12,6 @@ class AccountsController extends AppController {
|
||||
array('name' => 'Equity', 'url' => array('controller' => 'accounts', 'action' => 'equity')),
|
||||
array('name' => 'Income', 'url' => array('controller' => 'accounts', 'action' => 'income')),
|
||||
array('name' => 'Expense', 'url' => array('controller' => 'accounts', 'action' => 'expense')),
|
||||
array('name' => 'Deposits', 'header' => true),
|
||||
array('name' => 'Prior Deposits', 'url' => array('controller' => 'transactions', 'action' => 'deposit')),
|
||||
array('name' => 'New Deposit', 'url' => array('controller' => 'tenders', 'action' => 'deposit')),
|
||||
);
|
||||
|
||||
|
||||
@@ -93,6 +90,10 @@ class AccountsController extends AppController {
|
||||
$conditions[] = array('Account.type' => strtoupper($params['action']));
|
||||
}
|
||||
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
$conditions[] = array('Account.level >=' => 10);
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
@@ -138,17 +139,15 @@ class AccountsController extends AppController {
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$payment_accounts = $this->Account->collectableAccounts();
|
||||
//$payment_accounts[$this->Account->nameToID('Closing')] = 'Closing';
|
||||
//$payment_accounts[$this->Account->nameToID('Equity')] = 'Equity';
|
||||
$default_accounts = array_diff_key($this->Account->paymentAccounts(),
|
||||
array($this->Account->concessionAccountID() => 1));
|
||||
$this->set(compact('payment_accounts', 'default_accounts'));
|
||||
|
||||
$this->Account->recursive = -1;
|
||||
$account = $this->Account->read(null, $id);
|
||||
$account = $account['Account'];
|
||||
|
||||
$accounts = $this->Account->collectableAccounts();
|
||||
$payment_accounts = $accounts['all'];
|
||||
$default_accounts = $accounts['default'];
|
||||
$this->set(compact('payment_accounts', 'default_accounts'));
|
||||
|
||||
$title = ($account['name'] . ': Collected Report');
|
||||
$this->set(compact('account', 'title'));
|
||||
}
|
||||
@@ -162,12 +161,6 @@ class AccountsController extends AppController {
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Get details about the account and its ledgers (no ledger entries yet)
|
||||
$account = $this->Account->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
@@ -179,14 +172,18 @@ class AccountsController extends AppController {
|
||||
array('CloseTransaction' => array
|
||||
('order' => array('CloseTransaction.stamp' => 'DESC'))),
|
||||
),
|
||||
'conditions' => array(array('Account.id' => $id)),
|
||||
'conditions' => array(array('Account.id' => $id),
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
array('Account.level >=' => 10),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Get all ledger entries of the CURRENT ledger
|
||||
$entries = $this->Account->ledgerEntries($id);
|
||||
//pr(compact('entries'));
|
||||
$account['CurrentLedger']['LedgerEntry'] = $entries;
|
||||
if (empty($account)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Obtain stats across ALL ledgers for the summary infobox
|
||||
$stats = $this->Account->stats($id, true);
|
||||
@@ -204,8 +201,4 @@ class AccountsController extends AppController {
|
||||
$this->set(compact('account', 'title', 'stats'));
|
||||
}
|
||||
|
||||
function tst($id) {
|
||||
//$entries = $this->Account->($id);
|
||||
pr($entries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +126,6 @@ class ContactsController extends AppController {
|
||||
|
||||
// Now that the work is done, let the user view the updated contact
|
||||
$this->redirect(array('action'=>'view', $this->data['Contact']['id']));
|
||||
//$this->render('/empty');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
|
||||
@@ -50,7 +50,6 @@ class CustomersController extends AppController {
|
||||
('link' =>
|
||||
array(// Models
|
||||
'PrimaryContact',
|
||||
'CurrentLease' => array('fields' => array()),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -64,19 +63,19 @@ class CustomersController extends AppController {
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
$fields[] = ('COUNT(DISTINCT CurrentLease.id) AS lease_count');
|
||||
return array_merge($fields,
|
||||
$this->Customer->StatementEntry->chargePaymentFields(true));
|
||||
$this->Customer->StatementEntry->chargeDisbursementFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
if ($params['action'] === 'current') {
|
||||
$conditions[] = 'CurrentLease.id IS NOT NULL';
|
||||
$conditions[] = array('Customer.current_lease_count >' => 0);
|
||||
}
|
||||
elseif ($params['action'] === 'past') {
|
||||
$conditions[] = 'CurrentLease.id IS NULL';
|
||||
$conditions[] = array('Customer.current_lease_count' => 0);
|
||||
$conditions[] = array('Customer.past_lease_count >' => 0);
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
@@ -99,30 +98,6 @@ class CustomersController extends AppController {
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataCount(&$params, &$model) {
|
||||
|
||||
if ($params['action'] != 'current')
|
||||
return parent::gridDataCount($params, $model);
|
||||
|
||||
// OK, for current customers, we have an issue.
|
||||
// We don't have a good way to use the query to obtain
|
||||
// our count. The problem is that we're relying on the
|
||||
// group by for the query, but that simply won't work
|
||||
// for the count. However, it's not difficult to simply
|
||||
// derive it since 'current' customers are mutually
|
||||
// exclusive to 'past' customers.
|
||||
|
||||
$tmp_params = $params;
|
||||
$tmp_params['action'] = 'all';
|
||||
$all_count = parent::gridDataCount($tmp_params, $model);
|
||||
$tmp_params['action'] = 'past';
|
||||
$past_count = parent::gridDataCount($tmp_params, $model);
|
||||
|
||||
// The current customer count is simply calculated
|
||||
// as all customers that are not past customers.
|
||||
return $all_count - $past_count;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Customer'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
@@ -203,17 +178,44 @@ class CustomersController extends AppController {
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
/* //$result = $this->Customer->securityDeposits($id); */
|
||||
/* $result = $this->Customer->excessPayments($id); */
|
||||
/* //$result = $this->Customer->unreconciledCharges($id); */
|
||||
/* echo('<HR>'); */
|
||||
/* pr($result); */
|
||||
/* $this->autoRender = false; */
|
||||
/* return; */
|
||||
// Get details on this customer, its contacts and leases
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Contact' =>
|
||||
array('order' => array('Contact.display_name'),
|
||||
// Models
|
||||
'ContactPhone',
|
||||
'ContactEmail',
|
||||
'ContactAddress',
|
||||
),
|
||||
'Lease' =>
|
||||
array('Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
$customer = $this->Customer->details($id);
|
||||
'conditions' => array('Customer.id' => $id),
|
||||
));
|
||||
//pr($customer);
|
||||
$outstanding_balance = $customer['stats']['balance'];
|
||||
|
||||
// Determine how long this customer has been with us.
|
||||
$leaseinfo = $this->Customer->find
|
||||
('first', array
|
||||
('link' => array('Lease' => array('fields' => array())),
|
||||
'fields' => array('MIN(Lease.movein_date) AS since',
|
||||
'IF(Customer.current_lease_count = 0, MAX(Lease.moveout_date), NULL) AS until'),
|
||||
'conditions' => array('Customer.id' => $id),
|
||||
'group' => 'Customer.id',
|
||||
));
|
||||
$this->set($leaseinfo[0]);
|
||||
|
||||
// Figure out the outstanding balances for this customer
|
||||
//$this->set('stats', $this->Customer->stats($id));
|
||||
$outstanding_balance = $this->Customer->balance($id);
|
||||
$outstanding_deposit = $this->Customer->securityDepositBalance($id);
|
||||
|
||||
// Figure out if this customer has any non-closed leases
|
||||
@@ -247,12 +249,22 @@ class CustomersController extends AppController {
|
||||
/* $id)); */
|
||||
/* } */
|
||||
|
||||
if ($show_payment) {
|
||||
if ($show_payment || $outstanding_balance > 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Payment',
|
||||
array('name' => 'New Receipt',
|
||||
'url' => array('action' => 'receipt',
|
||||
$id));
|
||||
}
|
||||
|
||||
if (!$show_moveout && $outstanding_balance > 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Write-Off',
|
||||
'url' => array('action' => 'bad_debt',
|
||||
$id));
|
||||
|
||||
if ($outstanding_balance < 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Issue Refund',
|
||||
'url' => array('action' => 'refund', $id));
|
||||
|
||||
// Prepare to render.
|
||||
$title = 'Customer: ' . $customer['Customer']['name'];
|
||||
@@ -275,23 +287,20 @@ class CustomersController extends AppController {
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (isset($this->data['Customer']['id']))
|
||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||
else
|
||||
$this->redirect(array('action'=>'index'));
|
||||
return;
|
||||
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Make sure we have at least one contact
|
||||
if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) {
|
||||
$this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true);
|
||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure there is a primary contact
|
||||
if (!isset($this->data['Customer']['primary_contact_entry'])) {
|
||||
$this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true);
|
||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||
return;
|
||||
}
|
||||
|
||||
// Go through each customer and strip the bogus ID if new
|
||||
@@ -308,17 +317,12 @@ class CustomersController extends AppController {
|
||||
pr("CUSTOMER SAVE FAILED");
|
||||
}
|
||||
|
||||
// If existing customer, then view it. Otherwise, since
|
||||
// this is a new customer, go to the move in screen.
|
||||
// If existing customer, then view it.
|
||||
if ($this->data['Customer']['id'])
|
||||
$this->redirect(array('action'=>'view', $this->Customer->id));
|
||||
else
|
||||
$this->redirect(array('action'=>'move_in', $this->Customer->id));
|
||||
|
||||
// For debugging, only if the redirects above have been
|
||||
// commented out, otherwise this section isn't reached.
|
||||
$this->render('/empty');
|
||||
return;
|
||||
// Since this is a new customer, go to the move in screen.
|
||||
$this->redirect(array('action'=>'move_in', $this->Customer->id));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
@@ -367,20 +371,9 @@ class CustomersController extends AppController {
|
||||
$this->Customer->recursive = -1;
|
||||
$customer = $this->Customer->read(null, $id);
|
||||
$customer = $customer['Customer'];
|
||||
$unreconciled = $this->Customer->unreconciledCharges($id);
|
||||
//pr($unreconciled);
|
||||
$charges = $unreconciled['entries'];
|
||||
$stats = $unreconciled['summary']['Charge'];
|
||||
// Kludge until we update receipt to have the unpaid
|
||||
// charges grid generated from a dynamic query instead
|
||||
// of simply pre-providing the list of charge IDs
|
||||
foreach ($charges AS &$charge)
|
||||
$charge['id'] = $charge['StatementEntry']['id'];
|
||||
}
|
||||
else {
|
||||
$customer = null;
|
||||
$charges = array();
|
||||
$stats = array('balance' => 0);
|
||||
}
|
||||
|
||||
$TT = new TenderType();
|
||||
@@ -388,8 +381,8 @@ class CustomersController extends AppController {
|
||||
$default_type = $TT->defaultPaymentType();
|
||||
$this->set(compact('payment_types', 'default_type'));
|
||||
|
||||
$title = ($customer['name'] . ': Payment Entry');
|
||||
$this->set(compact('customer', 'charges', 'stats', 'title'));
|
||||
$title = ($customer['name'] . ': Receipt Entry');
|
||||
$this->set(compact('customer', 'title'));
|
||||
}
|
||||
|
||||
|
||||
@@ -400,58 +393,64 @@ class CustomersController extends AppController {
|
||||
* - Refunds customer charges
|
||||
*/
|
||||
|
||||
function refund() {
|
||||
$entries = $this->Customer->StatementEntry->find
|
||||
('all', array
|
||||
function refund($id) {
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
'conditions' => array('StatementEntry.id' =>
|
||||
//array(199,200,201)
|
||||
61
|
||||
'conditions' => array(array('Customer.id' => $id),
|
||||
),
|
||||
));
|
||||
pr(compact('entries'));
|
||||
if (empty($customer)) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
$this->Customer->StatementEntry->reverse($entries);
|
||||
// Determine the customer balance, bailing if the customer owes money
|
||||
$balance = $this->Customer->balance($id);
|
||||
if ($balance >= 0) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// The refund will be for a positive amount
|
||||
$balance *= -1;
|
||||
|
||||
// Get the accounts capable of paying the refund
|
||||
$refundAccounts = $this->Customer->StatementEntry->Account->refundAccounts();
|
||||
$defaultAccount = current($refundAccounts);
|
||||
$this->set(compact('refundAccounts', 'defaultAccount'));
|
||||
|
||||
// Prepare to render
|
||||
$title = ($customer['Customer']['name'] . ': Refund');
|
||||
$this->set(compact('title', 'customer', 'balance'));
|
||||
$this->render('/transactions/refund');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: unreconciled
|
||||
* - returns the list of unreconciled entries
|
||||
* action: bad_debt
|
||||
* - Sets up the write-off entry page, so that the
|
||||
* user can write off remaining charges of a customer.
|
||||
*/
|
||||
|
||||
function unreconciled($id) {
|
||||
function bad_debt($id) {
|
||||
$this->Customer->id = $id;
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
));
|
||||
|
||||
//$this->layout = 'ajax';
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
$this->autoRender = false;
|
||||
//Configure::write('debug', '0');
|
||||
//header("Content-type: text/xml;charset=utf-8");
|
||||
// Make sure we have a valid customer to write off
|
||||
if (empty($customer))
|
||||
$this->redirect(array('action' => 'index'));
|
||||
|
||||
App::import('Helper', 'Xml');
|
||||
$xml = new XmlHelper();
|
||||
// Get the customer balance
|
||||
$balance = $this->Customer->balance($id);
|
||||
|
||||
// Find the unreconciled entries, then manipulate the structure
|
||||
// slightly to accomodate the format necessary for XML Helper.
|
||||
$unreconciled = $this->Customer->unreconciledCharges($id);
|
||||
$unreconciled = array('entries' =>
|
||||
array_intersect_key($unreconciled['debit'],
|
||||
array('entry'=>1, 'balance'=>1)));
|
||||
|
||||
// XML Helper will dump an empty tag if the array is empty
|
||||
if (!count($unreconciled['entries']['entry']))
|
||||
unset($unreconciled['entries']['entry']);
|
||||
|
||||
//pr($unreconciled);
|
||||
//$reconciled = $cust->reconcileNewStatementEntry($cust_id, 'credit', $amount);
|
||||
|
||||
$opts = array();
|
||||
//$opts['format'] = 'tags';
|
||||
echo $xml->header();
|
||||
echo $xml->serialize($unreconciled, $opts);
|
||||
// Prepare to render
|
||||
$title = ($customer['Customer']['name'] . ': Write Off Bad Debt');
|
||||
$this->set(compact('title', 'customer', 'balance'));
|
||||
$this->render('/transactions/bad_debt');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,28 @@ class DoubleEntriesController extends AppController {
|
||||
'conditions' => array('DoubleEntry.id' => $id),
|
||||
));
|
||||
|
||||
$entry += $this->DoubleEntry->DebitEntry->Transaction->find
|
||||
('first',
|
||||
array('contain' => false,
|
||||
'conditions' => array('id' => $entry['DebitEntry']['transaction_id']),
|
||||
));
|
||||
|
||||
$entry += $this->DoubleEntry->DebitEntry->find
|
||||
('first',
|
||||
array('contain' => array('Ledger' => array('Account')),
|
||||
'conditions' => array('DebitEntry.id' => $entry['DebitEntry']['id']),
|
||||
));
|
||||
$entry['DebitLedger'] = $entry['Ledger'];
|
||||
unset($entry['Ledger']);
|
||||
|
||||
$entry += $this->DoubleEntry->CreditEntry->find
|
||||
('first',
|
||||
array('contain' => array('Ledger' => array('Account')),
|
||||
'conditions' => array('CreditEntry.id' => $entry['CreditEntry']['id']),
|
||||
));
|
||||
$entry['CreditLedger'] = $entry['Ledger'];
|
||||
unset($entry['Ledger']);
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}";
|
||||
$this->set(compact('entry', 'title'));
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
class LeasesController extends AppController {
|
||||
|
||||
var $sidemenu_links =
|
||||
array(array('name' => 'Leases', 'header' => true),
|
||||
array('name' => 'Active', 'url' => array('controller' => 'leases', 'action' => 'active')),
|
||||
array('name' => 'Closed', 'url' => array('controller' => 'leases', 'action' => 'closed')),
|
||||
array('name' => 'All', 'url' => array('controller' => 'leases', 'action' => 'all')),
|
||||
array(array('name' => 'Leases', 'header' => true),
|
||||
array('name' => 'Active', 'url' => array('controller' => 'leases', 'action' => 'active')),
|
||||
array('name' => 'Closed', 'url' => array('controller' => 'leases', 'action' => 'closed')),
|
||||
array('name' => 'Delinquent', 'url' => array('controller' => 'leases', 'action' => 'delinquent')),
|
||||
array('name' => 'All', 'url' => array('controller' => 'leases', 'action' => 'all')),
|
||||
);
|
||||
|
||||
|
||||
@@ -28,10 +29,11 @@ class LeasesController extends AppController {
|
||||
* - Generate a listing of leases
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function active() { $this->gridView('Active Leases'); }
|
||||
function closed() { $this->gridView('Closed Leases'); }
|
||||
function all() { $this->gridView('All Leases', 'all'); }
|
||||
function index() { $this->all(); }
|
||||
function active() { $this->gridView('Active Leases'); }
|
||||
function delinquent() { $this->gridView('Delinquent Leases'); }
|
||||
function closed() { $this->gridView('Closed Leases'); }
|
||||
function all() { $this->gridView('All Leases', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
@@ -63,8 +65,10 @@ class LeasesController extends AppController {
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
$fields[] = ("IF(" . $this->Lease->conditionDelinquent() . "," .
|
||||
" 'DELINQUENT', 'CURRENT') AS 'status'");
|
||||
return array_merge($fields,
|
||||
$this->Lease->StatementEntry->chargePaymentFields(true));
|
||||
$this->Lease->StatementEntry->chargeDisbursementFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
@@ -73,6 +77,9 @@ class LeasesController extends AppController {
|
||||
if ($params['action'] === 'active') {
|
||||
$conditions[] = 'Lease.close_date IS NULL';
|
||||
}
|
||||
elseif ($params['action'] === 'delinquent') {
|
||||
$conditions[] = $this->Lease->conditionDelinquent();
|
||||
}
|
||||
elseif ($params['action'] === 'closed') {
|
||||
$conditions[] = 'Lease.close_date IS NOT NULL';
|
||||
}
|
||||
@@ -135,21 +142,22 @@ class LeasesController extends AppController {
|
||||
|
||||
// Handle the move in based on the data given
|
||||
//pr(array('Move-in data', $this->data));
|
||||
foreach (array('deposit', 'rent') AS $currency) {
|
||||
$this->data['Lease'][$currency]
|
||||
= str_replace('$', '', $this->data['Lease'][$currency]);
|
||||
}
|
||||
|
||||
$lid = $this->Lease->moveIn($this->data['Lease']['customer_id'],
|
||||
$this->data['Lease']['unit_id'],
|
||||
null, null,
|
||||
$this->data['Lease']['deposit'],
|
||||
$this->data['Lease']['rent'],
|
||||
$this->data['Lease']['movein_date'],
|
||||
$this->data['Lease']['comment']
|
||||
);
|
||||
|
||||
// Since this is a new lease, go to the invoice
|
||||
// screen so we can start assessing charges.
|
||||
$this->redirect(array('action'=>'invoice', $lid));
|
||||
|
||||
// For debugging, only if the redirect above have been
|
||||
// commented out, otherwise this section isn't reached.
|
||||
$this->render('/empty');
|
||||
$this->redirect(array('action'=>'invoice', $lid, 'move-in'));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
@@ -166,14 +174,10 @@ class LeasesController extends AppController {
|
||||
|
||||
$this->Lease->moveOut($this->data['Lease']['id'],
|
||||
'VACANT',
|
||||
$this->data['Lease']['moveout_date'],
|
||||
//true // Close this lease, if able
|
||||
false
|
||||
$this->data['Lease']['moveout_date']
|
||||
);
|
||||
|
||||
$this->redirect($this->data['redirect']);
|
||||
$this->autoRender = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($id))
|
||||
@@ -213,118 +217,67 @@ class LeasesController extends AppController {
|
||||
}
|
||||
|
||||
|
||||
/* /\************************************************************************** */
|
||||
/* ************************************************************************** */
|
||||
/* ************************************************************************** */
|
||||
/* * action: promote_credit */
|
||||
/* * - Moves any lease credit up to the customer level, so that */
|
||||
/* * it may be used for charges other than those on this lease. */
|
||||
/* *\/ */
|
||||
|
||||
/* function promote_surplus($id) { */
|
||||
/* $this->Lease->promoteSurplus($id); */
|
||||
/* $this->redirect(array('controller' => 'leases', */
|
||||
/* 'action' => 'view', */
|
||||
/* $id)); */
|
||||
/* } */
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: apply_deposit
|
||||
* - Applies the security deposit to charges. This is much
|
||||
* like a receipt, but it's separated to keep it simple and
|
||||
* to prevent feature overload on the receipt page.
|
||||
* action: refund
|
||||
* - Provides lease customer with a refund
|
||||
*/
|
||||
|
||||
function apply_deposit($id = null) {
|
||||
// Create some models for convenience
|
||||
$A = new Account();
|
||||
|
||||
if ($this->data) {
|
||||
// Handle the move out based on the data given
|
||||
pr($this->data);
|
||||
$this->Lease->releaseSecurityDeposits($this->data['Lease']['id']);
|
||||
die();
|
||||
|
||||
// Assume this will succeed
|
||||
$ret = true;
|
||||
|
||||
// Go through the entered payments
|
||||
$receipt_transaction = array_intersect_key($this->data,
|
||||
array('Transaction'=>1,
|
||||
'transaction_id'=>1));
|
||||
foreach ($data['StatementEntry'] AS $entry) {
|
||||
// Create the receipt entry, and reconcile the credit side
|
||||
// of the double-entry (which should be A/R) as a payment.
|
||||
$ids = $this->StatementEntry->Ledger->Account->postLedgerEntry
|
||||
($receipt_transaction,
|
||||
array_intersect_key($entry, array('MonetarySource'=>1))
|
||||
+ array_intersect_key($entry, array('account_id'=>1)),
|
||||
array('debit_ledger_id' => $A->currentLedgerID($entry['account_id']),
|
||||
'credit_ledger_id' => $A->currentLedgerID($A->receiptAccountID()),
|
||||
'customer_id' => $customer_id,
|
||||
'lease_id' => $lease_id)
|
||||
+ $entry,
|
||||
'receipt');
|
||||
|
||||
if ($ids['error'])
|
||||
$ret = false;
|
||||
|
||||
$db = &$model->getDataSource();
|
||||
$fields = $db->fields($model, $model->alias);
|
||||
$fields[] = ("SUM(IF(Account.id IS NULL, 0," .
|
||||
" IF(LedgerEntry.debit_ledger_id = Account.id," .
|
||||
" 1, -1))" .
|
||||
" * IF(LedgerEntry.amount IS NULL, 0, LedgerEntry.amount))" .
|
||||
" AS 'balance'");
|
||||
return $fields;
|
||||
$receipt_transaction = array_intersect_key($ids,
|
||||
array('transaction_id'=>1,
|
||||
'split_transaction_id'=>1));
|
||||
}
|
||||
|
||||
$this->Lease->moveOut($this->data['Lease']['id'],
|
||||
'VACANT',
|
||||
$this->data['Lease']['moveout_date'],
|
||||
//true // Close this lease, if able
|
||||
false
|
||||
);
|
||||
|
||||
$this->redirect(array('controller' => 'leases',
|
||||
'action' => 'view',
|
||||
$this->data['Lease']['id']));
|
||||
$this->autoRender = false;
|
||||
return;
|
||||
}
|
||||
|
||||
$A = new Account();
|
||||
|
||||
function refund($id) {
|
||||
$lease = $this->Lease->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
|
||||
'Customer' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
'Unit' => array('fields' => array('id', 'name')),
|
||||
'Customer' => array('fields' => array('id', 'name')),
|
||||
),
|
||||
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
// Make sure lease is not closed...
|
||||
array('Lease.close_date' => null),
|
||||
),
|
||||
));
|
||||
if (empty($lease)) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// Determine the lease balance, bailing if the customer owes money
|
||||
$balance = $this->Lease->balance($id);
|
||||
if ($balance >= 0) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// Get the lease balance, part of lease stats
|
||||
$this->Lease->statsMerge($lease['Lease'],
|
||||
array('stats' => $this->Lease->stats($id)));
|
||||
// The refund will be for a positive amount
|
||||
$balance *= -1;
|
||||
|
||||
// Determine the lease security deposit
|
||||
$deposit_balance = $this->Lease->securityDeposits($lease['Lease']['id']);
|
||||
$this->set(compact('deposit_balance'));
|
||||
$this->set('customer', $lease['Customer']);
|
||||
$this->set('unit', $lease['Unit']);
|
||||
$this->set('lease', $lease['Lease']);
|
||||
$this->set('account', array('id' => $A->securityDepositAccountID()));
|
||||
|
||||
/* $redirect = array('controller' => 'leases', */
|
||||
/* 'action' => 'view', */
|
||||
/* $id); */
|
||||
// Get the accounts capable of paying the refund
|
||||
$refundAccounts = $this->Lease->StatementEntry->Account->refundAccounts();
|
||||
$defaultAccount = current($refundAccounts);
|
||||
$this->set(compact('refundAccounts', 'defaultAccount'));
|
||||
|
||||
// Prepare to render
|
||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||
$lease['Unit']['name'] . ': ' .
|
||||
$lease['Customer']['name'] . ': Utilize Security Deposit');
|
||||
$this->set(compact('title', 'redirect'));
|
||||
$lease['Customer']['name'] . ': Refund');
|
||||
$this->set(compact('title', 'lease', 'balance'));
|
||||
$this->render('/transactions/refund');
|
||||
}
|
||||
|
||||
|
||||
@@ -332,82 +285,34 @@ class LeasesController extends AppController {
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: bad_debt
|
||||
* - Writes off remaining charges on a lease.
|
||||
* REVISIT <AP>: 20090710
|
||||
* Should this be a customer function? What customer
|
||||
* would have only one lease that results in bad debt.
|
||||
* - Sets up the write-off entry page, so that the
|
||||
* user can write off remaining charges on a lease.
|
||||
*/
|
||||
|
||||
function bad_debt($id) {
|
||||
$A = new Account();
|
||||
|
||||
$this->Lease->id = $id;
|
||||
$lease = $this->Lease->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
|
||||
'Customer' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
'Unit' => array('fields' => array('id', 'name')),
|
||||
'Customer' => array('fields' => array('id', 'name')),
|
||||
),
|
||||
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
array('Lease.close_date' => null),
|
||||
),
|
||||
));
|
||||
|
||||
// Make sure we have a valid lease to write off
|
||||
if (empty($lease))
|
||||
$this->redirect(array('action' => 'view', $id));
|
||||
|
||||
// Get the lease balance, part of lease stats
|
||||
$this->Lease->statsMerge($lease['Lease'],
|
||||
array('stats' => $this->Lease->stats($id)));
|
||||
|
||||
// Determine the lease security deposit
|
||||
$deposit_balance = $this->Lease->securityDepositBalance($lease['Lease']['id']);
|
||||
if ($deposit_balance > 0)
|
||||
die("Still have un-utilized security deposit");
|
||||
|
||||
$this->set('customer', $lease['Customer']);
|
||||
$this->set('unit', $lease['Unit']);
|
||||
$this->set('lease', $lease['Lease']);
|
||||
$this->set('account', array('id' => $A->badDebtAccountID()));
|
||||
|
||||
/* $redirect = array('controller' => 'leases', */
|
||||
/* 'action' => 'view', */
|
||||
/* $id); */
|
||||
// Get the lease balance
|
||||
$balance = $this->Lease->balance($id);
|
||||
|
||||
// Prepare to render
|
||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||
$lease['Unit']['name'] . ': ' .
|
||||
$lease['Customer']['name'] . ': Write Off Bad Debt');
|
||||
$this->set(compact('title', 'redirect'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: refund
|
||||
* - Provides user with a refund
|
||||
* REVISIT <AP>: 20090710
|
||||
* Should this be a customer function?
|
||||
*/
|
||||
|
||||
function refund($id) {
|
||||
/* // Obtain the overall lease balance */
|
||||
/* $stats = $this->Lease->stats($id); */
|
||||
/* $outstanding_balance = $stats['balance']; */
|
||||
|
||||
/* // Determine the lease security deposit */
|
||||
/* $deposits = $this->Lease->securityDeposits($id); */
|
||||
/* $outstanding_deposit = $deposits['summary']['balance']; */
|
||||
|
||||
|
||||
/* $this->set(compact('lease', 'title', */
|
||||
/* 'outstanding_deposit', */
|
||||
/* 'outstanding_balance')); */
|
||||
$this->set(compact('title', 'lease', 'balance'));
|
||||
$this->render('/transactions/bad_debt');
|
||||
}
|
||||
|
||||
|
||||
@@ -418,9 +323,23 @@ class LeasesController extends AppController {
|
||||
* - Closes a lease to any further action
|
||||
*/
|
||||
|
||||
// REVISIT <AP>: 20090809
|
||||
// While cleaning up the sitelink data, then delete reldep()
|
||||
function reldep($id) {
|
||||
$this->Lease->id = $id;
|
||||
$stamp = $this->Lease->field('moveout_date');
|
||||
$this->Lease->releaseSecurityDeposits($id, $stamp);
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
function close($id) {
|
||||
// REVISIT <AP>: 20090708
|
||||
// We should probably seek confirmation first...
|
||||
if (!$this->Lease->closeable($id)) {
|
||||
$this->INTERNAL_ERROR("This lease is not ready to close");
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
$this->Lease->close($id);
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
@@ -455,15 +374,32 @@ class LeasesController extends AppController {
|
||||
));
|
||||
|
||||
$A = new Account();
|
||||
$charge_accounts = $A->chargeAccounts();
|
||||
$charge_accounts = $A->invoiceAccounts();
|
||||
$default_account = $A->rentAccountID();
|
||||
$this->set(compact('charge_accounts', 'default_account'));
|
||||
$rent_account = $A->rentAccountID();
|
||||
$security_deposit_account = $A->securityDepositAccountID();
|
||||
$this->set(compact('charge_accounts', 'default_account',
|
||||
'rent_account', 'security_deposit_account'));
|
||||
|
||||
// REVISIT <AP> 20090705:
|
||||
// Of course, the late charge should come from the late_schedule
|
||||
$default_rent = $lease['Lease']['rent'];
|
||||
$default_late = 10;
|
||||
$this->set(compact('default_rent', 'default_late'));
|
||||
$this->set(compact('default_late'));
|
||||
|
||||
if ($type === 'move-in') {
|
||||
$movein = array();
|
||||
$movein['time'] = strtotime($lease['Lease']['movein_date']);
|
||||
$movein['effective_time'] = strtotime($lease['Lease']['movein_date']);
|
||||
$movein_date = getdate($movein['effective_time']);
|
||||
$movein['through_time'] = mktime(0, 0, 0, $movein_date['mon'] + 1, 0, $movein_date['year']);
|
||||
$days_in_month = idate('d', $movein['through_time']);
|
||||
$movein['prorated_days'] = $days_in_month - $movein_date['mday'] + 1;
|
||||
$movein['prorated_rent'] = $lease['Lease']['rent'] * $movein['prorated_days'] / $days_in_month;
|
||||
$movein['prorated'] = $movein['prorated_days'] != $days_in_month;
|
||||
$movein['deposit'] = $lease['Lease']['deposit'];
|
||||
$this->set(compact('movein'));
|
||||
}
|
||||
|
||||
|
||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||
$lease['Unit']['name'] . ': ' .
|
||||
@@ -472,6 +408,27 @@ class LeasesController extends AppController {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: assess_rent/late
|
||||
* - Assesses the new monthly rent/late charge, if need be
|
||||
*/
|
||||
|
||||
function assess_rent($date = null) {
|
||||
$this->Lease->assessMonthlyRentAll($date);
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
function assess_late($date = null) {
|
||||
$this->Lease->assessMonthlyLateAll($date);
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
function assess_all($date = null) {
|
||||
$this->Lease->assessMonthlyRentAll($date);
|
||||
$this->Lease->assessMonthlyLateAll($date);
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -490,30 +447,26 @@ class LeasesController extends AppController {
|
||||
('first',
|
||||
array('contain' =>
|
||||
array(// Models
|
||||
'LeaseType',
|
||||
'Unit',
|
||||
'Customer',
|
||||
'LeaseType(id,name)',
|
||||
'Unit(id,name)',
|
||||
'Customer(id,name)',
|
||||
),
|
||||
'fields' => array('Lease.*', $this->Lease->delinquentField()),
|
||||
'conditions' => array(array('Lease.id' => $id)),
|
||||
)
|
||||
);
|
||||
$lease['Lease'] += $lease[0];
|
||||
unset($lease[0]);
|
||||
|
||||
$lease['Lease']['paid_through'] = $this->Lease->rentPaidThrough($id);
|
||||
// Figure out the outstanding balances for this lease
|
||||
$outstanding_balance = $this->Lease->balance($id);
|
||||
$outstanding_deposit = $this->Lease->securityDepositBalance($id);
|
||||
|
||||
|
||||
$this->set('charge_gaps', $this->Lease->rentChargeGaps($id));
|
||||
$this->set('charge_through', $this->Lease->rentChargeThrough($id));
|
||||
|
||||
// Obtain the overall lease balance
|
||||
$this->Lease->statsMerge($lease['Lease'],
|
||||
array('stats' => $this->Lease->stats($id)));
|
||||
$outstanding_balance = $lease['Lease']['stats']['balance'];
|
||||
|
||||
// Determine the lease security deposit
|
||||
$outstanding_deposit = $this->Lease->securityDepositBalance($lease['Lease']['id']);
|
||||
|
||||
// Set up dynamic menu items
|
||||
if (!isset($lease['Lease']['close_date'])) {
|
||||
// Set up dynamic menu items. Normally, these will only be present
|
||||
// on an open lease, but it's possible for a lease to be closed, and
|
||||
// yet still have an outstanding balance. This can happen if someone
|
||||
// were to reverse charges, or if a payment should come back NSF.
|
||||
if (!isset($lease['Lease']['close_date']) || $outstanding_balance > 0) {
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
|
||||
@@ -522,28 +475,36 @@ class LeasesController extends AppController {
|
||||
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
|
||||
$id));
|
||||
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Charges', 'url' => array('action' => 'invoice',
|
||||
$id));
|
||||
if (!isset($lease['Lease']['close_date']))
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'New Invoice', 'url' => array('action' => 'invoice',
|
||||
$id));
|
||||
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Payments', 'url' => array('controller' => 'customers',
|
||||
'action' => 'receipt',
|
||||
$lease['Customer']['id']));
|
||||
array('name' => 'New Receipt', 'url' => array('controller' => 'customers',
|
||||
'action' => 'receipt',
|
||||
$lease['Customer']['id']));
|
||||
|
||||
if (isset($lease['Lease']['moveout_date']) && $outstanding_deposit > 0 && $outstanding_balance > 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Apply Deposit', 'url' => array('action' => 'apply_deposit',
|
||||
$id));
|
||||
/* if ($outstanding_balance < 0) */
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Transfer Credit to Customer', */
|
||||
/* 'url' => array('action' => 'promote_surplus', $id)); */
|
||||
|
||||
if (isset($lease['Lease']['moveout_date']) &&
|
||||
$outstanding_balance <= 0 &&
|
||||
($outstanding_deposit - $outstanding_balance) > 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Issue Refund', 'url' => array('action' => 'refund',
|
||||
$id));
|
||||
// REVISIT <AP>:
|
||||
// Not allowing refund to be issued from the lease, as
|
||||
// in fact, we should never have a positive lease balance.
|
||||
// I'll flag this at the moment, since we might get one
|
||||
// when a charge is reimbursed; a bug that we'll either
|
||||
// need to fix, or we'll have to revisit this assumption.
|
||||
if ($outstanding_balance < 0)
|
||||
$this->INTERNAL_ERROR("Should not have a customer lease credit.");
|
||||
|
||||
if (isset($lease['Lease']['moveout_date']) && $outstanding_deposit == 0 && $outstanding_balance > 0)
|
||||
/* if ($outstanding_balance < 0) */
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Issue Refund', */
|
||||
/* 'url' => array('action' => 'refund', $id)); */
|
||||
|
||||
if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Write-Off', 'url' => array('action' => 'bad_debt',
|
||||
$id));
|
||||
|
||||
@@ -16,6 +16,16 @@ class LedgerEntriesController extends AppController {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / current / past / all
|
||||
* - Creates a list of ledger entries
|
||||
*/
|
||||
|
||||
function index() { $this->gridView('All Ledger Entries'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -135,12 +145,6 @@ class LedgerEntriesController extends AppController {
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
// Get the Entry and related fields
|
||||
$entry = $this->LedgerEntry->find
|
||||
('first',
|
||||
array('contain' => array
|
||||
@@ -153,6 +157,10 @@ class LedgerEntriesController extends AppController {
|
||||
array('fields' => array('id', 'sequence', 'name'),
|
||||
'Account' =>
|
||||
array('fields' => array('id', 'name', 'type'),
|
||||
'conditions' =>
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
array('Account.level >=' => 5),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -160,6 +168,9 @@ class LedgerEntriesController extends AppController {
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
|
||||
'DebitDoubleEntry' => array('id'),
|
||||
'CreditDoubleEntry' => array('id'),
|
||||
|
||||
'DebitEntry' => array('fields' => array('id', 'crdr')),
|
||||
'CreditEntry' => array('fields' => array('id', 'crdr')),
|
||||
),
|
||||
@@ -167,6 +178,11 @@ class LedgerEntriesController extends AppController {
|
||||
'conditions' => array('LedgerEntry.id' => $id),
|
||||
));
|
||||
|
||||
if (empty($entry) || empty($entry['Ledger']['Account'])) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
if (!empty($entry['DebitEntry']) && !empty($entry['CreditEntry']))
|
||||
die("LedgerEntry has both a matching DebitEntry and CreditEntry");
|
||||
if (empty($entry['DebitEntry']) && empty($entry['CreditEntry']))
|
||||
@@ -181,6 +197,11 @@ class LedgerEntriesController extends AppController {
|
||||
else
|
||||
$entry['MatchingEntry'] = $entry['DebitEntry'][0];
|
||||
|
||||
if (empty($entry['DebitDoubleEntry']['id']))
|
||||
$entry['DoubleEntry'] = $entry['CreditDoubleEntry'];
|
||||
else
|
||||
$entry['DoubleEntry'] = $entry['DebitDoubleEntry'];
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Ledger Entry #{$entry['LedgerEntry']['id']}";
|
||||
$this->set(compact('entry', 'title'));
|
||||
|
||||
@@ -50,24 +50,21 @@ class LedgersController extends AppController {
|
||||
}
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
// Our count should NOT include anything extra,
|
||||
// so we need the virtual function to prevent
|
||||
// the base class from just calling our
|
||||
// gridDataTables function.
|
||||
return parent::gridDataTables($params, $model);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
return array
|
||||
('link' =>
|
||||
array(// Models
|
||||
'Account',
|
||||
'LedgerEntry',
|
||||
'CloseTransaction',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$tables = $this->gridDataCountTables($params, $model);
|
||||
$tables['link'][] = 'LedgerEntry';
|
||||
$tables['link'][] = 'CloseTransaction';
|
||||
return $tables;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
$fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence';
|
||||
@@ -85,6 +82,10 @@ class LedgersController extends AppController {
|
||||
$conditions[] = array('Ledger.close_transaction_id !=' => null);
|
||||
}
|
||||
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
$conditions[] = array('Account.level >=' => 10);
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
@@ -119,22 +120,25 @@ class LedgersController extends AppController {
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Get details about the ledger itself (no entries yet)
|
||||
$ledger = $this->Ledger->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
array(// Models
|
||||
'Account',
|
||||
),
|
||||
'conditions' => array(array('Ledger.id' => $id)),
|
||||
'conditions' => array(array('Ledger.id' => $id),
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
array('Account.level >=' => 10),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if (empty($ledger)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Get ledger stats for our summary box
|
||||
$stats = $this->Ledger->stats($id);
|
||||
|
||||
|
||||
@@ -85,11 +85,33 @@ class MapsController extends AppController {
|
||||
'units' => array());
|
||||
|
||||
// Find all of the map/unit information from this SiteArea
|
||||
$this->Map->recursive = 2;
|
||||
$this->Map->SiteArea->unbindModel(array('hasOne' => array('Map')));
|
||||
$map = $this->Map->read(null, $id);
|
||||
//pr($map);
|
||||
|
||||
$map = $this->Map->find('first', array('contain' => false,
|
||||
'conditions' => array('id' => $id)));
|
||||
|
||||
$units = $this->Map->Unit->find
|
||||
('all',
|
||||
array('link' =>
|
||||
array('Map' =>
|
||||
array('fields' => array()),
|
||||
|
||||
'CurrentLease' =>
|
||||
array('fields' => array($this->Map->Unit->CurrentLease->
|
||||
delinquentField('CurrentLease'))),
|
||||
|
||||
'UnitSize' =>
|
||||
array('fields' => array('id', 'depth', 'width',
|
||||
'MapsUnit.pt_top',
|
||||
'MapsUnit.pt_left',
|
||||
'MapsUnit.transpose')),
|
||||
),
|
||||
'fields' => array('id', 'name', 'status'),
|
||||
'conditions' => array('Map.id' => $id),
|
||||
));
|
||||
|
||||
/* pr(compact('map', 'units')); */
|
||||
/* $this->render('/empty'); */
|
||||
/* return; */
|
||||
|
||||
/*****
|
||||
* The preference would be to leave all things "screen" related
|
||||
* to reside in the view. However, two separate views need this
|
||||
@@ -113,7 +135,7 @@ class MapsController extends AppController {
|
||||
$info['depth'] = $bottom * $screen_adjustment_factor;
|
||||
|
||||
// Go through each unit in the map, calculating the map location
|
||||
foreach ($map['Unit'] AS $unit) {
|
||||
foreach ($units AS $unit) {
|
||||
$lft = $unit['MapsUnit']['pt_left'] + $boundary_adjustment;
|
||||
$top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment;
|
||||
|
||||
@@ -132,10 +154,9 @@ class MapsController extends AppController {
|
||||
$width *= $screen_adjustment_factor;
|
||||
$depth *= $screen_adjustment_factor;
|
||||
|
||||
//$info['units'][$unit['id']] =
|
||||
$info['units'][] =
|
||||
array( 'id' => $unit['id'],
|
||||
'name' => $unit['name'],
|
||||
array( 'id' => $unit['Unit']['id'],
|
||||
'name' => $unit['Unit']['name'],
|
||||
'left' => $lft,
|
||||
'right' => $lft + $width,
|
||||
'top' => $top,
|
||||
@@ -143,11 +164,14 @@ class MapsController extends AppController {
|
||||
'width' => $width,
|
||||
'depth' => $depth,
|
||||
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
|
||||
'status' => $unit['status']
|
||||
'status' => (($unit['Unit']['status'] === 'OCCUPIED' &&
|
||||
!empty($unit[0]['delinquent']))
|
||||
? 'LATE' : $unit['Unit']['status'])
|
||||
);
|
||||
}
|
||||
|
||||
//pr($info);
|
||||
/* pr($info); */
|
||||
/* $this->render('/empty'); */
|
||||
return $info;
|
||||
}
|
||||
|
||||
@@ -160,8 +184,10 @@ class MapsController extends AppController {
|
||||
*/
|
||||
|
||||
function legend($id = null, $requested_width = 400) {
|
||||
$status = $this->Map->Unit->activeStatusEnums();
|
||||
//pr($status);
|
||||
$status = array_keys($this->Map->Unit->activeStatusEnums());
|
||||
$occupied_key = array_search('OCCUPIED', $status);
|
||||
array_splice($status, $occupied_key+1, 0, array('LATE'));
|
||||
|
||||
$rows = 2;
|
||||
$cols = (int)((count($status) + $rows - 1) / $rows);
|
||||
|
||||
@@ -191,7 +217,7 @@ class MapsController extends AppController {
|
||||
$item_width *= $screen_adjustment_factor;
|
||||
$item_depth *= $screen_adjustment_factor;
|
||||
|
||||
foreach ($status AS $code => $value) {
|
||||
foreach ($status AS $code) {
|
||||
$info['units'][] = array('name' => $code,
|
||||
'status' => $code,
|
||||
'width' => $item_width,
|
||||
@@ -241,9 +267,9 @@ class MapsController extends AppController {
|
||||
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
|
||||
$info['palate']['unit']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
|
||||
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
|
||||
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
|
||||
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 128, 'blue' => 128);
|
||||
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
|
||||
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
|
||||
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
|
||||
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 0, 'blue' => 128);
|
||||
|
||||
// Determine text color to go with each background
|
||||
foreach ($info['palate']['unit'] AS &$code) {
|
||||
|
||||
@@ -16,6 +16,16 @@ class StatementEntriesController extends AppController {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / current / past / all
|
||||
* - Creates a list of statement entries
|
||||
*/
|
||||
|
||||
function index() { $this->gridView('All Statement Entries'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -25,7 +35,7 @@ class StatementEntriesController extends AppController {
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
$link =
|
||||
array(// Models
|
||||
'Transaction' =>
|
||||
@@ -48,44 +58,45 @@ class StatementEntriesController extends AppController {
|
||||
),
|
||||
);
|
||||
|
||||
if (isset($params['post']['custom']['statement_entry_id'])) {
|
||||
$link['PaymentEntry'] = array();
|
||||
$link['ChargeEntry'] = array();
|
||||
if (!empty($params['post']['custom']['statement_entry_id'])) {
|
||||
$link['ChargeEntry'] = array();
|
||||
$link['DisbursementEntry'] = array();
|
||||
}
|
||||
|
||||
/* if ($params['action'] === 'collected') { */
|
||||
/* $link['PaymentEntry'] = array('Receipt' => array('class' => 'Transaction')); */
|
||||
/* $link['ChargeEntry'] = array('Invoice' => array('class' => 'Transaction')); */
|
||||
/* } */
|
||||
|
||||
/* if (count(array_intersect($params['fields'], array('applied'))) == 1) { */
|
||||
/* $link['PaymentEntry'] = array(); */
|
||||
/* $link['ChargeEntry'] = array(); */
|
||||
/* } */
|
||||
/* elseif (isset($params['post']['custom']['customer_id']) || isset($params['post']['custom']['lease_id'])) { */
|
||||
/* $link['PaymentEntry'] = array(); */
|
||||
/* } */
|
||||
|
||||
return array('link' => $link);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$tables = $this->gridDataCountTables($params, $model);
|
||||
|
||||
if (in_array('applied', $params['post']['fields'])) {
|
||||
$tables['link'] +=
|
||||
array('ChargeEntry' => array(),
|
||||
'DisbursementEntry' => array());
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
|
||||
if (in_array('applied', $params['post']['fields'])) {
|
||||
$fields[] = ("IF(StatementEntry.type = 'CHARGE'," .
|
||||
" SUM(COALESCE(PaymentEntry.amount,0))," .
|
||||
" SUM(COALESCE(DisbursementEntry.amount,0))," .
|
||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||
" AS 'applied'");
|
||||
}
|
||||
if (in_array('unapplied', $params['post']['fields'])) {
|
||||
$fields[] = ("StatementEntry.amount - (" .
|
||||
"IF(StatementEntry.type = 'CHARGE'," .
|
||||
" SUM(COALESCE(PaymentEntry.amount,0))," .
|
||||
" SUM(COALESCE(DisbursementEntry.amount,0))," .
|
||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||
") AS 'balance'");
|
||||
") AS 'unapplied'");
|
||||
}
|
||||
|
||||
$fields = array_merge($fields,
|
||||
$this->StatementEntry->chargePaymentFields());
|
||||
$this->StatementEntry->chargeDisbursementFields());
|
||||
|
||||
return $fields;
|
||||
}
|
||||
@@ -107,10 +118,25 @@ class StatementEntriesController extends AppController {
|
||||
if (isset($account_id))
|
||||
$conditions[] = array('StatementEntry.account_id' => $account_id);
|
||||
|
||||
if (isset($customer_id))
|
||||
$conditions[] = array('StatementEntry.customer_id' => $customer_id);
|
||||
|
||||
if (isset($statement_entry_id)) {
|
||||
$conditions[] = array('OR' =>
|
||||
array(array('ChargeEntry.id' => $statement_entry_id),
|
||||
array('PaymentEntry.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;
|
||||
@@ -141,26 +167,26 @@ class StatementEntriesController extends AppController {
|
||||
}
|
||||
|
||||
function gridDataRecordsExecute(&$params, &$model, $query) {
|
||||
if (in_array('applied', $params['post']['fields'])) {
|
||||
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
|
||||
$tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," .
|
||||
" SUM(COALESCE(PaymentEntry.amount,0))," .
|
||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||
" AS 'applied'",
|
||||
/* 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'", */
|
||||
|
||||
"StatementEntry.amount - (" .
|
||||
"IF(StatementEntry.type = 'CHARGE'," .
|
||||
" SUM(COALESCE(PaymentEntry.amount,0))," .
|
||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||
") AS 'balance'",
|
||||
);
|
||||
/* "StatementEntry.amount - (" . */
|
||||
/* "IF(StatementEntry.type = 'CHARGE'," . */
|
||||
/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */
|
||||
/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */
|
||||
/* ") AS 'balance'", */
|
||||
/* ); */
|
||||
|
||||
//pr(compact('tquery'));
|
||||
$total = $model->find('first', $tquery);
|
||||
$params['userdata']['total'] = $total[0]['applied'];
|
||||
$params['userdata']['balance'] = $total[0]['balance'];
|
||||
}
|
||||
else {
|
||||
/* //pr(compact('tquery')); */
|
||||
/* $total = $model->find('first', $tquery); */
|
||||
/* $params['userdata']['total'] = $total[0]['applied']; */
|
||||
/* $params['userdata']['balance'] = $total[0]['balance']; */
|
||||
/* } */
|
||||
if ($params['action'] === 'collected') {
|
||||
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
|
||||
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
|
||||
$total = $model->find('first', $tquery);
|
||||
@@ -183,6 +209,18 @@ class StatementEntriesController extends AppController {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: waive the ledger entry
|
||||
*/
|
||||
|
||||
function waive($id) {
|
||||
$this->StatementEntry->waive($id);
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -191,74 +229,60 @@ class StatementEntriesController extends AppController {
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
// Get the StatementEntry and related fields
|
||||
$entry = $this->StatementEntry->find
|
||||
('first',
|
||||
array('contain' => array
|
||||
('Transaction' => array('fields' => array('id', 'stamp')),
|
||||
('Transaction' => array('fields' => array('id', 'type', 'stamp')),
|
||||
'Account' => array('id', 'name', 'type'),
|
||||
'Customer' => array('fields' => array('id', 'name')),
|
||||
'Lease' => array('fields' => array('id')),
|
||||
),
|
||||
|
||||
'conditions' => array('StatementEntry.id' => $id),
|
||||
'conditions' => array(array('StatementEntry.id' => $id),
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
array('Account.level >=' => 5)
|
||||
),
|
||||
));
|
||||
|
||||
$reconciled = $this->StatementEntry->reconciledEntries($id);
|
||||
|
||||
|
||||
/* // REVISIT <AP>: 20090711 */
|
||||
/* // It's not clear whether we should be able to reverse charges that have */
|
||||
/* // already been paid/cleared/reconciled. Certainly, that will be the */
|
||||
/* // case when someone has pre-paid and then moves out early. However, this */
|
||||
/* // will work well for items accidentally charged but not yet paid for. */
|
||||
/* if ((!$entry['DebitLedger']['Account']['trackable'] || */
|
||||
/* $stats['debit']['amount_reconciled'] == 0) && */
|
||||
/* (!$entry['CreditLedger']['Account']['trackable'] || */
|
||||
/* $stats['credit']['amount_reconciled'] == 0) */
|
||||
|
||||
/* && 0 */
|
||||
|
||||
/* ) */
|
||||
/* { */
|
||||
/* // Set up dynamic menu items */
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Operations', 'header' => true); */
|
||||
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Undo', */
|
||||
/* 'url' => array('action' => 'reverse', */
|
||||
/* $id)); */
|
||||
/* } */
|
||||
|
||||
/* if ($this->StatementEntry->Ledger->Account->type */
|
||||
/* ($entry['CreditLedger']['Account']['id']) == 'INCOME') */
|
||||
/* { */
|
||||
/* // Set up dynamic menu items */
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Operations', 'header' => true); */
|
||||
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Reverse', */
|
||||
/* 'url' => array('action' => 'reverse', */
|
||||
/* $id)); */
|
||||
/* } */
|
||||
if (empty($entry)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
$stats = $this->StatementEntry->stats($id);
|
||||
|
||||
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE')
|
||||
if (in_array(strtoupper($entry['StatementEntry']['type']), $this->StatementEntry->debitTypes()))
|
||||
$stats = $stats['Charge'];
|
||||
else
|
||||
$stats = $stats['Payment'];
|
||||
$stats = $stats['Disbursement'];
|
||||
|
||||
|
||||
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
|
||||
|
||||
$reversable = $this->StatementEntry->reversable($id);
|
||||
|
||||
// Set up dynamic menu items
|
||||
if ($reversable || $stats['balance'] > 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
|
||||
if ($reversable)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Reverse',
|
||||
'url' => array('action' => 'reverse',
|
||||
$id));
|
||||
|
||||
if ($stats['balance'] > 0)
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Waive Balance',
|
||||
'url' => array('action' => 'waive',
|
||||
$id));
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Statement Entry #{$entry['StatementEntry']['id']}";
|
||||
$this->set(compact('entry', 'title', 'reconciled', 'stats'));
|
||||
$this->set(compact('entry', 'title', 'stats'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -115,15 +115,33 @@ class TendersController extends AppController {
|
||||
*/
|
||||
|
||||
function nsf($id = null) {
|
||||
if ($this->data) {
|
||||
$result = $this->Tender->nsf
|
||||
($this->data['Tender']['id'],
|
||||
$this->data['Transaction']['stamp'],
|
||||
$this->data['Transaction']['comment']);
|
||||
$this->redirect(array('controller' => 'tenders',
|
||||
'action' => 'view',
|
||||
$this->data['Tender']['id']));
|
||||
}
|
||||
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$this->Tender->nsf($id);
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
$this->Tender->id = $id;
|
||||
$tender = $this->Tender->find
|
||||
('first', array
|
||||
('contain' => array('Customer', 'LedgerEntry' => array('Transaction')),
|
||||
));
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']} : NSF";
|
||||
$this->set(compact('tender', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -138,22 +156,31 @@ class TendersController extends AppController {
|
||||
}
|
||||
|
||||
// Get the Tender and related fields
|
||||
$this->Tender->id = $id;
|
||||
$tender = $this->Tender->find
|
||||
('first', array
|
||||
('contain' => array('TenderType', 'Customer', 'LedgerEntry' => array('Transaction')),
|
||||
));
|
||||
|
||||
|
||||
// Set up dynamic menu items
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
|
||||
// Watch out for the special "Closing" entries
|
||||
if (!empty($tender['TenderType']['id']))
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Edit',
|
||||
'url' => array('action' => 'edit',
|
||||
$id));
|
||||
|
||||
if (!empty($tender['Tender']['deposit_transaction_id'])
|
||||
&& empty($tender['Tender']['nsf_transaction_id'])
|
||||
// Hard to tell what types of items can come back as NSF.
|
||||
// For now, assume iff it is a named item, it can be NSF.
|
||||
&& !empty($tender['TenderType']['data1_name'])
|
||||
// (or if we're in development mode)
|
||||
&& (!empty($tender['TenderType']['data1_name']) || !empty($this->params['dev']))
|
||||
) {
|
||||
// Set up dynamic menu items
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'NSF',
|
||||
'url' => array('action' => 'nsf',
|
||||
@@ -161,7 +188,71 @@ class TendersController extends AppController {
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Tender #{$tender['Tender']['id']}";
|
||||
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']}";
|
||||
$this->set(compact('tender', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
* - Edit tender information
|
||||
*/
|
||||
|
||||
function edit($id = null) {
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (empty($this->data['Tender']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->data['Tender']['id']));
|
||||
}
|
||||
|
||||
// Make sure we have tender data
|
||||
if (empty($this->data['Tender']) || empty($this->data['Tender']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
// Figure out which tender type was chosen
|
||||
// REVISIT <AP>: 20090810; Not ready to change tender type
|
||||
// $tender_type_id = $this->data['Tender']['tender_type_id'];
|
||||
$tender_type_id = $this->Tender->field('tender_type_id');
|
||||
if (empty($tender_type_id))
|
||||
$this->redirect(array('action'=>'view', $this->data['Tender']['id']));
|
||||
|
||||
// Get data fields from the selected tender type
|
||||
$this->data['Tender'] += $this->data['type'][$tender_type_id];
|
||||
unset($this->data['type']);
|
||||
|
||||
// Save the tender and all associated data
|
||||
$this->Tender->create();
|
||||
$this->Tender->id = $this->data['Tender']['id'];
|
||||
if (!$this->Tender->save($this->data, false)) {
|
||||
$this->Session->setFlash("TENDER SAVE FAILED", true);
|
||||
pr("TENDER SAVE FAILED");
|
||||
}
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->Tender->id));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->data = $this->Tender->findById($id);
|
||||
} else {
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$tender_types = $this->Tender->TenderType->find
|
||||
('list', array('order' => array('name')));
|
||||
$this->set(compact('tender_types'));
|
||||
|
||||
$types = $this->Tender->TenderType->find('all', array('contain' => false));
|
||||
$this->set(compact('types'));
|
||||
|
||||
// Prepare to render.
|
||||
$title = ('Tender #' . $this->data['Tender']['id'] .
|
||||
' : ' . $this->data['Tender']['name'] .
|
||||
" : Edit");
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,13 @@ class TransactionsController extends AppController {
|
||||
function all() { $this->gridView('All Transactions', 'all'); }
|
||||
function invoice() { $this->gridView('Invoices'); }
|
||||
function receipt() { $this->gridView('Receipts'); }
|
||||
function deposit() { $this->gridView('Deposits'); }
|
||||
function deposit() {
|
||||
$this->sidemenu_links = array
|
||||
(array('name' => 'Operations', 'header' => true),
|
||||
array('name' => 'New Deposit', 'url' => array('controller' => 'tenders',
|
||||
'action' => 'deposit')));
|
||||
$this->gridView('Deposits');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
@@ -48,7 +54,12 @@ class TransactionsController extends AppController {
|
||||
*/
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
return parent::gridDataTables($params, $model);
|
||||
return array
|
||||
('link' =>
|
||||
array(// Models
|
||||
'Account' => array('fields' => array()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
@@ -73,11 +84,16 @@ class TransactionsController extends AppController {
|
||||
if (in_array($params['action'], array('invoice', 'receipt', 'deposit')))
|
||||
$conditions[] = array('Transaction.type' => strtoupper($params['action']));
|
||||
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
$conditions[] = array('Account.level >=' => 5);
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Transaction'] = array('id');
|
||||
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
|
||||
? 'deposit_slip' : 'view'));
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
@@ -114,7 +130,7 @@ class TransactionsController extends AppController {
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postReceipt
|
||||
* - handles the creation of a payment receipt
|
||||
* - handles the creation of a receipt
|
||||
*/
|
||||
|
||||
function postReceipt() {
|
||||
@@ -261,6 +277,105 @@ class TransactionsController extends AppController {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postWriteOff
|
||||
* - handles the write off of bad debt
|
||||
*/
|
||||
|
||||
function postWriteOff() {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->data;
|
||||
if (empty($data['Customer']['id']))
|
||||
$data['Customer']['id'] = null;
|
||||
if (empty($data['Lease']['id']))
|
||||
$data['Lease']['id'] = null;
|
||||
|
||||
pr(compact('data'));
|
||||
|
||||
if (!$this->Transaction->addWriteOff($data,
|
||||
$data['Customer']['id'],
|
||||
$data['Lease']['id'])) {
|
||||
$this->Session->setFlash("WRITE OFF FAILED", true);
|
||||
// REVISIT <AP> 20090706:
|
||||
// Until we can work out the session problems,
|
||||
// just die.
|
||||
die("<H1>WRITE-OFF FAILED</H1>");
|
||||
}
|
||||
|
||||
// Return to viewing the lease/customer
|
||||
if (empty($data['Lease']['id']))
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$data['Customer']['id']));
|
||||
else
|
||||
$this->redirect(array('controller' => 'leases',
|
||||
'action' => 'view',
|
||||
$data['Lease']['id']));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postRefund
|
||||
* - handles issuing a customer refund
|
||||
*/
|
||||
|
||||
function postRefund() {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->data;
|
||||
if (empty($data['Customer']['id']))
|
||||
$data['Customer']['id'] = null;
|
||||
if (empty($data['Lease']['id']))
|
||||
$data['Lease']['id'] = null;
|
||||
|
||||
if (!$this->Transaction->addRefund($data,
|
||||
$data['Customer']['id'],
|
||||
$data['Lease']['id'])) {
|
||||
$this->Session->setFlash("REFUND FAILED", true);
|
||||
// REVISIT <AP> 20090706:
|
||||
// Until we can work out the session problems,
|
||||
// just die.
|
||||
die("<H1>REFUND FAILED</H1>");
|
||||
}
|
||||
|
||||
// Return to viewing the lease/customer
|
||||
if (empty($data['Lease']['id']))
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$data['Customer']['id']));
|
||||
else
|
||||
$this->redirect(array('controller' => 'leases',
|
||||
'action' => 'view',
|
||||
$data['Lease']['id']));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: destroy
|
||||
* - Deletes a transaction and associated entries
|
||||
* - !!WARNING!! This should be used with EXTREME caution, as it
|
||||
* irreversibly destroys the data. It is not for normal use.
|
||||
*/
|
||||
|
||||
function destroy($id = null) {
|
||||
$this->Transaction->destroy($id);
|
||||
//$this->redirect(array('action' => 'index'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -269,33 +384,45 @@ class TransactionsController extends AppController {
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$transaction = $this->Transaction->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
array(// Models
|
||||
'Account' =>
|
||||
array('fields' => array('Account.id',
|
||||
'Account.name'),
|
||||
),
|
||||
|
||||
'Ledger' =>
|
||||
array('fields' => array('Ledger.id',
|
||||
'Ledger.name'),
|
||||
),
|
||||
'Account(id,name)',
|
||||
'Ledger(id,name)',
|
||||
'NsfTender(id,name)',
|
||||
),
|
||||
'conditions' => array('Transaction.id' => $id),
|
||||
'conditions' => array(array('Transaction.id' => $id),
|
||||
// REVISIT <AP>: 20090811
|
||||
// No security issues have been worked out yet
|
||||
array('OR' =>
|
||||
array(array('Account.level >=' => 5),
|
||||
array('Account.id' => null))),
|
||||
),
|
||||
));
|
||||
|
||||
if ($transaction['Transaction']['type'] === 'DEPOSIT') {
|
||||
// REVISIT <AP>: 20090815
|
||||
// for debug purposes only (pr output)
|
||||
$this->Transaction->stats($id);
|
||||
|
||||
if (empty($transaction)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
if ($transaction['Transaction']['type'] === 'DEPOSIT' || $this->params['dev']) {
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'View Slip', 'url' => array('action' => 'deposit_slip', $id));
|
||||
|
||||
if ($transaction['Transaction']['type'] === 'DEPOSIT')
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'View Slip', 'url' => array('action' => 'deposit_slip', $id));
|
||||
if ($this->params['dev'])
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Destroy', 'url' => array('action' => 'destroy', $id),
|
||||
'confirmMessage' => ("This may leave the database in an unstable state." .
|
||||
" Do NOT do this unless you know what you're doing." .
|
||||
" Proceed anyway?"));
|
||||
}
|
||||
|
||||
// OK, prepare to render.
|
||||
@@ -348,15 +475,12 @@ class TransactionsController extends AppController {
|
||||
$type['TenderType'] + $type[0];
|
||||
}
|
||||
|
||||
// For each form of tender in the deposit, get the deposit items
|
||||
/* foreach ($deposit['types'] AS $type_id => &$type) { */
|
||||
/* $type['entries'] = $this->Transaction->DepositTender->find */
|
||||
/* ('all', */
|
||||
/* array('contain' => array('Customer', 'LedgerEntry'), */
|
||||
/* 'conditions' => array(array('DepositTender.deposit_transaction_id' => $id), */
|
||||
/* array('DepositTender.tender_type_id' => $type_id)), */
|
||||
/* )); */
|
||||
/* } */
|
||||
$deposit_total = 0;
|
||||
foreach ($deposit['types'] AS $type)
|
||||
$deposit_total += $type['total'];
|
||||
|
||||
if ($deposit['Transaction']['amount'] != $deposit_total)
|
||||
$this->INTERNAL_ERROR("Deposit items do not add up to deposit slip total");
|
||||
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
|
||||
@@ -82,7 +82,7 @@ class UnitsController extends AppController {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
|
||||
return array_merge($fields,
|
||||
$this->Unit->Lease->StatementEntry->chargePaymentFields(true));
|
||||
$this->Unit->Lease->StatementEntry->chargeDisbursementFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
@@ -236,23 +236,33 @@ class UnitsController extends AppController {
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Edit', 'url' => array('action' => 'edit',
|
||||
$id));
|
||||
|
||||
if (isset($unit['CurrentLease']['id']) &&
|
||||
!isset($unit['CurrentLease']['moveout_date'])) {
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
|
||||
$id));
|
||||
} else {
|
||||
} elseif ($this->Unit->available($unit['Unit']['status'])) {
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Move-In', 'url' => array('action' => 'move_in',
|
||||
$id));
|
||||
} else {
|
||||
// Unit is unavailable (dirty, damaged, reserved, business-use, etc)
|
||||
}
|
||||
|
||||
if (isset($unit['CurrentLease']['id']) &&
|
||||
!isset($unit['CurrentLease']['close_date'])) {
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Payment', 'url' => array('controller' => 'customers',
|
||||
'action' => 'receipt',
|
||||
$unit['CurrentLease']['customer_id']));
|
||||
array('name' => 'New Invoice', 'url' => array('controller' => 'leases',
|
||||
'action' => 'invoice',
|
||||
$unit['CurrentLease']['id']));
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'New Receipt', 'url' => array('controller' => 'customers',
|
||||
'action' => 'receipt',
|
||||
$unit['CurrentLease']['customer_id']));
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
@@ -261,4 +271,66 @@ class UnitsController extends AppController {
|
||||
'outstanding_balance',
|
||||
'outstanding_deposit'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
* - Edit unit information
|
||||
*/
|
||||
|
||||
function edit($id = null) {
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (empty($this->data['Unit']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->data['Unit']['id']));
|
||||
}
|
||||
|
||||
// Make sure we have unit data
|
||||
if (empty($this->data['Unit']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
// Make sure we have a rental rate
|
||||
if (empty($this->data['Unit']['rent']))
|
||||
$this->redirect(array('action'=>'view', $this->data['Unit']['id']));
|
||||
|
||||
// Save the unit and all associated data
|
||||
$this->Unit->create();
|
||||
$this->Unit->id = $this->data['Unit']['id'];
|
||||
if (!$this->Unit->save($this->data, false)) {
|
||||
$this->Session->setFlash("UNIT SAVE FAILED", true);
|
||||
pr("UNIT SAVE FAILED");
|
||||
}
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->Unit->id));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->data = $this->Unit->findById($id);
|
||||
$title = 'Unit ' . $this->data['Unit']['name'] . " : Edit";
|
||||
}
|
||||
else {
|
||||
$title = "Enter New Unit";
|
||||
$this->data = array();
|
||||
}
|
||||
|
||||
$statusEnums = $this->Unit->allowedStatusSet($id);
|
||||
$statusEnums = array_combine(array_keys($statusEnums),
|
||||
array_keys($statusEnums));
|
||||
$this->set(compact('statusEnums'));
|
||||
|
||||
$unit_sizes = $this->Unit->UnitSize->find
|
||||
('list', array('order' => array('unit_type_id', 'width', 'depth', 'id')));
|
||||
$this->set(compact('unit_sizes'));
|
||||
|
||||
// Prepare to render.
|
||||
pr($this->data);
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -128,15 +128,28 @@ class Account extends AppModel {
|
||||
function nsfChargeAccountID() { return $this->nameToID('NSF Charge'); }
|
||||
function taxAccountID() { return $this->nameToID('Tax'); }
|
||||
function accountReceivableAccountID() { return $this->nameToID('A/R'); }
|
||||
function accountPayableAccountID() { return $this->nameToID('A/P'); }
|
||||
function cashAccountID() { return $this->nameToID('Cash'); }
|
||||
function checkAccountID() { return $this->nameToID('Check'); }
|
||||
function moneyOrderAccountID() { return $this->nameToID('Money Order'); }
|
||||
function achAccountID() { return $this->nameToID('ACH'); }
|
||||
function concessionAccountID() { return $this->nameToID('Concession'); }
|
||||
function waiverAccountID() { return $this->nameToID('Waiver'); }
|
||||
function pettyCashAccountID() { return $this->nameToID('Petty Cash'); }
|
||||
function invoiceAccountID() { return $this->nameToID('Invoice'); }
|
||||
function receiptAccountID() { return $this->nameToID('Receipt'); }
|
||||
function badDebtAccountID() { return $this->nameToID('Bad Debt'); }
|
||||
|
||||
function customerCreditAccountID() { return $this->nameToID(
|
||||
// REVISIT <AP>: 20090816
|
||||
// Use of A/R works, and saves an excess of accounts.
|
||||
// However, a dedicated account is nice, since it can
|
||||
// quickly be spotted how much is _really_ due, vs
|
||||
// how much has been pre-paid. Customer credits in
|
||||
// A/R is not as clear, although a report is an
|
||||
// obvious solution.
|
||||
//'A/R'
|
||||
'Credit'
|
||||
); }
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -193,18 +206,22 @@ class Account extends AppModel {
|
||||
* - Returns an array of accounts suitable for activity xxx
|
||||
*/
|
||||
|
||||
function chargeAccounts() {
|
||||
return $this->relatedAccounts('charges', array('order' => 'name'));
|
||||
function invoiceAccounts() {
|
||||
return $this->relatedAccounts('invoices', array('order' => 'name'));
|
||||
}
|
||||
|
||||
function paymentAccounts() {
|
||||
return $this->relatedAccounts('payments', array('order' => 'name'));
|
||||
function receiptAccounts() {
|
||||
return $this->relatedAccounts('receipts', array('order' => 'name'));
|
||||
}
|
||||
|
||||
function depositAccounts() {
|
||||
return $this->relatedAccounts('deposits', array('order' => 'name'));
|
||||
}
|
||||
|
||||
function refundAccounts() {
|
||||
return $this->relatedAccounts('refunds', array('order' => 'name'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -214,14 +231,30 @@ class Account extends AppModel {
|
||||
*/
|
||||
|
||||
function collectableAccounts() {
|
||||
$accounts = $this->paymentAccounts();
|
||||
$accounts = $this->receiptAccounts();
|
||||
|
||||
foreach(array($this->nsfAccountID(),
|
||||
$this->securityDepositAccountID())
|
||||
foreach(array($this->customerCreditAccountID(),
|
||||
$this->securityDepositAccountID(),
|
||||
$this->nsfAccountID(),
|
||||
$this->waiverAccountID(),
|
||||
$this->badDebtAccountID(),
|
||||
//$this->nameToID('Closing'),
|
||||
//$this->nameToID('Equity'),
|
||||
)
|
||||
AS $account_id) {
|
||||
$accounts[$account_id] = $this->name($account_id);
|
||||
}
|
||||
|
||||
$accounts['all'] = $accounts['default'] = $accounts;
|
||||
|
||||
foreach(array($this->concessionAccountID(),
|
||||
$this->waiverAccountID(),
|
||||
$this->badDebtAccountID(),
|
||||
)
|
||||
AS $account_id) {
|
||||
unset($accounts['default'][$account_id]);
|
||||
}
|
||||
|
||||
return $accounts;
|
||||
}
|
||||
|
||||
@@ -337,6 +370,7 @@ class Account extends AppModel {
|
||||
$this->queryInit($query);
|
||||
$query['link'] = array('Account' => $query['link']);
|
||||
|
||||
$stats = array();
|
||||
foreach ($this->ledgers($id, $all) AS $ledger)
|
||||
$this->statsMerge($stats['Ledger'],
|
||||
$this->Ledger->stats($ledger, $query));
|
||||
|
||||
@@ -81,12 +81,7 @@ class Customer extends AppModel {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['Customer']))
|
||||
$query['link']['Customer'] = array();
|
||||
if (!isset($query['link']['Customer']['fields']))
|
||||
$query['link']['Customer']['fields'] = array();
|
||||
|
||||
$query['conditions'][] = array('Customer.id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||
$this->StatementEntry->Account->securityDepositAccountID());
|
||||
|
||||
@@ -106,18 +101,12 @@ class Customer extends AppModel {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['Lease']))
|
||||
$query['link']['Lease'] = array();
|
||||
if (!isset($query['link']['Lease']['fields']))
|
||||
$query['link']['Lease']['fields'] = array();
|
||||
|
||||
$query['conditions'][] = array('Lease.id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||
$this->StatementEntry->Account->securityDepositAccountID());
|
||||
|
||||
$stats = $this->StatementEntry->stats(null, $query);
|
||||
$balance = $stats['Charge']['reconciled'] - $stats['Payment']['reconciled'];
|
||||
return $this->prReturn($balance);
|
||||
return $this->prReturn($stats['account_balance']);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,92 +121,12 @@ class Customer extends AppModel {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['Customer']))
|
||||
$query['link']['Customer'] = array();
|
||||
if (!isset($query['link']['Customer']['fields']))
|
||||
$query['link']['Customer']['fields'] = array();
|
||||
/* if (!isset($query['link']['StatementEntry'])) */
|
||||
/* $query['link']['StatementEntry'] = array(); */
|
||||
/* if (!isset($query['link']['StatementEntry']['Customer'])) */
|
||||
/* $query['link']['StatementEntry']['Customer'] = array(); */
|
||||
/* if (!isset($query['link']['StatementEntry']['Customer']['fields'])) */
|
||||
/* $query['link']['StatementEntry']['Customer']['fields'] = array(); */
|
||||
|
||||
$query['conditions'][] = array('Customer.id' => $id);
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
|
||||
return $this->prReturn($set);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: excessPayments
|
||||
* - Returns payments which have not yet been fully utilized
|
||||
*/
|
||||
|
||||
function excessPayments($id, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['StatementEntry']))
|
||||
$query['link']['StatementEntry'] = array();
|
||||
/* if (!isset($query['link']['StatementEntry']['Customer'])) */
|
||||
/* $query['link']['StatementEntry']['Customer'] = array(); */
|
||||
/* if (!isset($query['link']['StatementEntry']['Customer']['fields'])) */
|
||||
/* $query['link']['StatementEntry']['Customer']['fields'] = array(); */
|
||||
|
||||
$query['conditions'][] = array('Customer.id' => $id);
|
||||
|
||||
$set = $this->StatementEntry->reconciledSet('PAYMENT', $query, true);
|
||||
return $this->prReturn($set);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: details
|
||||
* - Returns detail information for the customer
|
||||
*/
|
||||
|
||||
function details($id = null) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
// Query the DB for need information.
|
||||
$customer = $this->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Contact' =>
|
||||
array('order' => array('Contact.display_name'),
|
||||
// Models
|
||||
'ContactPhone',
|
||||
'ContactEmail',
|
||||
'ContactAddress',
|
||||
),
|
||||
'Lease' =>
|
||||
array('Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
'conditions' => array('Customer.id' => $id),
|
||||
));
|
||||
|
||||
// Figure out the outstanding balance for this customer
|
||||
$customer['stats'] = $this->stats($id);
|
||||
|
||||
// Figure out the total security deposit for the current lease.
|
||||
$customer['deposits'] = $this->securityDeposits($id);
|
||||
|
||||
return $this->prReturn($customer);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -233,10 +142,8 @@ class Customer extends AppModel {
|
||||
continue;
|
||||
|
||||
$I = new Contact();
|
||||
$I->create();
|
||||
if (!$I->save($contact, false)) {
|
||||
if (!$I->saveContact(null, array('Contact' => $contact)))
|
||||
return false;
|
||||
}
|
||||
$contact['id'] = $I->id;
|
||||
}
|
||||
|
||||
@@ -294,6 +201,67 @@ class Customer extends AppModel {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: update
|
||||
* - Update any cached or calculated fields
|
||||
*/
|
||||
function update($id) {
|
||||
|
||||
// REVISIT <AP>: 20090812
|
||||
// updateLeaseCount is handled directly when needed.
|
||||
// Should we simplify by just doing it anyway?
|
||||
//$this->updateLeaseCount($id);
|
||||
|
||||
$current_leases =
|
||||
$this->find('all',
|
||||
array('link' => array('CurrentLease' => array('type' => 'INNER')),
|
||||
'conditions' => array('Customer.id' => $id)));
|
||||
|
||||
foreach ($current_leases AS $lease)
|
||||
$this->Lease->update($lease['CurrentLease']['id']);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: updateLeaseCount
|
||||
* - Updates the internal lease count
|
||||
*/
|
||||
|
||||
function updateLeaseCount($id) {
|
||||
$this->id = $id;
|
||||
|
||||
$lease_count =
|
||||
$this->find('count',
|
||||
array('link' => array('Lease' => array('type' => 'INNER')),
|
||||
'conditions' => array('Customer.id' => $id)));
|
||||
$current_count =
|
||||
$this->find('count',
|
||||
array('link' => array('CurrentLease' => array('type' => 'INNER')),
|
||||
'conditions' => array('Customer.id' => $id)));
|
||||
|
||||
$this->saveField('lease_count', $lease_count);
|
||||
$this->saveField('current_lease_count', $current_count);
|
||||
$this->saveField('past_lease_count', $lease_count - $current_count);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: balance
|
||||
* - Returns the balance of money owed on the lease
|
||||
*/
|
||||
|
||||
function balance($id) {
|
||||
$stats = $this->stats($id);
|
||||
return $stats['balance'];
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -320,14 +288,14 @@ class Customer extends AppModel {
|
||||
/* $stats = $this->StatementEntry->find */
|
||||
/* ('first', array */
|
||||
/* ('contain' => false, */
|
||||
/* 'fields' => $this->StatementEntry->chargePaymentFields(true), */
|
||||
/* 'fields' => $this->StatementEntry->chargeDisbursementFields(true), */
|
||||
/* 'conditions' => array('StatementEntry.customer_id' => $id), */
|
||||
/* )); */
|
||||
|
||||
$find_stats = $this->StatementEntry->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
'fields' => $this->StatementEntry->chargePaymentFields(true),
|
||||
'fields' => $this->StatementEntry->chargeDisbursementFields(true),
|
||||
'conditions' => array('StatementEntry.customer_id' => $id),
|
||||
));
|
||||
$find_stats = $find_stats[0];
|
||||
|
||||
@@ -53,12 +53,27 @@ class DoubleEntry extends AppModel {
|
||||
*/
|
||||
|
||||
function addDoubleEntry($entry1, $entry2, $entry1_tender = null) {
|
||||
/* pr(array('DoubleEntry::addDoubleEntry' => */
|
||||
/* compact('entry1', 'entry2', 'entry1_tender'))); */
|
||||
$this->prFunctionLevel(16);
|
||||
$this->prEnter(compact('entry1', 'entry2', 'entry1_tender'));
|
||||
|
||||
$ret = array();
|
||||
if (!$this->verifyDoubleEntry($entry1, $entry2, $entry1_tender))
|
||||
return array('error' => true) + $ret;
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
// Handle the case where a double entry involves the same
|
||||
// exact ledger. This would not serve any useful purpose.
|
||||
// It is not, however, an error. It is semantically correct
|
||||
// just not really logically correct. To make this easier,
|
||||
// just ensure ledger_id is set for each entry, even though
|
||||
// it would be handled later by the LedgerEntry model.
|
||||
//array($entry1, $entry2) AS &$entry) {
|
||||
for ($i=1; $i <= 2; ++$i) {
|
||||
if (empty(${'entry'.$i}['ledger_id']))
|
||||
${'entry'.$i}['ledger_id'] =
|
||||
$this->DebitEntry->Account->currentLedgerID(${'entry'.$i}['account_id']);
|
||||
}
|
||||
if ($entry1['ledger_id'] == $entry2['ledger_id'])
|
||||
return $this->prReturn(array('error' => false));
|
||||
|
||||
// Since this model only relates to DebitEntry and CreditEntry...
|
||||
$LE = new LedgerEntry();
|
||||
@@ -67,13 +82,13 @@ class DoubleEntry extends AppModel {
|
||||
$result = $LE->addLedgerEntry($entry1, $entry1_tender);
|
||||
$ret['Entry1'] = $result;
|
||||
if ($result['error'])
|
||||
return array('error' => true) + $ret;
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
// Add the second ledger entry to the database
|
||||
$result = $LE->addLedgerEntry($entry2);
|
||||
$ret['Entry2'] = $result;
|
||||
if ($result['error'])
|
||||
return array('error' => true) + $ret;
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
// Now link them as a double entry
|
||||
$double_entry = array();
|
||||
@@ -82,15 +97,13 @@ class DoubleEntry extends AppModel {
|
||||
$double_entry['credit_entry_id'] =
|
||||
($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
|
||||
|
||||
/* pr(array('DoubleEntry::addDoubleEntry' => */
|
||||
/* array('checkpoint' => 'Pre-Save') */
|
||||
/* + compact('double_entry'))); */
|
||||
$ret['data'] = $double_entry;
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($double_entry))
|
||||
return array('error' => true) + $ret;
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
$ret['double_entry_id'] = $this->id;
|
||||
return $ret + array('error' => false);
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ class Lease extends AppModel {
|
||||
'StatementEntry',
|
||||
);
|
||||
|
||||
//var $default_log_level = array('log' => 30, 'show' => 30);
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -23,21 +24,11 @@ class Lease extends AppModel {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['Lease']))
|
||||
$query['link']['Lease'] = array();
|
||||
if (!isset($query['link']['Lease']['fields']))
|
||||
$query['link']['Lease']['fields'] = array();
|
||||
|
||||
$query['conditions'][] = array('Lease.id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||
$this->StatementEntry->Account->securityDepositAccountID());
|
||||
|
||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
||||
|
||||
/* $set['summary'] = array('total' => $set['summary']['Charge']['total'], */
|
||||
/* 'balance' => $set['summary']['Charge']['reconciled'], */
|
||||
/* ); */
|
||||
|
||||
return $this->prReturn($set);
|
||||
}
|
||||
|
||||
@@ -53,18 +44,26 @@ class Lease extends AppModel {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['Lease']))
|
||||
$query['link']['Lease'] = array();
|
||||
if (!isset($query['link']['Lease']['fields']))
|
||||
$query['link']['Lease']['fields'] = array();
|
||||
// REVISIT <AP>: 20090807
|
||||
// Let's try simplifying the security deposit issue.
|
||||
// Presume that security deposits are NOT used at all,
|
||||
// until the customer moves out of the unit. At that
|
||||
// time, the ENTIRE deposit is converted to customer
|
||||
// credit. Piece of cake.
|
||||
// For more information, see file revision history,
|
||||
// including the revision just before this, r503.
|
||||
|
||||
$query['conditions'][] = array('Lease.id' => $id);
|
||||
$this->id = $id;
|
||||
$moveout_date = $this->field('moveout_date');
|
||||
if (!empty($moveout_date))
|
||||
return $this->prReturn(0);
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||
$this->StatementEntry->Account->securityDepositAccountID());
|
||||
|
||||
$stats = $this->StatementEntry->stats(null, $query);
|
||||
$balance = $stats['Charge']['reconciled'] - $stats['Payment']['reconciled'];
|
||||
return $this->prReturn($balance);
|
||||
return $this->prReturn($stats['Charge']['disbursement']);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,21 +72,18 @@ class Lease extends AppModel {
|
||||
**************************************************************************
|
||||
* function: releaseSecurityDeposits
|
||||
* - Releases all security deposits associated with this lease.
|
||||
* That simply makes a payment out of them, which can be used
|
||||
* That simply makes a disbursement out of them, which can be used
|
||||
* to pay outstanding customer charges, or simply to become
|
||||
* a customer surplus (customer credit).
|
||||
*/
|
||||
function releaseSecurityDeposits($id, $query = null) {
|
||||
$this->prFunctionLevel(30);
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
function releaseSecurityDeposits($id, $stamp = null, $query = null) {
|
||||
//$this->prFunctionLevel(30);
|
||||
$this->prEnter(compact('id', 'stamp', 'query'));
|
||||
|
||||
$secdeps = $this->securityDeposits($id, $query);
|
||||
$secdeps = $secdeps['entries'];
|
||||
$this->pr(20, compact('secdeps'));
|
||||
|
||||
$this->securityDepositBalance($id, $query);
|
||||
die();
|
||||
|
||||
// If there are no paid security deposits, then
|
||||
// we can consider all security deposits released.
|
||||
if (count($secdeps) == 0)
|
||||
@@ -95,23 +91,17 @@ class Lease extends AppModel {
|
||||
|
||||
// Build a transaction
|
||||
$release = array('Transaction' => array(), 'Entry' => array());
|
||||
$release['Transaction']['stamp'] = $stamp;
|
||||
$release['Transaction']['comment'] = "Security Deposit Release";
|
||||
foreach ($secdeps AS $charge) {
|
||||
if ($charge['StatementEntry']['type'] !== 'CHARGE')
|
||||
die("INTERNAL ERROR: SECURITY DEPOSIT IS NOT CHARGE");
|
||||
|
||||
// Since security deposits are being released, this also means
|
||||
// we're reducing any oustanding amount on a security deposit
|
||||
// since we no longer expect it to be owed.
|
||||
// REVISIT <AP>: 20090730
|
||||
// This is kludgy, and I really don't like it. However, this
|
||||
// is not presently something that even happens at the moment,
|
||||
// so this solution will have to work until we come up with
|
||||
// something more robust, like flagging those charges as defunct.
|
||||
if ($charge['StatementEntry']['balance'] > 0) {
|
||||
$this->StatementEntry->id = $charge['StatementEntry']['id'];
|
||||
$this->StatementEntry->saveField('amount', $charge['StatementEntry']['reconciled']);
|
||||
}
|
||||
// any unpaid (or only partially paid) security deposit should
|
||||
// have the remaining balance reversed.
|
||||
if ($charge['StatementEntry']['balance'] > 0)
|
||||
$this->StatementEntry->reverse($charge['StatementEntry']['id'], true, $stamp);
|
||||
|
||||
$release['Entry'][] =
|
||||
array('amount' => $charge['StatementEntry']['reconciled'],
|
||||
@@ -121,10 +111,14 @@ class Lease extends AppModel {
|
||||
}
|
||||
|
||||
$customer_id = $secdeps[0]['StatementEntry']['customer_id'];
|
||||
$lease_id = $secdeps[0]['StatementEntry']['lease_id'];
|
||||
$lease_id = $secdeps[0]['StatementEntry']['lease_id'];
|
||||
|
||||
// Add receipt of the security deposit funds. Do NOT
|
||||
// flag them as part of the lease, as all received funds
|
||||
// are only associated with the customer, for future
|
||||
// (or present) disbursement on any lease.
|
||||
$result = $this->StatementEntry->Transaction->addReceipt
|
||||
($release, $customer_id, $lease_id);
|
||||
($release, $customer_id, null);
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
@@ -174,6 +168,35 @@ class Lease extends AppModel {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: lateCharges
|
||||
* - Returns a list of late charges from this lease
|
||||
*/
|
||||
|
||||
function lateCharges($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$late_account_id = $this->StatementEntry->Account->lateChargeAccountID();
|
||||
$entries = $this->StatementEntry->find
|
||||
('all',
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'Lease',
|
||||
),
|
||||
|
||||
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
array('StatementEntry.type' => 'CHARGE'),
|
||||
array('StatementEntry.account_id' => $late_account_id),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
return $this->prReturn($entries);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -273,6 +296,262 @@ class Lease extends AppModel {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyRent
|
||||
* - Charges rent for the month, if not already charged.
|
||||
*/
|
||||
|
||||
function assessMonthlyRent($id, $date = null) {
|
||||
$this->prEnter(compact('id', 'date'));
|
||||
$this->id = $id;
|
||||
|
||||
if (empty($date))
|
||||
$date = time();
|
||||
|
||||
if (is_string($date))
|
||||
$date = strtotime($date);
|
||||
|
||||
// REVISIT <AP>: 20090808
|
||||
// Anniversary Billing not supported
|
||||
$anniversary = 0 && $this->field('anniversary_billing');
|
||||
if (empty($anniversary)) {
|
||||
$date_parts = getdate($date);
|
||||
$date = mktime(0, 0, 0, $date_parts['mon'], 1, $date_parts['year']);
|
||||
}
|
||||
|
||||
// Make sure we're not trying to assess rent on a closed lease
|
||||
$close_date = $this->field('close_date');
|
||||
$this->pr(17, compact('close_date'));
|
||||
if (!empty($close_date))
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Don't assess rent after customer has moved out
|
||||
$moveout_date = $this->field('moveout_date');
|
||||
$this->pr(17, compact('moveout_date'));
|
||||
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine when the customer has already been charged through
|
||||
// and, of course, don't charge them if they've already been.
|
||||
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
||||
$this->pr(17, compact('date', 'charge_through_date')
|
||||
+ array('date_str' => date('Y-m-d', $date),
|
||||
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
|
||||
if ($charge_through_date >= $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// OK, it seems we're going to go ahead and charge the customer
|
||||
// on this lease. Calculate the new charge through date, which
|
||||
// is 1 day shy of 1 month from $date. For example, if we're
|
||||
// charging for 8/1/09, charge through will be 8/31/09, and
|
||||
// charging for 8/15/09, charge through will be 9/14/09.
|
||||
$date_parts = getdate($date);
|
||||
$charge_through_date = mktime(0, 0, 0,
|
||||
$date_parts['mon']+1,
|
||||
$date_parts['mday']-1,
|
||||
$date_parts['year']);
|
||||
|
||||
// Build the invoice transaction
|
||||
$invoice = array('Transaction' => array(), 'Entry' => array());
|
||||
// REVISIT <AP>: 20090808
|
||||
// Keeping Transaction.stamp until the existing facility
|
||||
// is up to date. Then we want the stamp to be now()
|
||||
// (and so can just delete the next line).
|
||||
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
||||
$invoice['Entry'][] =
|
||||
array('effective_date' => date('Y-m-d', $date),
|
||||
'through_date' => date('Y-m-d', $charge_through_date),
|
||||
'amount' => $this->field('rent'),
|
||||
'account_id' => $this->StatementEntry->Account->rentAccountId(),
|
||||
);
|
||||
|
||||
// Record the invoice and return the result
|
||||
$this->pr(21, compact('invoice'));
|
||||
$result = $this->StatementEntry->Transaction->addInvoice
|
||||
($invoice, null, $id);
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyRentAll
|
||||
* - Ensures rent has been charged on all open leases
|
||||
*/
|
||||
|
||||
function assessMonthlyRentAll($date = null) {
|
||||
$this->prEnter(compact('date'));
|
||||
$leases = $this->find
|
||||
('all', array('contain' => false,
|
||||
'conditions' => array('Lease.close_date' => null),
|
||||
));
|
||||
|
||||
$ret = array('Lease' => array());
|
||||
foreach ($leases AS $lease) {
|
||||
$result = $this->assessMonthlyRent($lease['Lease']['id'], $date);
|
||||
$ret['Lease'][$lease['Lease']['id']] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyLate
|
||||
* - Assess late charges for the month, if not already charged.
|
||||
*/
|
||||
|
||||
function assessMonthlyLate($id, $date = null) {
|
||||
$this->prFunctionLevel(25);
|
||||
$this->prEnter(compact('id', 'date'));
|
||||
$this->id = $id;
|
||||
|
||||
if (empty($date))
|
||||
$date = time();
|
||||
|
||||
if (is_string($date))
|
||||
$date = strtotime($date);
|
||||
|
||||
// REVISIT <AP>: 20090808
|
||||
// Anniversary Billing not supported
|
||||
$anniversary = 0 && $this->field('anniversary_billing');
|
||||
if (empty($anniversary)) {
|
||||
$date_parts = getdate($date);
|
||||
$date = mktime(0, 0, 0, $date_parts['mon'], 11, $date_parts['year']);
|
||||
}
|
||||
|
||||
// Don't assess a late charge if the late charge date hasn't
|
||||
// even come yet. This is questionable whether we really
|
||||
// should restrict, since the user could know what they're
|
||||
// doing, and/or the server clock could be off (although that
|
||||
// would certainly have much larger ramifications). But, the
|
||||
// fact is that this check likely handles the vast majority
|
||||
// of the expected behavior, and presents an issue for very
|
||||
// few users, if any at all.
|
||||
if ($date > time())
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Make sure we're not trying to assess late charges on a closed lease
|
||||
$close_date = $this->field('close_date');
|
||||
$this->pr(17, compact('close_date'));
|
||||
if (!empty($close_date))
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Don't assess late charges after customer has moved out
|
||||
$moveout_date = $this->field('moveout_date');
|
||||
$this->pr(17, compact('moveout_date'));
|
||||
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine when the customer has been charged through for rent
|
||||
// and don't mark them as late if they haven't even been charged rent
|
||||
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
||||
$this->pr(17, compact('date', 'charge_through_date')
|
||||
+ array('date_str' => date('Y-m-d', $date),
|
||||
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
|
||||
if ($charge_through_date <= $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine if the customer is actually late. This is based on
|
||||
// when they've paid through, plus 10 days before they're late.
|
||||
// REVISIT <AP>: 20090813
|
||||
// Of course, 10 days is a terrible hardcode. This should be
|
||||
// driven from the late schedule, saved as part of the lease
|
||||
// (when finally implemented).
|
||||
$paid_through_date = strtotime($this->rentPaidThrough($id));
|
||||
$this->pr(17, compact('date', 'paid_through_date')
|
||||
+ array('date_str' => date('Y-m-d', $date),
|
||||
'paid_through_date_str' => date('Y-m-d', $paid_through_date)));
|
||||
$date_parts = getdate($paid_through_date);
|
||||
$paid_through_date = mktime(0, 0, 0, $date_parts['mon'], $date_parts['mday']+10, $date_parts['year']);
|
||||
if ($paid_through_date >= $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine if the customer has already been charged a late fee
|
||||
// and, of course, don't charge them if they've already been.
|
||||
$late_charges = $this->lateCharges($id);
|
||||
foreach ($late_charges AS $late) {
|
||||
if (strtotime($late['StatementEntry']['effective_date']) == $date)
|
||||
return $this->prReturn(null);
|
||||
}
|
||||
|
||||
// Build the invoice transaction
|
||||
$invoice = array('Transaction' => array(), 'Entry' => array());
|
||||
// REVISIT <AP>: 20090808
|
||||
// Keeping Transaction.stamp until the existing facility
|
||||
// is up to date. Then we want the stamp to be now()
|
||||
// (and so can just delete the next line).
|
||||
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
||||
$invoice['Entry'][] =
|
||||
array('effective_date' => date('Y-m-d', $date),
|
||||
'amount' => 10,
|
||||
'account_id' => $this->StatementEntry->Account->lateChargeAccountId(),
|
||||
);
|
||||
|
||||
// Record the invoice and return the result
|
||||
$this->pr(21, compact('invoice'));
|
||||
$result = $this->StatementEntry->Transaction->addInvoice
|
||||
($invoice, null, $id);
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyLateAll
|
||||
* - Ensures rent has been charged on all open leases
|
||||
*/
|
||||
|
||||
function assessMonthlyLateAll($date = null) {
|
||||
$this->prEnter(compact('date'));
|
||||
$leases = $this->find
|
||||
('all', array('contain' => false,
|
||||
'conditions' => array('Lease.close_date' => null),
|
||||
));
|
||||
|
||||
$ret = array('Lease' => array());
|
||||
foreach ($leases AS $lease) {
|
||||
$result = $this->assessMonthlyLate($lease['Lease']['id'], $date);
|
||||
$ret['Lease'][$lease['Lease']['id']] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* functions: delinquency
|
||||
* - SQL fragments to determine whether a lease is delinquent
|
||||
*/
|
||||
|
||||
function conditionDelinquent($table_name = 'Lease') {
|
||||
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
||||
return ("({$t}close_date IS NULL AND" .
|
||||
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 15 DAY))");
|
||||
}
|
||||
|
||||
function delinquentDaysSQL($table_name = 'Lease') {
|
||||
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
||||
return ("IF(" . $this->conditionDelinquent($table_name) . "," .
|
||||
" DATEDIFF(NOW(), {$t}paid_through_date)-1," .
|
||||
" NULL)");
|
||||
}
|
||||
|
||||
function delinquentField($table_name = 'Lease') {
|
||||
return ($this->delinquentDaysSQL($table_name) . " AS 'delinquent'");
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -345,7 +624,10 @@ class Lease extends AppModel {
|
||||
// Set the lease number to be the same as the lease ID
|
||||
$this->id;
|
||||
$this->saveField('number', $this->id);
|
||||
|
||||
|
||||
// Update the current lease count for the customer
|
||||
$this->Customer->updateLeaseCount($customer_id);
|
||||
|
||||
// Update the unit status
|
||||
$this->Unit->updateStatus($unit_id, 'OCCUPIED');
|
||||
|
||||
@@ -368,7 +650,7 @@ class Lease extends AppModel {
|
||||
*/
|
||||
|
||||
function moveOut($id, $status = 'VACANT',
|
||||
$stamp = null, $close = false)
|
||||
$stamp = null, $close = true)
|
||||
{
|
||||
$this->prEnter(compact('id', 'status', 'stamp', 'close'));
|
||||
|
||||
@@ -386,10 +668,16 @@ class Lease extends AppModel {
|
||||
// Save it!
|
||||
$this->save($this->data, false);
|
||||
|
||||
// Release the security deposit(s)
|
||||
$this->releaseSecurityDeposits($id, $stamp);
|
||||
|
||||
// Close the lease, if so requested
|
||||
if ($close)
|
||||
$this->close($id, $stamp);
|
||||
|
||||
// Update the current lease count for the customer
|
||||
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
||||
|
||||
// Finally, update the unit status
|
||||
$this->recursive = -1;
|
||||
$this->read();
|
||||
@@ -423,6 +711,10 @@ class Lease extends AppModel {
|
||||
|
||||
// Save it!
|
||||
$this->save($this->data, false);
|
||||
|
||||
// Update the current lease count for the customer
|
||||
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
@@ -448,12 +740,13 @@ class Lease extends AppModel {
|
||||
if (isset($this->data['Lease']['close_date']))
|
||||
return $this->prReturn(false);
|
||||
|
||||
$deposit_balance = $this->securityDepositBalance($id);
|
||||
$stats = $this->stats($id);
|
||||
|
||||
// A lease can only be closed if there are no outstanding
|
||||
// security deposits, and if the account balance is zero.
|
||||
if ($deposit_balance != 0)
|
||||
// security deposits ...
|
||||
if ($this->securityDepositBalance($id) != 0)
|
||||
return $this->prReturn(false);
|
||||
|
||||
// ... and if the account balance is zero.
|
||||
if ($this->balance($id) != 0)
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Apparently this lease meets all the criteria!
|
||||
@@ -464,12 +757,62 @@ class Lease extends AppModel {
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: addCharge
|
||||
* - Adds an additional charge to the lease
|
||||
* function: refund
|
||||
* - Marks any lease balance as payable to the customer.
|
||||
*/
|
||||
|
||||
function addCharge($id, $charge) {
|
||||
|
||||
function refund($id, $stamp = null) {
|
||||
$this->prEnter(compact('id'));
|
||||
$balance = $this->balance($id);
|
||||
|
||||
if ($balance >= 0)
|
||||
return $this->prReturn(array('error' => true));
|
||||
|
||||
$balance *= -1;
|
||||
|
||||
// Build a transaction
|
||||
$refund = array('Transaction' => array(), 'Entry' => array());
|
||||
$refund['Transaction']['stamp'] = $stamp;
|
||||
$refund['Transaction']['comment'] = "Lease Refund";
|
||||
|
||||
$refund['Entry'][] =
|
||||
array('amount' => $balance);
|
||||
|
||||
$result = $this->StatementEntry->Transaction->addRefund
|
||||
($refund, null, $id);
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: update
|
||||
* - Update any cached or calculated fields
|
||||
*/
|
||||
function update($id) {
|
||||
$this->id = $id;
|
||||
$this->saveField('charge_through_date', $this->rentChargeThrough($id));
|
||||
$this->saveField('paid_through_date', $this->rentPaidThrough($id));
|
||||
|
||||
$moveout = $this->field('moveout_date');
|
||||
if (empty($moveout))
|
||||
$this->Unit->update($this->field('unit_id'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: balance
|
||||
* - Returns the balance of money owed on the lease
|
||||
*/
|
||||
|
||||
function balance($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$stats = $this->stats($id);
|
||||
return $this->prReturn($stats['balance']);
|
||||
}
|
||||
|
||||
|
||||
@@ -485,42 +828,14 @@ class Lease extends AppModel {
|
||||
if (!$id)
|
||||
return $this->prReturn(null);
|
||||
|
||||
$this->queryInit($query);
|
||||
|
||||
//$query['link'] = array('Lease' => $query['link']);
|
||||
/* if (!isset($query['link']['StatementEntry'])) */
|
||||
/* $query['link']['StatementEntry'] = array(); */
|
||||
/* if (!isset($query['link']['StatementEntry']['ChargeEntry'])) */
|
||||
/* $query['link']['StatementEntry']['ChargeEntry'] = array(); */
|
||||
|
||||
/* $query['link']['StatementEntry']['fields'] = array(); */
|
||||
/* $query['link']['ChargeEntry']['fields'] = array(); */
|
||||
/* $query['link']['ChargeEntry']['Account']['fields'] = array(); */
|
||||
/* $query['link']['ChargeEntry']['StatementEntry']['fields'] = array(); */
|
||||
/* $query['link']['ChargeEntry']['StatementEntry']['Invoice']['fields'] = array(); */
|
||||
|
||||
if (!isset($query['fields']))
|
||||
$query['fields'] = array();
|
||||
|
||||
$query['fields'] = array_merge($query['fields'],
|
||||
$this->StatementEntry->chargePaymentFields(true));
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
||||
|
||||
$query['group'] = null;
|
||||
|
||||
$stats = $this->StatementEntry->find('first', $query);
|
||||
//$this->pr(20, compact('query', 'stats'));
|
||||
|
||||
// The fields are all tucked into the [0] index,
|
||||
// and the rest of the array is useless (empty).
|
||||
$stats = $stats[0];
|
||||
|
||||
// Make sure we have a non-null balance
|
||||
if (!isset($stats['balance']))
|
||||
$stats['balance'] = 0;
|
||||
|
||||
return $this->prReturn($stats);
|
||||
$find_stats = $this->StatementEntry->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
'fields' => $this->StatementEntry->chargeDisbursementFields(true),
|
||||
'conditions' => array('StatementEntry.lease_id' => $id),
|
||||
));
|
||||
$find_stats = $find_stats[0];
|
||||
return $this->prReturn($find_stats);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,22 @@ class LedgerEntry extends AppModel {
|
||||
);
|
||||
|
||||
var $hasOne = array(
|
||||
'Tender',
|
||||
'DoubleEntry',
|
||||
'Tender' => array(
|
||||
'dependent' => true,
|
||||
),
|
||||
'DebitDoubleEntry' => array(
|
||||
'className' => 'DoubleEntry',
|
||||
'foreignKey' => 'debit_entry_id',
|
||||
'dependent' => true,
|
||||
),
|
||||
'CreditDoubleEntry' => array(
|
||||
'className' => 'DoubleEntry',
|
||||
'foreignKey' => 'credit_entry_id',
|
||||
'dependent' => true,
|
||||
),
|
||||
'DoubleEntry' => array(
|
||||
'foreignKey' => false,
|
||||
),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
@@ -113,24 +127,20 @@ class LedgerEntry extends AppModel {
|
||||
* - Inserts new Ledger Entry into the database
|
||||
*/
|
||||
function addLedgerEntry($entry, $tender = null) {
|
||||
/* pr(array('LedgerEntry::addLedgerEntry' => */
|
||||
/* compact('entry', 'tender'))); */
|
||||
$this->prFunctionLevel(16);
|
||||
$this->prEnter(compact('entry', 'tender'));
|
||||
|
||||
$ret = array();
|
||||
$ret = array('data' => $entry);
|
||||
if (!$this->verifyLedgerEntry($entry, $tender))
|
||||
return array('error' => true) + $ret;
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
if (empty($entry['ledger_id']))
|
||||
$entry['ledger_id'] =
|
||||
$this->Account->currentLedgerID($entry['account_id']);
|
||||
|
||||
/* pr(array('LedgerEntry::addLedgerEntry' => */
|
||||
/* array('checkpoint' => 'Pre-Save') */
|
||||
/* + compact('entry'))); */
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($entry))
|
||||
return array('error' => true) + $ret;
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
$ret['ledger_entry_id'] = $this->id;
|
||||
|
||||
@@ -140,10 +150,10 @@ class LedgerEntry extends AppModel {
|
||||
$result = $this->Tender->addTender($tender);
|
||||
$ret['Tender'] = $result;
|
||||
if ($result['error'])
|
||||
return array('error' => true) + $ret;
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
}
|
||||
|
||||
return $ret + array('error' => false);
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +180,7 @@ class LedgerEntry extends AppModel {
|
||||
|
||||
//pr(array('stats()', compact('id', 'query', 'set')));
|
||||
|
||||
$rtypes = array('charge', 'payment',
|
||||
$rtypes = array('charge', 'disbursement',
|
||||
// 'debit', 'credit',
|
||||
);
|
||||
|
||||
@@ -178,10 +188,8 @@ class LedgerEntry extends AppModel {
|
||||
foreach($rtypes AS $rtype) {
|
||||
$Rtype = ucfirst($rtype);
|
||||
|
||||
if (($rtype == 'charge' && (!isset($set) || $set == 'PAYMENT')) ||
|
||||
($rtype == 'payment' && (!isset($set) || $set == 'CHARGE'))
|
||||
/* ($rtype == 'debit' && (!isset($set) || $set == 'CREDIT')) || */
|
||||
/* ($rtype == 'credit' && (!isset($set) || $set == 'DEBIT')) */
|
||||
if (($rtype == 'charge' && (!isset($set) || $set == 'DISBURSEMENT')) ||
|
||||
($rtype == 'disbursement' && (!isset($set) || $set == 'CHARGE'))
|
||||
) {
|
||||
|
||||
$rquery = $query;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
class MapsUnit extends AppModel {
|
||||
|
||||
var $name = 'MapsUnit';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'map_id' => array('numeric'),
|
||||
'unit_id' => array('numeric'),
|
||||
'pt_top' => array('numeric'),
|
||||
'pt_left' => array('numeric'),
|
||||
'transpose' => array('boolean')
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -7,46 +7,81 @@ class StatementEntry extends AppModel {
|
||||
'Lease',
|
||||
'Account',
|
||||
|
||||
// The charge to which this payment applies (if it is one)
|
||||
// The charge to which this disbursement applies (if it is one)
|
||||
'ChargeEntry' => array(
|
||||
'className' => 'StatementEntry',
|
||||
),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
// The payments that apply to this charge (if it is one)
|
||||
'PaymentEntry' => array(
|
||||
// The disbursements that apply to this charge (if it is one)
|
||||
'DisbursementEntry' => array(
|
||||
'className' => 'StatementEntry',
|
||||
'foreignKey' => 'charge_entry_id',
|
||||
'dependent' => true,
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
//var $default_log_level = 30;
|
||||
var $default_log_level = array('log' => 30, 'show' => 15);
|
||||
var $max_log_level = 19;
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: chargePaymentFields
|
||||
* function: debit/creditTypes
|
||||
*/
|
||||
|
||||
function debitTypes() {
|
||||
return array('CHARGE', 'PAYMENT', 'REFUND');
|
||||
}
|
||||
|
||||
function creditTypes() {
|
||||
return array('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS');
|
||||
}
|
||||
|
||||
function voidTypes() {
|
||||
return array('VOID');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: chargeDisbursementFields
|
||||
*/
|
||||
|
||||
function chargeDisbursementFields($sum = false, $entry_name = 'StatementEntry') {
|
||||
$debits = $this->debitTypes();
|
||||
$credits = $this->creditTypes();
|
||||
$voids = $this->voidTypes();
|
||||
|
||||
foreach ($debits AS &$enum)
|
||||
$enum = "'" . $enum . "'";
|
||||
foreach ($credits AS &$enum)
|
||||
$enum = "'" . $enum . "'";
|
||||
foreach ($voids AS &$enum)
|
||||
$enum = "'" . $enum . "'";
|
||||
|
||||
$debit_set = implode(", ", $debits);
|
||||
$credit_set = implode(", ", $credits);
|
||||
$void_set = implode(", ", $voids);
|
||||
|
||||
function chargePaymentFields($sum = false, $entry_name = 'StatementEntry') {
|
||||
$fields = array
|
||||
(
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.type = 'CHARGE'," .
|
||||
"IF({$entry_name}.type IN ({$debit_set})," .
|
||||
" {$entry_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''),
|
||||
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.type = 'PAYMENT' OR {$entry_name}.type = 'SURPLUS'," .
|
||||
"IF({$entry_name}.type IN({$credit_set})," .
|
||||
" {$entry_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS payment' . ($sum ? 's' : ''),
|
||||
($sum ? ')' : '') . ' AS disbursement' . ($sum ? 's' : ''),
|
||||
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.type = 'CHARGE', 1," .
|
||||
" IF({$entry_name}.type = 'PAYMENT' OR {$entry_name}.type = 'SURPLUS', -1, 0))" .
|
||||
"IF({$entry_name}.type IN ({$debit_set}), 1," .
|
||||
" IF({$entry_name}.type IN ({$credit_set}), -1, 0))" .
|
||||
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
|
||||
($sum ? ')' : '') . ' AS balance',
|
||||
);
|
||||
@@ -90,16 +125,13 @@ class StatementEntry extends AppModel {
|
||||
function addStatementEntry($entry) {
|
||||
$this->prEnter(compact('entry'));
|
||||
|
||||
$ret = array();
|
||||
$ret = array('data' => $entry);
|
||||
if (!$this->verifyStatementEntry($entry))
|
||||
return array('error' => true, 'verify_data' => $entry) + $ret;
|
||||
|
||||
$this->pr(20, array('checkpoint' => 'Pre-Save')
|
||||
+ compact('entry'));
|
||||
return $this->prReturn(array('error' => true, 'verify_data' => $entry) + $ret);
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($entry))
|
||||
return array('error' => true, 'save_data' => $entry) + $ret;
|
||||
return $this->prReturn(array('error' => true, 'save_data' => $entry) + $ret);
|
||||
|
||||
$ret['statement_entry_id'] = $this->id;
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
@@ -109,115 +141,98 @@ class StatementEntry extends AppModel {
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reverse
|
||||
* - Reverses the charges
|
||||
*
|
||||
* SAMPLE MOVE IN w/ PRE PAYMENT
|
||||
* DEPOSIT RENT A/R RECEIPT CHECK PETTY BANK
|
||||
* ------- ------- ------- ------- ------- ------- -------
|
||||
* |25 | 25| | | | |
|
||||
* | |20 20| | | | |
|
||||
* | |20 20| | | | |
|
||||
* | |20 20| | | | |
|
||||
* | | |25 25| | | |
|
||||
* | | |20 20| | | |
|
||||
* | | |20 20| | | |
|
||||
* | | |20 20| | | |
|
||||
* | | | |85 85| | |
|
||||
* | | | | |85 | 85|
|
||||
|
||||
* MOVE OUT and REFUND FINAL MONTH
|
||||
* DEPOSIT RENT C/P RECEIPT CHECK PETTY BANK
|
||||
* ------- ------- ------- ------- ------- ------- -------
|
||||
* 25| | |25 | | | | t20 e20a
|
||||
* | 20| |20 | | | | t20 e20b
|
||||
|
||||
* -ONE REFUND CHECK-
|
||||
* | | 25| |25 | | | t30 e30a
|
||||
* | | 20| |20 | | | t30 e30b
|
||||
* | | | 45| | | |45 t40 e40
|
||||
* -OR MULTIPLE-
|
||||
* | | 15| |15 | | | t50a e50a
|
||||
* | | | 15| | |15 | t60a e60a
|
||||
* | | 30| |30 | | | t50b e50b
|
||||
* | | | 30| | | |30 t60b e60b
|
||||
* | | | | | | |
|
||||
|
||||
|
||||
OPTION 1
|
||||
* |-25 | -25| | | | |
|
||||
* | |-20 -20| | | | |
|
||||
* | | |-25 -25| | | |
|
||||
* | | |-20 -20| | | |
|
||||
|
||||
OPTION 2
|
||||
* |-25 | | -25| | | |
|
||||
* | |-20 | -20| | | |
|
||||
* | | | |-15 | -15| |
|
||||
* | | | |-30 | | -30|
|
||||
* | | | | | | |
|
||||
* function: waive
|
||||
* - Waives the charge balance
|
||||
*
|
||||
*/
|
||||
function reverse($ledger_entries, $stamp = null) {
|
||||
$this->prEnter(compact('ledger_entries', 'stamp'));
|
||||
function waive($id, $stamp = null) {
|
||||
$this->prEnter(compact('id', 'stamp'));
|
||||
|
||||
// If the user only wants to reverse one ID, we'll allow it
|
||||
if (!is_array($ledger_entries))
|
||||
$ledger_entries = $this->find
|
||||
('all', array
|
||||
('contain' => false,
|
||||
'conditions' => array('Entry.id' => $ledger_entries)));
|
||||
// Get the basic information about the entry to be waived.
|
||||
$this->recursive = -1;
|
||||
$charge = $this->read(null, $id);
|
||||
$charge = $charge['StatementEntry'];
|
||||
|
||||
$A = new Account();
|
||||
if ($charge['type'] !== 'CHARGE')
|
||||
$this->INTERNAL_ERROR("Waiver item is not CHARGE.");
|
||||
|
||||
$ar_account_id = $A->accountReceivableAccountID();
|
||||
$receipt_account_id = $A->receiptAccountID();
|
||||
// Query the stats to get the remaining balance
|
||||
$stats = $this->stats($id);
|
||||
|
||||
$transaction_id = null;
|
||||
foreach ($ledger_entries AS $entry) {
|
||||
$entry = $entry['Entry'];
|
||||
$amount = -1*$entry['amount'];
|
||||
// Build a transaction
|
||||
$waiver = array('Transaction' => array(), 'Entry' => array());
|
||||
$waiver['Transaction']['stamp'] = $stamp;
|
||||
$waiver['Transaction']['comment'] = "Charge Waiver";
|
||||
|
||||
if (isset($entry['credit_account_id']))
|
||||
$refund_account_id = $entry['credit_account_id'];
|
||||
elseif (isset($entry['CreditLedger']['Account']['id']))
|
||||
$refund_account_id = $entry['CreditLedger']['Account']['id'];
|
||||
elseif (isset($entry['credit_ledger_id']))
|
||||
$refund_account_id = $this->Ledger->accountID($entry['credit_ledger_id']);
|
||||
else
|
||||
return $this->prReturn(null);
|
||||
// Add the charge waiver
|
||||
$waiver['Entry'][] =
|
||||
array('amount' => $stats['Charge']['balance'],
|
||||
'comment' => null,
|
||||
);
|
||||
|
||||
// post new refund in the income account
|
||||
$ids = $A->postEntry
|
||||
(array('transaction_id' => $transaction_id),
|
||||
null,
|
||||
array('debit_ledger_id' => $A->currentLedgerID($ar_account_id),
|
||||
'credit_ledger_id' => $A->currentLedgerID($refund_account_id),
|
||||
'effective_date' => $entry['effective_date'],
|
||||
'through_date' => $entry['through_date'],
|
||||
'amount' => $amount,
|
||||
'lease_id' => $entry['lease_id'],
|
||||
'customer_id' => $entry['customer_id'],
|
||||
'comment' => "Refund; Entry #{$entry['id']}",
|
||||
),
|
||||
array('debit' => array
|
||||
(array('Entry' =>
|
||||
array('id' => $entry['id'],
|
||||
'amount' => $amount))),
|
||||
)
|
||||
);
|
||||
// Record the waiver transaction
|
||||
return $this->prReturn($this->Transaction->addWaiver
|
||||
($waiver, $id, $charge['customer_id'], $charge['lease_id']));
|
||||
}
|
||||
|
||||
if ($ids['error'])
|
||||
return $this->prReturn(null);
|
||||
$transaction_id = $ids['transaction_id'];
|
||||
|
||||
$this->pr(15, compact('ids', 'amount', 'refund_account_id', 'ar_account_id'),
|
||||
'Posted Refund Ledger Entry');
|
||||
}
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reversable
|
||||
* - Returns true if the charge can be reversed; false otherwise
|
||||
*/
|
||||
function reversable($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
// Verify the item is an actual charge
|
||||
$this->id = $id;
|
||||
$charge_type = $this->field('type');
|
||||
if ($charge_type !== 'CHARGE')
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Determine anything reconciled against the charge
|
||||
$reverse_transaction_id = $this->field('reverse_transaction_id');
|
||||
if (!empty($reverse_transaction_id))
|
||||
return $this->prReturn(false);
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reverse
|
||||
* - Reverses the charges
|
||||
*/
|
||||
function reverse($id, $stamp = null) {
|
||||
$this->prEnter(compact('id', 'stamp'));
|
||||
|
||||
// Verify the item can be reversed
|
||||
if (!$this->reversable($id))
|
||||
$this->INTERNAL_ERROR("Item is not reversable.");
|
||||
|
||||
// Get the basic information about this charge
|
||||
$charge = $this->find('first', array('contain' => true));
|
||||
//$charge = $charge['StatementEntry'];
|
||||
|
||||
// Query the stats to get the remaining balance
|
||||
$stats = $this->stats($id);
|
||||
$charge['paid'] = $stats['Charge']['disbursement'];
|
||||
|
||||
// Record the reversal transaction
|
||||
$result = $this->Transaction->addReversal
|
||||
($charge, $stamp, 'Charge Reversal');
|
||||
|
||||
if (empty($result['error'])) {
|
||||
// Mark the charge as reversed
|
||||
$this->id = $id;
|
||||
$this->saveField('reverse_transaction_id', $result['transaction_id']);
|
||||
}
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -229,28 +244,21 @@ OPTION 2
|
||||
function reconciledSetQuery($set, $query) {
|
||||
$this->queryInit($query);
|
||||
|
||||
if ($set == 'CHARGE' || $set == 'PAYMENT')
|
||||
$query['conditions'][] = array('StatementEntry.type' => $set);
|
||||
if (in_array($set, $this->debitTypes()))
|
||||
$query['link']['DisbursementEntry'] = array('fields' => array("SUM(DisbursementEntry.amount) AS reconciled"));
|
||||
elseif (in_array($set, $this->creditTypes()))
|
||||
$query['link']['ChargeEntry'] = array('fields' => array("SUM(ChargeEntry.amount) AS reconciled"));
|
||||
else
|
||||
die("INVALID RECONCILE SET");
|
||||
|
||||
if ($set == 'CHARGE')
|
||||
$query['link']['PaymentEntry'] = array('fields' => array("SUM(PaymentEntry.amount) AS reconciled"));
|
||||
if ($set == 'PAYMENT')
|
||||
$query['link']['ChargeEntry'] = array('fields' => array("SUM(ChargeEntry.amount) AS reconciled"));
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.type' => $set);
|
||||
$query['group'] = 'StatementEntry.id';
|
||||
|
||||
// REVISIT: TESTING
|
||||
//$query['link']['PaymentEntry'] = array('fields' => array("(`PaymentEntry.amount`+0) AS reconciled"));
|
||||
//$query['group'] = null;
|
||||
// END REVISIT
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
function reconciledSet($set, $query = null, $unrec = false, $if_rec_include_partial = false) {
|
||||
//$this->prFunctionLevel(16);
|
||||
$this->prFunctionLevel(array('log' => 16, 'show' => 10));
|
||||
$this->prEnter(compact('set', 'query', 'unrec', 'if_rec_include_partial'));
|
||||
$lquery = $this->reconciledSetQuery($set, $query);
|
||||
$result = $this->find('all', $lquery);
|
||||
@@ -274,7 +282,7 @@ OPTION 2
|
||||
$reconciled = true;
|
||||
elseif ($entry['StatementEntry']['reconciled'] == 0)
|
||||
$reconciled = false;
|
||||
else // Partial payment; depends on unrec
|
||||
else // Partial disbursement; depends on unrec
|
||||
$reconciled = (!$unrec && $if_rec_include_partial);
|
||||
|
||||
// Add to the set, if it's been requested
|
||||
@@ -292,7 +300,7 @@ OPTION 2
|
||||
**************************************************************************
|
||||
* function: reconciledEntries
|
||||
* - Returns a list of entries that reconcile against the given entry.
|
||||
* (such as payments towards a charge).
|
||||
* (such as disbursements towards a charge).
|
||||
*/
|
||||
function reconciledEntriesQuery($id, $query = null) {
|
||||
$this->queryInit($query, false);
|
||||
@@ -303,10 +311,14 @@ OPTION 2
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.id' => $id);
|
||||
|
||||
if ($this->data['StatementEntry']['type'] == 'CHARGE')
|
||||
$query['link']['PaymentEntry'] = array();
|
||||
if ($this->data['StatementEntry']['type'] == 'PAYMENT')
|
||||
if (in_array($this->data['StatementEntry']['type'], $this->debitTypes())) {
|
||||
$query['link']['DisbursementEntry'] = array();
|
||||
$query['conditions'][] = array('DisbursementEntry.id !=' => null);
|
||||
}
|
||||
if (in_array($this->data['StatementEntry']['type'], $this->creditTypes())) {
|
||||
$query['link']['ChargeEntry'] = array();
|
||||
$query['conditions'][] = array('ChargeEntry.id !=' => null);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
@@ -331,198 +343,295 @@ OPTION 2
|
||||
*
|
||||
* REVISIT <AP>: 20090726
|
||||
* This algorithm shouldn't be hardcoded. We need to allow
|
||||
* the user to specify how payments should be applied.
|
||||
* the user to specify how disbursements should be applied.
|
||||
*
|
||||
*/
|
||||
function assignCredits($query = null, $receipt_id = null) {
|
||||
function assignCredits($query = null, $receipt_id = null,
|
||||
$charge_ids = null, $disbursement_type = null,
|
||||
$customer_id = null, $lease_id = null)
|
||||
{
|
||||
//$this->prFunctionLevel(25);
|
||||
$this->prEnter( compact('query', 'receipt_id'));
|
||||
$this->prEnter(compact('query', 'receipt_id',
|
||||
'charge_ids', 'disbursement_type',
|
||||
'customer_id', 'lease_id'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!empty($customer_id))
|
||||
$query['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
|
||||
|
||||
if (empty($disbursement_type))
|
||||
$disbursement_type = 'DISBURSEMENT';
|
||||
|
||||
$ret = array();
|
||||
|
||||
// First, find all known credits
|
||||
$lquery = $query;
|
||||
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
|
||||
$lquery['order'][] = 'StatementEntry.effective_date ASC';
|
||||
$credits = $this->find('all', $lquery);
|
||||
$this->pr(18, compact('credits'),
|
||||
"Credits Established");
|
||||
// First, find all known credits, unless this call is to make
|
||||
// credit adjustments to a specific charge
|
||||
if (empty($receipt_id)) {
|
||||
|
||||
if (!empty($charge_ids))
|
||||
$this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt");
|
||||
|
||||
// Next, establish credit from the newly added receipt
|
||||
$receipt_credit = null;
|
||||
if (!empty($receipt_id)) {
|
||||
$lquery = $query;
|
||||
$lquery['link'] += array('LedgerEntry' =>
|
||||
array('conditions' =>
|
||||
//array(LedgerEntry.'crdr'=>'DEBIT'),
|
||||
array('LedgerEntry.account_id !=' => $this->Account->accountReceivableAccountID()),
|
||||
));
|
||||
$lquery['fields'] = array('Transaction.id', 'Transaction.stamp', 'Transaction.amount',
|
||||
'LedgerEntry.account_id');
|
||||
// Very specific case here... no extra conditions
|
||||
unset($lquery['conditions']);
|
||||
$this->Transaction->id = $receipt_id;
|
||||
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
|
||||
// REVISIT <AP>: 20090804
|
||||
// We need to ensure that we're using surplus credits ONLY from either
|
||||
// the given lease, or those that do not apply to any specific lease.
|
||||
// However, by doing this, it forces any lease surplus amounts to
|
||||
// remain frozen with that lease until either there is a lease charge,
|
||||
// we refund the money, or we "promote" that surplus to the customer
|
||||
// level and out of the leases direct control.
|
||||
// That seems like a pain. Perhaps we should allow any customer
|
||||
// surplus to be used on any customer charge.
|
||||
$lquery['conditions'][] =
|
||||
array('OR' =>
|
||||
array(array('StatementEntry.lease_id' => null),
|
||||
(!empty($lease_id)
|
||||
? array('StatementEntry.lease_id' => $lease_id)
|
||||
: array()),
|
||||
));
|
||||
$lquery['order'][] = 'StatementEntry.effective_date ASC';
|
||||
$credits = $this->find('all', $lquery);
|
||||
$this->pr(18, compact('credits'),
|
||||
"Credits Established");
|
||||
}
|
||||
else {
|
||||
// Establish credit from the (newly added) receipt
|
||||
$lquery =
|
||||
array('link' =>
|
||||
array('StatementEntry',
|
||||
'LedgerEntry' =>
|
||||
array('conditions' =>
|
||||
array('LedgerEntry.account_id <> Transaction.account_id')
|
||||
),
|
||||
),
|
||||
'conditions' => array('Transaction.id' => $receipt_id),
|
||||
'fields' => array('Transaction.id', 'Transaction.stamp', 'Transaction.amount'),
|
||||
);
|
||||
$receipt_credit = $this->Transaction->find('first', $lquery);
|
||||
if (!$receipt_credit)
|
||||
die("INTERNAL ERROR: UNABLE TO LOCATE RECEIPT");
|
||||
$this->INTERNAL_ERROR("Unable to locate receipt.");
|
||||
|
||||
$receipt_credit['balance'] = $receipt_credit['Transaction']['amount'];
|
||||
$stats = $this->Transaction->stats($receipt_id);
|
||||
$receipt_credit['balance'] = $stats['undisbursed'];
|
||||
|
||||
$this->pr(18, compact('receipt_credit'),
|
||||
$receipt_credit['receipt'] = true;
|
||||
$credits = array($receipt_credit);
|
||||
$this->pr(18, compact('credits'),
|
||||
"Receipt Credit Added");
|
||||
}
|
||||
|
||||
// Now find all unpaid charges
|
||||
$lquery = $query;
|
||||
if (isset($charge_ids)) {
|
||||
$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);
|
||||
}
|
||||
$lquery['order'] = 'StatementEntry.effective_date ASC';
|
||||
$charges = $this->reconciledSet('CHARGE', $lquery, true);
|
||||
$this->pr(18, compact('charges'),
|
||||
"Outstanding Charges Determined");
|
||||
|
||||
// Initialize our list of used credits
|
||||
$used_credits = array();
|
||||
|
||||
// Work through all unpaid charges, applying payments as we go
|
||||
foreach ($charges['entries'] AS $charge) {
|
||||
$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
|
||||
foreach ($charges AS $charge) {
|
||||
$this->pr(20, compact('charge'),
|
||||
'Process Charge');
|
||||
|
||||
// Check that we have available credits.
|
||||
// Technically, this isn't necessary, since the loop
|
||||
// will handle everything just fine. However, this
|
||||
// just saves extra processing if/when there is no
|
||||
// means to resolve a charge anyway.
|
||||
if (count($credits) == 0 && empty($receipt_credit['balance'])) {
|
||||
$this->pr(15, 'No more available credits');
|
||||
break;
|
||||
}
|
||||
|
||||
$charge['balance'] = $charge['StatementEntry']['balance'];
|
||||
while ($charge['balance'] > 0 &&
|
||||
(count($credits) || !empty($receipt_credit['balance']))) {
|
||||
|
||||
// Use explicit credits before using the new receipt credit
|
||||
foreach ($credits AS &$credit) {
|
||||
if (empty($charge['balance']))
|
||||
break;
|
||||
if ($charge['balance'] < 0)
|
||||
$this->INTERNAL_ERROR("Negative Charge Balance");
|
||||
|
||||
if (!isset($credit['balance']))
|
||||
$credit['balance'] = $credit['StatementEntry']['amount'];
|
||||
|
||||
if (empty($credit['balance']))
|
||||
continue;
|
||||
if ($credit['balance'] < 0)
|
||||
$this->INTERNAL_ERROR("Negative Credit Balance");
|
||||
|
||||
$this->pr(20, compact('charge'),
|
||||
'Attempt Charge Reconciliation');
|
||||
|
||||
// Use explicit credits before using implicit credits
|
||||
// (Not sure it matters though).
|
||||
if (count($credits)) {
|
||||
// Peel off the first credit available
|
||||
$credit =& $credits[0];
|
||||
$payment_date = $credit['StatementEntry']['effective_date'];
|
||||
$payment_transaction_id = $credit['StatementEntry']['transaction_id'];
|
||||
$payment_account_id = $credit['StatementEntry']['account_id'];
|
||||
if (empty($credit['receipt']))
|
||||
$disbursement_account_id = $credit['StatementEntry']['account_id'];
|
||||
else
|
||||
$disbursement_account_id = $credit['LedgerEntry']['account_id'];
|
||||
|
||||
if (!isset($credit['balance']))
|
||||
$credit['balance'] = $credit['StatementEntry']['amount'];
|
||||
}
|
||||
elseif (!empty($receipt_credit['balance'])) {
|
||||
// Use our only receipt credit
|
||||
$credit =& $receipt_credit;
|
||||
$payment_date = $credit['Transaction']['stamp'];
|
||||
$payment_transaction_id = $credit['Transaction']['id'];
|
||||
$payment_account_id = $credit['LedgerEntry']['account_id'];
|
||||
}
|
||||
else {
|
||||
die("HOW DID WE GET HERE WITH NO SURPLUS?");
|
||||
}
|
||||
// REVISIT <AP>: 20090811
|
||||
// Need to come up with a better strategy for handling
|
||||
// concessions. For now, just restricting concessions
|
||||
// to apply only towards rent will resolve the most
|
||||
// predominant (or only) needed usage case.
|
||||
if ($disbursement_account_id == $this->Account->concessionAccountID() &&
|
||||
$charge['StatementEntry']['account_id'] != $this->Account->rentAccountID())
|
||||
continue;
|
||||
|
||||
// Set the payment amount to the maximum amount
|
||||
// Set the disbursement amount to the maximum amount
|
||||
// possible without exceeding the charge or credit balance
|
||||
$payment_amount = min($charge['balance'], $credit['balance']);
|
||||
$disbursement_amount = min($charge['balance'], $credit['balance']);
|
||||
if (!isset($credit['applied']))
|
||||
$credit['applied'] = 0;
|
||||
|
||||
$credit['applied'] += $payment_amount;
|
||||
$credit['balance'] -= $payment_amount;
|
||||
$credit['applied'] += $disbursement_amount;
|
||||
$credit['balance'] -= $disbursement_amount;
|
||||
|
||||
$this->pr(20, compact('credit'),
|
||||
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
|
||||
(count($credits) ? ' Credit' : ' Receipt'));
|
||||
(empty($credit['receipt']) ? ' Credit' : ' Receipt'));
|
||||
|
||||
if ($credit['balance'] < 0)
|
||||
die("HOW DID WE END UP WITH NEGATIVE SURPLUS BALANCE?");
|
||||
if (strtotime($charge['StatementEntry']['effective_date']) >
|
||||
strtotime($credit['StatementEntry']['effective_date']))
|
||||
$disbursement_edate = $charge['StatementEntry']['effective_date'];
|
||||
else
|
||||
$disbursement_edate = $credit['StatementEntry']['effective_date'];
|
||||
|
||||
// If we've exhausted the credit, get it out of the
|
||||
// available credit pool (but keep track of it for later).
|
||||
if ($credit['balance'] <= 0 && count($credits))
|
||||
$used_credits[] = array_shift($credits);
|
||||
if (empty($credit['receipt'])) {
|
||||
// Explicit Credit
|
||||
$result = $this->Transaction->addTransactionEntries
|
||||
(array('include_ledger_entry' => true,
|
||||
'include_statement_entry' => true),
|
||||
array('type' => 'INVOICE',
|
||||
'id' => $credit['StatementEntry']['transaction_id'],
|
||||
'account_id' => $this->Account->accountReceivableAccountID(),
|
||||
'crdr' => 'CREDIT',
|
||||
'customer_id' => $charge['StatementEntry']['customer_id'],
|
||||
'lease_id' => $charge['StatementEntry']['lease_id'],
|
||||
),
|
||||
array
|
||||
(array('type' => $disbursement_type,
|
||||
'effective_date' => $disbursement_edate,
|
||||
'account_id' => $credit['StatementEntry']['account_id'],
|
||||
'amount' => $disbursement_amount,
|
||||
'charge_entry_id' => $charge['StatementEntry']['id'],
|
||||
),
|
||||
));
|
||||
|
||||
// Add a payment that uses the available credit to pay the charge
|
||||
$payment = array('type' => 'PAYMENT',
|
||||
'account_id' => $payment_account_id,
|
||||
'amount' => $payment_amount,
|
||||
'effective_date' => $payment_date,
|
||||
'transaction_id' => $payment_transaction_id,
|
||||
'customer_id' => $charge['StatementEntry']['customer_id'],
|
||||
'lease_id' => $charge['StatementEntry']['lease_id'],
|
||||
'charge_entry_id' => $charge['StatementEntry']['id'],
|
||||
'comment' => null,
|
||||
);
|
||||
$ret['Disbursement'][] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
else {
|
||||
// Receipt Credit
|
||||
|
||||
$this->pr(20, compact('payment'),
|
||||
'New Payment Entry');
|
||||
if (strtotime($charge['StatementEntry']['effective_date']) >
|
||||
strtotime($credit['Transaction']['stamp']))
|
||||
$disbursement_edate = $charge['StatementEntry']['effective_date'];
|
||||
else
|
||||
$disbursement_edate = $credit['Transaction']['stamp'];
|
||||
|
||||
$result = $this->addStatementEntry($payment);
|
||||
$ret['Payment'][] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
// Add a disbursement that uses the available credit to pay the charge
|
||||
$disbursement =
|
||||
array('type' => $disbursement_type,
|
||||
'effective_date' => $disbursement_edate,
|
||||
'amount' => $disbursement_amount,
|
||||
'account_id' => $credit['LedgerEntry']['account_id'],
|
||||
'transaction_id' => $credit['Transaction']['id'],
|
||||
'customer_id' => $charge['StatementEntry']['customer_id'],
|
||||
'lease_id' => $charge['StatementEntry']['lease_id'],
|
||||
'charge_entry_id' => $charge['StatementEntry']['id'],
|
||||
'comment' => null,
|
||||
);
|
||||
|
||||
// Adjust the charge balance to reflect the new payment
|
||||
$charge['balance'] -= $payment_amount;
|
||||
$this->pr(20, compact('disbursement'), 'New Disbursement Entry');
|
||||
$result = $this->addStatementEntry($disbursement);
|
||||
$ret['Disbursement'][] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
|
||||
// Adjust the charge balance to reflect the new disbursement
|
||||
$charge['balance'] -= $disbursement_amount;
|
||||
if ($charge['balance'] < 0)
|
||||
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
|
||||
unset($credit);
|
||||
}
|
||||
|
||||
// Partially used credits must be added to the used list
|
||||
if (isset($credits[0]['applied']))
|
||||
$used_credits[] = array_shift($credits);
|
||||
|
||||
$this->pr(18, compact('credits', 'used_credits', 'receipt_credit'),
|
||||
'Payments added');
|
||||
$this->pr(18, compact('credits'),
|
||||
'Disbursements complete');
|
||||
|
||||
// Clean up any explicit credits that have been used
|
||||
foreach ($used_credits AS $credit) {
|
||||
foreach ($credits AS $credit) {
|
||||
if (!empty($credit['receipt']))
|
||||
continue;
|
||||
|
||||
if (empty($credit['applied']))
|
||||
continue;
|
||||
|
||||
if ($credit['balance'] > 0) {
|
||||
$this->pr(20, compact('credit'),
|
||||
'Update Credit Entry');
|
||||
|
||||
$this->id = $credit['StatementEntry']['id'];
|
||||
$this->id = $credit['StatementEntry']['id'];
|
||||
$this->saveField('amount', $credit['balance']);
|
||||
}
|
||||
else {
|
||||
$this->pr(20, compact('credit'),
|
||||
'Delete Exhausted Credit Entry');
|
||||
|
||||
$this->del($credit['StatementEntry']['id'], false);
|
||||
$this->delete($credit['StatementEntry']['id'], false);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert non-exhausted receipt credit to an explicit one
|
||||
if (!empty($receipt_credit['balance'])) {
|
||||
$credit =& $receipt_credit;
|
||||
// Check for any implicit receipt credits, converting
|
||||
// into explicit credits if there is a remaining balance.
|
||||
foreach ($credits AS $credit) {
|
||||
if (empty($credit['receipt']))
|
||||
continue;
|
||||
|
||||
$this->pr(18, compact('credit'),
|
||||
'Create Explicit Credit');
|
||||
if (empty($credit['balance']))
|
||||
continue;
|
||||
|
||||
$result = $this->addStatementEntry
|
||||
(array('type' => 'SURPLUS',
|
||||
'account_id' => $credit['LedgerEntry']['account_id'],
|
||||
'amount' => $credit['balance'],
|
||||
'effective_date' => $credit['Transaction']['stamp'],
|
||||
'transaction_id' => $credit['Transaction']['id'],
|
||||
'customer_id' => $credit['Customer']['id'],
|
||||
));
|
||||
$ret['Credit'] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
// See if there is an existing explicit credit
|
||||
// for this transaction.
|
||||
$explicit_credit = $this->find
|
||||
('first', array('contain' => false,
|
||||
'conditions' =>
|
||||
array(array('transaction_id' => $credit['Transaction']['id']),
|
||||
array('type' => 'SURPLUS')),
|
||||
));
|
||||
|
||||
if (!empty($explicit_credit)) {
|
||||
// REVISIT <AP>: 20090815
|
||||
// Testing whether or not this case occurs
|
||||
$this->INTERNAL_ERROR('Existing explicit credit unexpected');
|
||||
|
||||
// Since there IS an existing explicit credit, we must update
|
||||
// its balance instead of creating a new one, since it has
|
||||
// already been incorporated in the overall credit balance.
|
||||
// If we were to create a new one, we would erroneously create
|
||||
// an excess of credit available.
|
||||
$this->pr(18, compact('explicit_credit', 'credit'),
|
||||
'Update existing explicit credit');
|
||||
$EC = new StatementEntry();
|
||||
$EC->id = $explicit_credit['StatementEntry']['id'];
|
||||
$EC->saveField('amount', $credit['balance']);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($ret['receipt_balance']))
|
||||
$this->INTERNAL_ERROR('Only one receipt expected in assignCredits');
|
||||
|
||||
// Give caller the information necessary to create an explicit
|
||||
// credit from the passed receipt, which we've not exhausted.
|
||||
$this->pr(18, compact('credit'), 'Convert to explicit credit');
|
||||
$ret['receipt_balance'] = $credit['balance'];
|
||||
}
|
||||
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
@@ -536,6 +645,7 @@ OPTION 2
|
||||
* - Returns summary data from the requested statement entry
|
||||
*/
|
||||
function stats($id = null, $query = null) {
|
||||
$this->prFunctionLevel(array('log' => 16, 'show' => 10));
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
|
||||
$this->queryInit($query);
|
||||
@@ -545,48 +655,68 @@ OPTION 2
|
||||
if (isset($id))
|
||||
$query['conditions'][] = array('StatementEntry.id' => $id);
|
||||
|
||||
$rquery = $query;
|
||||
unset($rquery['link']['ChargeEntry']);
|
||||
$rquery['link']['PaymentEntry'] = array('fields' => array());
|
||||
$types = array('Charge', 'Disbursement');
|
||||
foreach ($types AS $type_index => $this_name) {
|
||||
$that_name = $types[($type_index + 1) % 2];
|
||||
if ($this_name === 'Charge') {
|
||||
$this_types = $this->debitTypes();
|
||||
$that_types = $this->creditTypes();
|
||||
} else {
|
||||
$this_types = $this->creditTypes();
|
||||
$that_types = $this->debitTypes();
|
||||
}
|
||||
|
||||
$rquery['fields'] = array();
|
||||
$rquery['fields'][] = "StatementEntry.amount";
|
||||
$rquery['fields'][] = "SUM(PaymentEntry.amount) AS reconciled";
|
||||
$this_query = $query;
|
||||
$this_query['fields'] = array();
|
||||
$this_query['fields'][] = "SUM(StatementEntry.amount) AS total";
|
||||
$this_query['conditions'][] = array('StatementEntry.type' => $this_types);
|
||||
$result = $this->find('first', $this_query);
|
||||
$stats[$this_name] = $result[0];
|
||||
|
||||
$rquery['conditions'][] = array('StatementEntry.type' => 'CHARGE');
|
||||
$rquery['group'] = 'StatementEntry.id';
|
||||
$this->pr(17, compact('this_query', 'result'), $this_name.'s');
|
||||
|
||||
$result = $this->find('all', $rquery);
|
||||
$stats['Charge'] = array('total' => 0, 'reconciled' => 0);
|
||||
foreach($result AS $charge) {
|
||||
$stats['Charge']['total'] += $charge['StatementEntry']['amount'];
|
||||
$stats['Charge']['reconciled'] += $charge[0]['reconciled'];
|
||||
// Tally the different types that result in credits towards the charges
|
||||
$stats[$this_name]['reconciled'] = 0;
|
||||
foreach ($that_types AS $that_type) {
|
||||
$lc_that_type = strtolower($that_type);
|
||||
$that_query = $this_query;
|
||||
$that_query['link']["{$that_name}Entry"] = array('fields' => array());
|
||||
$that_query['fields'] = array();
|
||||
if ($this_name == 'Charge')
|
||||
$that_query['fields'][] = "COALESCE(SUM(${that_name}Entry.amount),0) AS $lc_that_type";
|
||||
else
|
||||
$that_query['fields'][] = "COALESCE(SUM(StatementEntry.amount), 0) AS $lc_that_type";
|
||||
$that_query['conditions'][] = array("{$that_name}Entry.type" => $that_type);
|
||||
$result = $this->find('first', $that_query);
|
||||
$stats[$this_name] += $result[0];
|
||||
|
||||
$this->pr(17, compact('that_query', 'result'), "{$this_name}s: $that_type");
|
||||
$stats[$this_name]['reconciled'] += $stats[$this_name][$lc_that_type];
|
||||
}
|
||||
|
||||
// Compute balance information for charges
|
||||
$stats[$this_name]['balance'] =
|
||||
$stats[$this_name]['total'] - $stats[$this_name]['reconciled'];
|
||||
if (!isset($stats[$this_name]['balance']))
|
||||
$stats[$this_name]['balance'] = 0;
|
||||
}
|
||||
$stats['Charge']['balance'] =
|
||||
$stats['Charge']['total'] - $stats['Charge']['reconciled'];
|
||||
|
||||
$this->pr(17, compact('query', 'result'),
|
||||
'Charges');
|
||||
|
||||
$rquery = $query;
|
||||
unset($rquery['link']['PaymentEntry']);
|
||||
$rquery['link']['ChargeEntry'] = array('fields' => array());
|
||||
// 'balance' is simply the difference between
|
||||
// the balances of charges and disbursements
|
||||
$stats['balance'] = $stats['Charge']['balance'] - $stats['Disbursement']['balance'];
|
||||
if (!isset($stats['balance']))
|
||||
$stats['balance'] = 0;
|
||||
|
||||
$rquery['fields'] = array();
|
||||
$rquery['fields'][] = "SUM(StatementEntry.amount) AS total";
|
||||
$rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, 0, StatementEntry.amount)) AS reconciled";
|
||||
$rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, StatementEntry.amount, 0)) AS balance";
|
||||
|
||||
$rquery['conditions'][] = array('StatementEntry.type' => 'PAYMENT');
|
||||
$result = $this->find('first', $rquery);
|
||||
if (!isset($result[0]['balance']))
|
||||
$result[0]['balance'] = 0;
|
||||
$stats['Payment'] = $result[0];
|
||||
|
||||
$this->pr(17, compact('rquery', 'result'),
|
||||
'Payments');
|
||||
// 'account_balance' is really only relevant to
|
||||
// callers that have requested charge and disbursement
|
||||
// stats with respect to a particular account.
|
||||
// It represents the difference between inflow
|
||||
// and outflow from that account.
|
||||
$stats['account_balance'] = $stats['Charge']['reconciled'] - $stats['Disbursement']['total'];
|
||||
if (!isset($stats['account_balance']))
|
||||
$stats['account_balance'] = 0;
|
||||
|
||||
return $this->prReturn($stats);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,68 @@ class Tender extends AppModel {
|
||||
),
|
||||
'NsfTransaction' => array(
|
||||
'className' => 'Transaction',
|
||||
'dependent' => true,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: afterSave
|
||||
* - Performs any work needed after the save occurs
|
||||
*/
|
||||
|
||||
function afterSave($created) {
|
||||
// Come up with a (not necessarily unique) name for the tender.
|
||||
// For checks & money orders, this will be based on the check
|
||||
// number. For other types of tender, we'll just use the
|
||||
// generic name of the tender type, and the tender ID
|
||||
|
||||
// Determine our tender type, and set the ID of that model
|
||||
$this->TenderType->id = $this->field('tender_type_id');
|
||||
|
||||
// REVISIT <AP>: 20090810
|
||||
// The only tender expected to have no tender type
|
||||
// is our special "Closing" tender.
|
||||
if (empty($this->TenderType->id))
|
||||
$newname = 'Closing';
|
||||
else {
|
||||
$newname = $this->TenderType->field('name');
|
||||
$naming_field = $this->TenderType->field('naming_field');
|
||||
if (!empty($naming_field))
|
||||
$newname .= ' #' . $this->field($naming_field);
|
||||
}
|
||||
|
||||
if ($newname !== $this->field('name'))
|
||||
$this->saveField('name', $newname);
|
||||
|
||||
return parent::afterSave($created);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: beforeDelete
|
||||
* - Performs any work needed before the delete occurs
|
||||
*/
|
||||
|
||||
function beforeDelete($cascade = true) {
|
||||
// REVISIT <AP>: 20090814
|
||||
// Experimental, and incomplete mechanism to protect
|
||||
// against trying to delete data that shouldn't be deleted.
|
||||
|
||||
$deposit_id = $this->field('deposit_transaction_id');
|
||||
pr(compact('deposit_id'));
|
||||
// If this tender has already been deposited, it would
|
||||
// be a rats nest to figure out how to delete this tender.
|
||||
if (!empty($deposit_id))
|
||||
return false;
|
||||
|
||||
return parent::beforeDelete($cascade);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -43,29 +101,10 @@ class Tender extends AppModel {
|
||||
function addTender($tender) {
|
||||
$this->prEnter(compact('tender'));
|
||||
|
||||
$ret = array();
|
||||
$ret = array('data' => $tender);
|
||||
if (!$this->verifyTender($tender))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
// Come up with a (not necessarily unique) name for the tender.
|
||||
// For checks & money orders, this will be based on the check
|
||||
// number. For other types of tender, we'll just use the
|
||||
// generic name of the monetary account.
|
||||
// REVISIT <AP>: 20090723
|
||||
// I would like to have cash named "Cash #1234", where
|
||||
// the number would correspond to either the Tender ID
|
||||
// or the LedgerEntry ID.
|
||||
if (empty($tender['name']) && !empty($tender['account_id'])) {
|
||||
$tender['name'] = $this->LedgerEntry->Account->name($tender['account_id']);
|
||||
if ($tender['account_id'] == $this->LedgerEntry->Account->checkAccountID() ||
|
||||
$tender['account_id'] == $this->LedgerEntry->Account->moneyOrderAccountID()) {
|
||||
$tender['name'] .= ' #' . $tender['data1'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->pr(20, array('Tender' => $tender),
|
||||
'Pre-Save');
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($tender))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
@@ -80,31 +119,10 @@ class Tender extends AppModel {
|
||||
**************************************************************************
|
||||
* function: nsf
|
||||
* - Flags the ledger entry as having insufficient funds
|
||||
*
|
||||
* Steps:
|
||||
* - Get information from Check (C1); for amount $A
|
||||
* - Find Bank Deposit matching to Tender
|
||||
* - New Transaction (T1)
|
||||
* - New Bank Deposit (D1)
|
||||
* - New Tender (N1); NSF; D1,
|
||||
* - Add new LedgerEntry (L1a); T1; debit:bank; -$A
|
||||
* - Add new LedgerEntry (L1b); T1; credit:NSF; -$A
|
||||
* - Add new LedgerEntry (L2a); T1; debit:NSF; -$A; N1
|
||||
* - Add new LedgerEntry (L2b); T1; credit:A/R; -$A
|
||||
* - For Tx associated with LE associated with C1:
|
||||
* - For each Payment SE of Tx:
|
||||
* - Add new StatementEntry (S1n); T1; PAYMENT; -1*S1n.amount
|
||||
* - New Transaction (T2) (?????)
|
||||
* - Add new StatementEntry (S2); T2; CHARGE; NSF; $35
|
||||
* - Add new LedgerEntry (L3a); T2; credit:NSF-Fee; $35
|
||||
* - Add new LedgerEntry (L3b); T2; debit:A/R; $35
|
||||
* - Set C1.nsf_tx = T1
|
||||
* - Re-Reconcile (customer may have running credit)
|
||||
*/
|
||||
|
||||
function nsf($id, $stamp = null) {
|
||||
$this->prFunctionLevel(30);
|
||||
$this->prEnter(compact('id'));
|
||||
function nsf($id, $stamp = null, $comment = null) {
|
||||
$this->prEnter(compact('id', 'stamp', 'comment'));
|
||||
|
||||
// Get information about this NSF item.
|
||||
$this->id = $id;
|
||||
@@ -128,16 +146,15 @@ class Tender extends AppModel {
|
||||
unset($tender['NsfTransaction']);
|
||||
|
||||
$T = new Transaction();
|
||||
$result = $T->addNsf($tender, $stamp);
|
||||
if ($result['error'])
|
||||
return $this->prReturn(false);
|
||||
$result = $T->addNsf($tender, $stamp, $comment);
|
||||
if (empty($result['error'])) {
|
||||
// Flag the tender as NSF, using the items created from addNsf
|
||||
$this->id = $id;
|
||||
$this->saveField('nsf_transaction_id', $result['nsf_transaction_id']);
|
||||
$this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']);
|
||||
}
|
||||
|
||||
// Flag the tender as NSF, using the items created from addNsf
|
||||
$this->id = $id;
|
||||
$this->saveField('nsf_transaction_id', $result['nsf_transaction_id']);
|
||||
$this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']);
|
||||
|
||||
return $this->prReturn(true);
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -112,4 +112,4 @@ class TenderType extends AppModel {
|
||||
return $stats[0];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,8 @@ class Unit extends AppModel {
|
||||
'Lease',
|
||||
);
|
||||
|
||||
//var $default_log_level = array('log' => 30, 'show' => 15);
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -50,13 +52,53 @@ class Unit extends AppModel {
|
||||
}
|
||||
|
||||
function occupiedEnumValue() {
|
||||
return statusValue('OCCUPIED');
|
||||
return $this->statusValue('OCCUPIED');
|
||||
}
|
||||
|
||||
function statusCheck($id_or_enum,
|
||||
$min = null, $min_strict = false,
|
||||
$max = null, $max_strict = false)
|
||||
{
|
||||
$this->prEnter(compact('id_or_enum', 'min', 'min_strict', 'max', 'max_strict'));
|
||||
|
||||
if (is_int($id_or_enum)) {
|
||||
$this->id = $id_or_enum;
|
||||
$id_or_enum = $this->field('status');
|
||||
}
|
||||
|
||||
$enum_val = $this->statusValue($id_or_enum);
|
||||
if (isset($min) && is_string($min))
|
||||
$min = $this->statusValue($min);
|
||||
if (isset($max) && is_string($max))
|
||||
$max = $this->statusValue($max);
|
||||
|
||||
$this->pr(17, compact('enum_val', 'min', 'min_strict', 'max', 'max_strict'));
|
||||
|
||||
if (isset($min) &&
|
||||
($enum_val < $min ||
|
||||
($min_strict && $enum_val == $min)))
|
||||
return $this->prReturn(false);
|
||||
|
||||
if (isset($max) &&
|
||||
($enum_val > $max ||
|
||||
($max_strict && $enum_val == $max)))
|
||||
return $this->prReturn(false);
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
function occupied($enum) {
|
||||
return $this->statusCheck($enum, 'OCCUPIED', false, null, false);
|
||||
}
|
||||
|
||||
function conditionOccupied() {
|
||||
return ('Unit.status >= ' . $this->statusValue('OCCUPIED'));
|
||||
}
|
||||
|
||||
function vacant($enum) {
|
||||
return $this->statusCheck($enum, 'UNAVAILABLE', true, 'OCCUPIED', true);
|
||||
}
|
||||
|
||||
function conditionVacant() {
|
||||
return ('Unit.status BETWEEN ' .
|
||||
($this->statusValue('UNAVAILABLE')+1) .
|
||||
@@ -64,22 +106,91 @@ class Unit extends AppModel {
|
||||
($this->statusValue('OCCUPIED')-1));
|
||||
}
|
||||
|
||||
function unavailable($enum) {
|
||||
return $this->statusCheck($enum, null, false, 'UNAVAILABLE', false);
|
||||
}
|
||||
|
||||
function conditionUnavailable() {
|
||||
return ('Unit.status <= ' . $this->statusValue('UNAVAILABLE'));
|
||||
}
|
||||
|
||||
function available($enum) { return $this->vacant($enum); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: allowedStatusSet
|
||||
* - Returns the status set allowed for the given unit
|
||||
*/
|
||||
function allowedStatusSet($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$this->id = $id;
|
||||
$old_status = $this->field('status');
|
||||
$old_val = $this->statusValue($old_status);
|
||||
$this->pr(17, compact('old_status', 'old_val'));
|
||||
|
||||
$enums = $this->activeStatusEnums();
|
||||
$this->pr(21, compact('enums'));
|
||||
|
||||
foreach ($enums AS $enum => $val) {
|
||||
if (($old_val < $this->occupiedEnumValue()) !=
|
||||
($val < $this->occupiedEnumValue())) {
|
||||
unset($enums[$enum]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->prReturn($enums);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: updateStatus
|
||||
* - Update the given unit to the given status
|
||||
*/
|
||||
function updateStatus($id, $status) {
|
||||
function updateStatus($id, $status, $check = false) {
|
||||
$this->prEnter(compact('id', 'status', 'check'));
|
||||
|
||||
/* if ($check) { */
|
||||
/* $old_status = $this->field('status'); */
|
||||
/* $this->pr(17, compact('old_status')); */
|
||||
/* if ($this->statusValue($old_status) < $this->occupiedEnumValue() && */
|
||||
/* $this->statusValue($status) >= $this->occupiedEnumValue()) */
|
||||
/* { */
|
||||
/* die("Can't transition a unit from vacant to occupied"); */
|
||||
/* return $this->prReturn(false); */
|
||||
/* } */
|
||||
/* if ($this->statusValue($old_status) >= $this->occupiedEnumValue() && */
|
||||
/* $this->statusValue($status) < $this->occupiedEnumValue()) */
|
||||
/* { */
|
||||
/* die("Can't transition a unit from occupied to vacant"); */
|
||||
/* return $this->prReturn(false); */
|
||||
/* } */
|
||||
/* } */
|
||||
|
||||
if ($check) {
|
||||
if (!array_key_exists($status, $this->allowedStatusSet($id)))
|
||||
return $this->prReturn(false);
|
||||
}
|
||||
|
||||
$this->id = $id;
|
||||
//pr(compact('id', 'status'));
|
||||
$this->saveField('status', $status);
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: update
|
||||
* - Update any cached or calculated fields
|
||||
*/
|
||||
function update($id) {
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
|
||||
@@ -15,7 +15,8 @@ echo '<div class="account collected">' . "\n";
|
||||
|
||||
// Reset the form
|
||||
function resetForm() {
|
||||
/* updateEntriesGrid(); */
|
||||
// Kick off the grid
|
||||
updateEntriesGrid();
|
||||
}
|
||||
|
||||
function onGridLoadComplete() {
|
||||
@@ -39,12 +40,15 @@ function updateEntriesGrid() {
|
||||
|
||||
$('#collected-total').html('Calculating...');
|
||||
$('#collected-entries-jqGrid').clearGridData();
|
||||
$('#collected-entries-jqGrid').setPostDataItem('dynamic_post', serialize(dynamic_post));
|
||||
$('#collected-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
|
||||
$('#collected-entries-jqGrid')
|
||||
.setGridParam({ page: 1 })
|
||||
.trigger("reloadGrid");
|
||||
|
||||
//$('#collected-entries .HeaderButton').click();
|
||||
//$('#debug').html("<PRE>\n"+htmlEncode(dump($('#collected-entries-jqGrid').getGridParam()))+"\n</PRE>")
|
||||
var gridstate = $('#collected-entries-jqGrid').getGridParam('gridstate');
|
||||
if (gridstate == 'hidden')
|
||||
$('#collected-entries .HeaderButton').click();
|
||||
}
|
||||
|
||||
|
||||
@@ -161,12 +165,12 @@ echo $this->element('statement_entries', array
|
||||
'grid_div_id' => 'collected-entries',
|
||||
'grid_div_class' => 'text-below',
|
||||
'grid_events' => array('loadComplete' => 'onGridLoadComplete()'),
|
||||
//'grid_setup' => array('hiddengrid' => true),
|
||||
//'caption' => '<SPAN id="receipt-charges-caption"></SPAN>',
|
||||
'grid_setup' => array('hiddengrid' => true),
|
||||
'caption' => 'Collected ' . Inflector::pluralize($account['name']),
|
||||
'filter' => array('StatementEntry.type' => 'PAYMENT',
|
||||
'ChargeEntry.account_id' => $account['id']),
|
||||
'exclude' => array('Account', 'Charge'),
|
||||
'action' => 'collected',
|
||||
'filter' => array('ChargeEntry.account_id' => $account['id']),
|
||||
'include' => array('Amount'),
|
||||
'exclude' => array(/*'Type',*/ 'Debit', 'Credit'),
|
||||
),
|
||||
));
|
||||
|
||||
@@ -201,5 +205,3 @@ echo '</div>' . "\n";
|
||||
echo '</div>' . "\n";
|
||||
|
||||
?>
|
||||
|
||||
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>
|
||||
|
||||
@@ -82,7 +82,7 @@ echo $this->element('ledger_entries', array
|
||||
"(". $current_ledger['name'] .")"),
|
||||
'filter' => array('Ledger.id' => $current_ledger['id']),
|
||||
'exclude' => array('Account', 'Amount', 'Cr/Dr', 'Balance',
|
||||
empty($account['payments']) ? 'Tender' : null),
|
||||
empty($account['receipts']) ? 'Tender' : null),
|
||||
'include' => array('Debit', 'Credit', 'Sub-Total'),
|
||||
)));
|
||||
|
||||
@@ -100,7 +100,7 @@ echo $this->element('ledger_entries', array
|
||||
'caption' => "Entire Ledger",
|
||||
'filter' => array('Account.id' => $account['id']),
|
||||
'exclude' => array('Account', 'Amount', 'Cr/Dr', 'Balance',
|
||||
empty($account['payments']) ? 'Tender' : null),
|
||||
empty($account['receipts']) ? 'Tender' : null),
|
||||
'include' => array('Debit', 'Credit', 'Sub-Total'),
|
||||
)));
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ echo($this->element
|
||||
'comment' => true,
|
||||
))) . "\n");
|
||||
|
||||
echo $form->submit('Update') . "\n";
|
||||
echo $form->submit(isset($this->data['Customer']) ? 'Update' : 'Add New Customer') . "\n";
|
||||
?>
|
||||
|
||||
<div CLASS="dynamic-set">
|
||||
@@ -268,7 +268,7 @@ echo $form->submit('Update') . "\n";
|
||||
<?php
|
||||
; // Alignment
|
||||
|
||||
echo $form->submit('Update') . "\n";
|
||||
echo $form->submit(isset($this->data['Customer']) ? 'Update' : 'Add New Customer') . "\n";
|
||||
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
|
||||
echo $form->end() . "\n";
|
||||
echo '</div>' . "\n";
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
* Javascript
|
||||
*/
|
||||
|
||||
// Warnings _really_ screw up javascript
|
||||
$saved_debug_state = Configure::read('debug');
|
||||
Configure::write('debug', '0');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
@@ -23,14 +26,8 @@
|
||||
success: showResponse, // post-submit callback
|
||||
|
||||
// other available options:
|
||||
//url: url, // override for form's 'action' attribute
|
||||
//type: 'get', // 'get' or 'post', override for form's 'method' attribute
|
||||
//dataType: null, // 'xml', 'script', or 'json' (expected server response type)
|
||||
//clearForm: true, // clear all form fields after successful submit
|
||||
//resetForm: true, // reset the form after successful submit
|
||||
|
||||
// $.ajax options can be used here too, for example:
|
||||
//timeout: 3000,
|
||||
};
|
||||
|
||||
// bind form using 'ajaxForm'
|
||||
@@ -39,16 +36,7 @@
|
||||
|
||||
// pre-submit callback
|
||||
function verifyRequest(formData, jqForm, options) {
|
||||
// formData is an array; here we use $.param to convert it to a string to display it
|
||||
// but the form plugin does this for you automatically when it submits the data
|
||||
//var_dump(formData);
|
||||
//$('#request-debug').html('<PRE>'+dump(formData)+'</PRE>');
|
||||
$('#request-debug').html('Ommitted');
|
||||
//return false;
|
||||
|
||||
$('#response-debug').html('Loading <BLINK>...</BLINK>');
|
||||
$('#output-debug').html('Loading <BLINK>...</BLINK>');
|
||||
|
||||
$('#results').html('Working <BLINK>...</BLINK>');
|
||||
// here we could return false to prevent the form from being submitted;
|
||||
// returning anything other than false will allow the form submit to continue
|
||||
return true;
|
||||
@@ -56,27 +44,32 @@ function verifyRequest(formData, jqForm, options) {
|
||||
|
||||
// post-submit callback
|
||||
function showResponse(responseText, statusText) {
|
||||
// for normal html responses, the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseText property
|
||||
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'xml' then the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseXML property
|
||||
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'json' then the first argument to the success callback
|
||||
// is the json data object returned by the server
|
||||
|
||||
if (statusText == 'success') {
|
||||
var amount = 0;
|
||||
$("input.payment.amount").each(function(i) {
|
||||
amount += $(this).val();
|
||||
});
|
||||
|
||||
$('#results').html('<H3>Receipt Saved<BR>' +
|
||||
$("#receipt-customer-name").html() +
|
||||
' : ' + fmtCurrency(amount) +
|
||||
'</H3>');
|
||||
|
||||
if (!$("#repeat").attr("checked")) {
|
||||
window.location.href =
|
||||
"<?php echo $html->url(array('controller' => 'customers',
|
||||
'action' => 'view')); ?>"
|
||||
+ "/" + $("#customer-id").val();
|
||||
return;
|
||||
}
|
||||
|
||||
// get a clean slate
|
||||
//resetForm();
|
||||
resetForm();
|
||||
}
|
||||
else {
|
||||
alert('not successful??');
|
||||
$('#results').html('<H2>Failed to save receipt!</H2>');
|
||||
alert('Failed to save receipt.');
|
||||
}
|
||||
|
||||
|
||||
$('#response-debug').html('<PRE>'+dump(statusText)+'</PRE>');
|
||||
}
|
||||
|
||||
// Reset the form
|
||||
@@ -84,13 +77,35 @@ function resetForm() {
|
||||
$('#payment-entry-id').val(1);
|
||||
$('#payments').html('');
|
||||
|
||||
$("#receipt-customer-id").html("INTERNAL ERROR");
|
||||
$("#receipt-customer-name").html("INTERNAL ERROR");
|
||||
$("#receipt-balance").html("INTERNAL ERROR");
|
||||
$("#receipt-charges-caption").html("Outstanding Charges");
|
||||
|
||||
addPaymentSource(false);
|
||||
datepickerNow('TransactionStamp');
|
||||
updateCharges($("#customer-id").val());
|
||||
}
|
||||
|
||||
function updateCharges(id) {
|
||||
$('#charge-entries-jqGrid').clearGridData();
|
||||
$("#receipt-balance").html("Calculating...");
|
||||
$("#receipt-charges-caption").html("Please Wait...");
|
||||
|
||||
var custom = new Array();
|
||||
custom['customer_id'] = id;
|
||||
|
||||
var dynamic_post = new Array();
|
||||
dynamic_post['custom'] = custom;
|
||||
|
||||
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
|
||||
$('#charge-entries-jqGrid')
|
||||
.setGridParam({ page: 1 })
|
||||
.trigger("reloadGrid");
|
||||
|
||||
var gridstate = $('#charge-entries-jqGrid').getGridParam('gridstate');
|
||||
if (gridstate == 'hidden')
|
||||
$('#charge-entries .HeaderButton').click();
|
||||
}
|
||||
|
||||
function onGridLoadComplete() {
|
||||
var userdata = $('#charge-entries-jqGrid').getGridParam('userData');
|
||||
$('#receipt-balance').html(fmtCurrency(userdata['balance']));
|
||||
$("#receipt-charges-caption").html("Outstanding Charges");
|
||||
}
|
||||
|
||||
function onRowSelect(grid_id, customer_id) {
|
||||
@@ -103,14 +118,15 @@ function onRowSelect(grid_id, customer_id) {
|
||||
// This is not intended as a long term solution,
|
||||
// but I need a way to enter data and then view
|
||||
// the results. This link will help.
|
||||
$("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
|
||||
$("#receipt-customer-id").html('<A HREF="' +
|
||||
"<?php echo $html->url(array('controller' => 'customers',
|
||||
'action' => 'view')); ?>"
|
||||
+ "/" +
|
||||
$(grid_id).getCell(customer_id, 'Customer-id').replace(/^#/,'') +
|
||||
'">' +
|
||||
$(grid_id).getCell(customer_id, 'Customer-id') +
|
||||
'</A>');
|
||||
$("#receipt-customer-name").html($(grid_id).getCell(customer_id, 'Customer-name'));
|
||||
$("#receipt-balance").html("Calculating...");
|
||||
$("#receipt-charges-caption").html("Please Wait...");
|
||||
|
||||
// Hide the "no customer" message and show the current customer
|
||||
$(".customer-selection-invalid").hide();
|
||||
@@ -143,7 +159,8 @@ function addPaymentSource(flash) {
|
||||
addDiv('payment-entry-id', 'payment', 'payments', flash,
|
||||
// HTML section
|
||||
'<FIELDSET CLASS="payment subset">' +
|
||||
'<LEGEND>Payment #%{id} (%{remove})</LEGEND>' +
|
||||
<?php /* '<LEGEND>Payment #%{id} (%{remove})</LEGEND>' + */ ?>
|
||||
'<LEGEND>Payment</LEGEND>' +
|
||||
|
||||
'<DIV ID="payment-div-%{id}">' +
|
||||
<?php
|
||||
@@ -173,7 +190,7 @@ function addPaymentSource(flash) {
|
||||
'<DIV ID="payment-amount-div-%{id}" CLASS="input text required">' +
|
||||
' <INPUT TYPE="text" SIZE="20"' +
|
||||
' NAME="data[Entry][%{id}][amount]"' +
|
||||
' CLASS="payment"' +
|
||||
' CLASS="payment amount"' +
|
||||
' ID="payment-amount-%{id}" />' +
|
||||
' <LABEL CLASS="payment" FOR="payment-amount-%{id}">Amount</LABEL>' +
|
||||
'</DIV>' +
|
||||
@@ -219,48 +236,20 @@ function addPaymentSource(flash) {
|
||||
}
|
||||
|
||||
function switchPaymentType(paymentid_base, paymentid, radioid) {
|
||||
$("."+paymentid_base+"-"+paymentid).slideUp();
|
||||
var type_id = $("#"+radioid).val();
|
||||
$("."+paymentid_base+"-"+paymentid+
|
||||
":not(" +
|
||||
"#"+paymentid_base+"-"+paymentid+"-"+type_id +
|
||||
")").slideUp();
|
||||
$("#"+paymentid_base+"-"+paymentid+"-"+type_id).slideDown();
|
||||
}
|
||||
|
||||
|
||||
function updateChargesGrid(idlist) {
|
||||
$('#charge-entries-jqGrid').setPostDataItem('idlist', serialize(idlist));
|
||||
$('#charge-entries-jqGrid')
|
||||
.setGridParam({ page: 1 })
|
||||
.trigger("reloadGrid");
|
||||
}
|
||||
|
||||
function updateCharges(id) {
|
||||
var url = '<?php echo ($html->url(array("controller" => $this->params["controller"],
|
||||
"action" => "unreconciled"))); ?>';
|
||||
url += '/'+id;
|
||||
|
||||
$('#charge-entries-jqGrid').clearGridData();
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "xml",
|
||||
success: function(xml) {
|
||||
var ids = new Array();
|
||||
$('entry',xml).each(function(i){
|
||||
ids.push($(this).attr('id'));
|
||||
});
|
||||
$('#receipt-balance').html(fmtCurrency($('entries',xml).attr('balance')));
|
||||
$("#receipt-charges-caption").html("Outstanding Charges");
|
||||
updateChargesGrid(ids);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
--></script>
|
||||
--></script>
|
||||
|
||||
<?php
|
||||
; // align
|
||||
//echo '<DIV ID="dialog">' . "\n";
|
||||
// Re-Enable warnings
|
||||
Configure::write('debug', $saved_debug_state);
|
||||
|
||||
echo $this->element('customers', array
|
||||
('config' => array
|
||||
@@ -302,17 +291,19 @@ echo ('<DIV CLASS="receipt grid-selection-text">' .
|
||||
|
||||
|
||||
echo $this->element('statement_entries', array
|
||||
(// Element configuration
|
||||
'account_ftype' => 'credit',
|
||||
'limit' => 8,
|
||||
|
||||
// Grid configuration
|
||||
(// Grid configuration
|
||||
'config' => array
|
||||
(
|
||||
'grid_div_id' => 'charge-entries',
|
||||
'grid_div_class' => 'text-below',
|
||||
'grid_events' => array('loadComplete' => 'onGridLoadComplete()'),
|
||||
'grid_setup' => array('hiddengrid' => true),
|
||||
'caption' => '<SPAN id="receipt-charges-caption"></SPAN>',
|
||||
'rows' => $charges,
|
||||
'action' => 'unreconciled',
|
||||
'exclude' => array('Customer', 'Type', 'Debit', 'Credit'),
|
||||
'include' => array('Applied', 'Balance'),
|
||||
'remap' => array('Applied' => 'Paid'),
|
||||
'limit' => 8,
|
||||
),
|
||||
));
|
||||
|
||||
@@ -351,25 +342,37 @@ echo $this->element('form_table',
|
||||
),
|
||||
)));
|
||||
|
||||
echo "<BR>\n";
|
||||
echo $form->input('repeat', array('type' => 'checkbox',
|
||||
'id' => 'repeat',
|
||||
'label' => 'Enter Multiple Receipts')) . "\n";
|
||||
echo $form->submit('Generate Receipt') . "\n";
|
||||
?>
|
||||
|
||||
<?php /*
|
||||
<fieldset CLASS="payment superset">
|
||||
<legend>Payments</legend>
|
||||
*/ ?>
|
||||
<input type="hidden" id="payment-entry-id" value="0">
|
||||
<div id="payments"></div>
|
||||
<?php /*
|
||||
<fieldset> <legend>
|
||||
<a href="#" onClick="addPaymentSource(true); return false;">Add Another Payment</a>
|
||||
</legend> </fieldset>
|
||||
</fieldset>
|
||||
*/ ?>
|
||||
|
||||
<?php echo $form->end('Generate Receipt'); ?>
|
||||
|
||||
<?php /* echo '</DIV>' . "\n"; // End of the dialog DIV */ ?>
|
||||
|
||||
<div><H4>Request</H4><div id="request-debug"></div></div>
|
||||
<div><H4>Response</H4><div id="response-debug"></div></div>
|
||||
<div><H4>Output</H4><div id="output-debug"></div></div>
|
||||
<div id="results"></div>
|
||||
<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(){
|
||||
@@ -380,12 +383,18 @@ echo $form->submit('Generate Receipt') . "\n";
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
resetForm();
|
||||
$("#receipt-customer-id").html("INTERNAL ERROR");
|
||||
$("#receipt-customer-name").html("INTERNAL ERROR");
|
||||
$("#receipt-balance").html("INTERNAL ERROR");
|
||||
$("#receipt-charges-caption").html("Outstanding Charges");
|
||||
|
||||
<?php if (isset($customer['id'])): ?>
|
||||
$("#customer-id").val(<?php echo $customer['id']; ?>);
|
||||
//$("#receipt-customer-id").html("<?php echo '#'.$customer['id']; ?>");
|
||||
$("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
|
||||
$("#receipt-customer-id").html('<A HREF="' +
|
||||
"<?php echo $html->url(array('controller' => 'customers',
|
||||
'action' => 'view')); ?>"
|
||||
+ "/" +
|
||||
"<?php echo $customer['id']; ?>" +
|
||||
'">#' +
|
||||
"<?php echo $customer['id']; ?>" +
|
||||
@@ -397,37 +406,15 @@ echo $form->submit('Generate Receipt') . "\n";
|
||||
onGridState(null, 'visible');
|
||||
<?php endif; ?>
|
||||
|
||||
resetForm();
|
||||
datepickerNow('TransactionStamp');
|
||||
|
||||
|
||||
/* $("#dialog").dialog({ */
|
||||
/* bgiframe: true, */
|
||||
/* autoOpen: false, */
|
||||
/* height: 500, */
|
||||
/* width: 600, */
|
||||
/* modal: true, */
|
||||
/* buttons: { */
|
||||
/* 'Post a Payment': function() { */
|
||||
/* var bValid = true; */
|
||||
/* if (bValid) { */
|
||||
/* $('#debug').append('<H2>POSTED!</H2>'); */
|
||||
/* $(this).dialog('close'); */
|
||||
/* } */
|
||||
/* }, */
|
||||
/* Cancel: function() { */
|
||||
/* $(this).dialog('close'); */
|
||||
/* } */
|
||||
/* }, */
|
||||
/* close: function() { */
|
||||
/* } */
|
||||
/* }); */
|
||||
|
||||
/* $('#post-payment').click(function() { */
|
||||
/* $('#dialog').dialog('open'); */
|
||||
/* }); */
|
||||
<?php if ($this->params['dev']): ?>
|
||||
$('#output-debug').html('Post Output');
|
||||
$('#output-debug').show();
|
||||
<?php endif; ?>
|
||||
|
||||
});
|
||||
--></script>
|
||||
|
||||
</div>
|
||||
|
||||
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>
|
||||
|
||||
@@ -11,6 +11,9 @@ echo '<div class="customer view">' . "\n";
|
||||
|
||||
$rows = array();
|
||||
$rows[] = array('Name', $customer['Customer']['name']);
|
||||
$rows[] = array('Since', FormatHelper::date($since, true));
|
||||
if (!empty($until))
|
||||
$rows[] = array('Until', FormatHelper::date($until, true));
|
||||
$rows[] = array('Comment', $customer['Customer']['comment']);
|
||||
|
||||
echo $this->element('table',
|
||||
@@ -27,7 +30,9 @@ echo $this->element('table',
|
||||
echo '<div class="infobox">' . "\n";
|
||||
$rows = array();
|
||||
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
|
||||
$rows[] = array('Balance:', FormatHelper::currency($outstandingBalance));
|
||||
//$rows[] = array('Charges:', FormatHelper::currency($stats['charges']));
|
||||
//$rows[] = array('Payments:', FormatHelper::currency($stats['disbursements']));
|
||||
$rows[] = array('Balance Owed:', FormatHelper::currency($outstandingBalance));
|
||||
echo $this->element('table',
|
||||
array('class' => 'summary',
|
||||
'rows' => $rows,
|
||||
@@ -80,35 +85,31 @@ echo $this->element('leases', array
|
||||
echo $this->element('statement_entries', array
|
||||
(// Grid configuration
|
||||
'config' => array
|
||||
('caption' => 'Account',
|
||||
('caption' => 'Customer Statement',
|
||||
'filter' => array('Customer.id' => $customer['Customer']['id'],
|
||||
'type !=' => 'VOID'),
|
||||
'exclude' => array('Customer'),
|
||||
'sort_column' => 'Effective',
|
||||
'sort_order' => 'DESC',
|
||||
)));
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* Customer Ledger History
|
||||
* Receipt History
|
||||
*/
|
||||
|
||||
/*
|
||||
* REVISIT <AP>: 20090724
|
||||
* It's not my intention to really include this, as I believe it
|
||||
* just will confuse folks. However, I've added it at the moment
|
||||
* to help me see the picture of what's happening. It may prove
|
||||
* useful with respect to identifying pre-payments, so after using
|
||||
* it for a while, maybe we can get a feeling for that. I suspect
|
||||
* it will be MUCH more useful just to add the pre-pay amount to
|
||||
* the info box, or provide a list of ledger entries that are JUST
|
||||
* pre-payments. We'll see...
|
||||
*/
|
||||
echo $this->element('ledger_entries', array
|
||||
(// Grid configuration
|
||||
'config' => array
|
||||
('caption' => 'Ledger Entries',
|
||||
('caption' => 'Receipts',
|
||||
'filter' => array('Customer.id' => $customer['Customer']['id'],
|
||||
'Account.id !=' => '-AR-'),
|
||||
'exclude' => array('Customer'),
|
||||
'Transaction.type' => 'RECEIPT',
|
||||
'Tender.id !=' => null,
|
||||
//'Account.id !=' => '-AR-'
|
||||
),
|
||||
'exclude' => array('Account', 'Cr/Dr'),
|
||||
'sort_column' => 'Date',
|
||||
'sort_order' => 'DESC',
|
||||
)));
|
||||
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ $ledgers = array('debit' => $entry['DebitLedger'],
|
||||
'credit' => $entry['CreditLedger']);
|
||||
$entries = array('debit' => $entry['DebitEntry'],
|
||||
'credit' => $entry['CreditEntry']);
|
||||
$customer = $entry['Customer'];
|
||||
$lease = $entry['Lease'];
|
||||
$entry = $entry['DoubleEntry'];
|
||||
|
||||
$rows = array();
|
||||
@@ -63,21 +61,7 @@ $rows[] = array('Transaction', $html->link('#'.$transaction['id'],
|
||||
'action' => 'view',
|
||||
$transaction['id'])));
|
||||
$rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp']));
|
||||
$rows[] = array('Effective', FormatHelper::date($entry['effective_date']));
|
||||
//$rows[] = array('Through', FormatHelper::date($entry['through_date']));
|
||||
$rows[] = array('Customer', (isset($customer['name'])
|
||||
? $html->link($customer['name'],
|
||||
array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$customer['id']))
|
||||
: null));
|
||||
$rows[] = array('Lease', (isset($lease['id'])
|
||||
? $html->link('#'.$lease['id'],
|
||||
array('controller' => 'leases',
|
||||
'action' => 'view',
|
||||
$lease['id']))
|
||||
: null));
|
||||
$rows[] = array('Comment', $entry['comment']);
|
||||
$rows[] = array('Comment', $entry['comment']);
|
||||
|
||||
echo $this->element('table',
|
||||
array('class' => 'item ledger-entry detail',
|
||||
@@ -132,8 +116,8 @@ foreach ($ledgers AS $type => $ledger) {
|
||||
array('controller' => 'ledgers',
|
||||
'action' => 'view',
|
||||
$ledger['id'])));
|
||||
$rows[] = array('Amount', FormatHelper::currency($entry['amount']));
|
||||
$rows[] = array('Effect', $ledger['Account']['ftype'] == $type ? 'INCREASE' : 'DECREASE');
|
||||
$rows[] = array('Amount', FormatHelper::currency($entries[$type]['amount']));
|
||||
//$rows[] = array('Effect', $ledger['Account']['ftype'] == $type ? 'INCREASE' : 'DECREASE');
|
||||
|
||||
echo $this->element('table',
|
||||
array('class' => array('item', $type, 'detail'),
|
||||
|
||||
@@ -7,7 +7,7 @@ $cols['Relationship'] = array('index' => 'ContactsCustomer.type', 'formatt
|
||||
$cols['Name'] = array('index' => 'Customer.name', 'formatter' => 'longname');
|
||||
$cols['Last Name'] = array('index' => 'PrimaryContact.last_name', 'formatter' => 'name');
|
||||
$cols['First Name'] = array('index' => 'PrimaryContact.first_name', 'formatter' => 'name');
|
||||
$cols['Leases'] = array('index' => 'lease_count', 'formatter' => 'number');
|
||||
$cols['Leases'] = array('index' => 'current_lease_count', 'formatter' => 'number');
|
||||
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
|
||||
$cols['Comment'] = array('index' => 'Customer.comment', 'formatter' => 'comment');
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ foreach ($fields AS $field => $config) {
|
||||
}
|
||||
|
||||
echo $this->element('table',
|
||||
compact('class', 'caption', 'headers',
|
||||
compact('id', 'class', 'caption', 'headers',
|
||||
'rows', 'row_class', 'suppress_alternate_rows',
|
||||
'column_class')
|
||||
);
|
||||
|
||||
@@ -63,7 +63,6 @@ $javascript->link('pmgr_jqGrid', false);
|
||||
// as part of the data fetch.
|
||||
$url = $html->url(array('controller' => $controller,
|
||||
'action' => 'gridData',
|
||||
'debug' => 0,
|
||||
));
|
||||
|
||||
// Create extra parameters that jqGrid will pass to our
|
||||
@@ -202,11 +201,11 @@ foreach (array_merge(array('loadComplete' => '', 'loadError' => ''),
|
||||
|
||||
if ($event == 'loadComplete') {
|
||||
$grid_events[$event] =
|
||||
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url.replace(/\/debug.*$/,'?'); pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Query</A><BR>'); $statement;}");
|
||||
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url+'/debug:1?'; pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Query</A><BR>'); $statement;}");
|
||||
}
|
||||
elseif ($event == 'loadError') {
|
||||
$grid_events[$event] =
|
||||
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url.replace(/\/debug.*$/,'?'); pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Error Query</A><BR>'); $statement;}");
|
||||
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url+'/debug:1?'; pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Error Query</A><BR>'); $statement;}");
|
||||
}
|
||||
else {
|
||||
$grid_events[$event] =
|
||||
|
||||
@@ -11,9 +11,21 @@ $cols['Deposit'] = array('index' => 'Lease.deposit', 'formatter' => 'cur
|
||||
$cols['Signed'] = array('index' => 'Lease.lease_date', 'formatter' => 'date');
|
||||
$cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date');
|
||||
$cols['Move-Out'] = array('index' => 'Lease.moveout_date', 'formatter' => 'date');
|
||||
$cols['Closed'] = array('index' => 'Lease.close_date', 'formatter' => 'date');
|
||||
$cols['Paid-Thru'] = array('index' => 'Lease.paid_through_date', 'formatter' => 'date');
|
||||
$cols['Status'] = array('index' => 'status', 'formatter' => 'enum', 'width' => 100);
|
||||
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
|
||||
$cols['Comment'] = array('index' => 'Lease.comment', 'formatter' => 'comment');
|
||||
|
||||
if (!empty($this->params['action'])) {
|
||||
if ($this->params['action'] === 'closed')
|
||||
$grid->invalidFields(array('Paid-Thru', 'Status'));
|
||||
elseif ($this->params['action'] === 'active')
|
||||
$grid->invalidFields(array('Closed'));
|
||||
elseif ($this->params['action'] === 'delinquent')
|
||||
$grid->invalidFields(array('Closed'));
|
||||
}
|
||||
|
||||
// Render the grid
|
||||
$grid
|
||||
->columns($cols)
|
||||
@@ -21,4 +33,4 @@ $grid
|
||||
->defaultFields(array('LeaseID', 'Lease'))
|
||||
->searchFields(array('Customer', 'Unit'))
|
||||
->render($this, isset($config) ? $config : null,
|
||||
array_diff(array_keys($cols), array('Comment')));
|
||||
array_diff(array_keys($cols), array('Signed', 'Status', 'Comment')));
|
||||
|
||||
@@ -17,10 +17,15 @@ $cols['Unit'] = array('index' => 'Unit.name', 'formatter' =>
|
||||
|
||||
$cols['Comment'] = array('index' => 'StatementEntry.comment', 'formatter' => 'comment', 'width'=>150);
|
||||
|
||||
$cols['Charge'] = array('index' => 'charge', 'formatter' => 'currency');
|
||||
$cols['Payment'] = array('index' => 'payment', 'formatter' => 'currency');
|
||||
$cols['Type'] = array('index' => 'StatementEntry.type', 'formatter' => 'enum', 'width'=>120);
|
||||
$cols['Debit'] = array('index' => 'charge', 'formatter' => 'currency');
|
||||
$cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency');
|
||||
|
||||
$cols['Amount'] = array('index' => "StatementEntry.amount", 'formatter' => 'currency');
|
||||
$cols['Applied'] = array('index' => "applied", 'formatter' => 'currency');
|
||||
// 'balance' is already in use as part of charge/disbursement/balance.
|
||||
// 'unapplied' isn't quite the right term, but it's not customer visible.
|
||||
$cols['Balance'] = array('index' => "unapplied", 'formatter' => 'currency');
|
||||
$cols['Sub-Total'] = array('index' => 'subtotal-balance', 'formatter' => 'currency', 'sortable' => false);
|
||||
|
||||
|
||||
@@ -39,6 +44,6 @@ $grid
|
||||
->searchFields(array('Customer', 'Unit'))
|
||||
->render($this, isset($config) ? $config : null,
|
||||
array_diff(array_keys($cols), array('Through', 'Lease',
|
||||
'Applied', 'Sub-Total',
|
||||
'Amount', 'Applied', 'Balance', 'Sub-Total',
|
||||
'Comment')));
|
||||
|
||||
|
||||
@@ -64,7 +64,10 @@ if (isset($rows) && is_array($rows) && count($rows)) {
|
||||
$class = implode(' ', $class);
|
||||
|
||||
// OK, output the table HTML
|
||||
echo('<TABLE' . (isset($class) ? ' CLASS="'.$class.'"' : '') . '>' . "\n");
|
||||
echo('<TABLE' .
|
||||
(isset($id) ? ' ID="'.$id.'"' : '') .
|
||||
(isset($class) ? ' CLASS="'.$class.'"' : '') .
|
||||
'>' . "\n");
|
||||
|
||||
if (isset($caption))
|
||||
echo(' <CAPTION>' . $caption . '</CAPTION>' . "\n");
|
||||
|
||||
@@ -8,6 +8,7 @@ $cols['ID'] = array('index' => 'Unit.id', 'formatter' => 'id');
|
||||
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname');
|
||||
$cols['Size'] = array('index' => 'UnitSize.name', 'formatter' => 'shortname');
|
||||
$cols['Rent'] = array('index' => 'Unit.rent', 'formatter' => 'currency');
|
||||
$cols['Deposit'] = array('index' => 'Unit.deposit', 'formatter' => 'currency');
|
||||
$cols['Status'] = array('index' => 'Unit.status', 'formatter' => 'name'); // We have enough real estate
|
||||
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
|
||||
$cols['Comment'] = array('index' => 'Unit.comment', 'formatter' => 'comment');
|
||||
@@ -19,4 +20,4 @@ $grid
|
||||
->defaultFields(array('Sort', 'ID', 'Unit'))
|
||||
->searchFields(array('Unit', 'Size', 'Status'))
|
||||
->render($this, isset($config) ? $config : null,
|
||||
array_diff(array_keys($cols), array('Walk', 'Comment')));
|
||||
array_diff(array_keys($cols), array('Walk', 'Deposit', 'Comment')));
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
if (!empty($message))
|
||||
echo $message;
|
||||
|
||||
|
||||
|
||||
@@ -19,14 +19,26 @@ class FormatHelper extends AppHelper {
|
||||
true));
|
||||
}
|
||||
|
||||
function currency($amount, $spans = false) {
|
||||
function currency($amount, $spans = false, $dollar_sign = null) {
|
||||
if (!isset($amount))
|
||||
return '-';
|
||||
//return null;
|
||||
|
||||
$currency = self::$number->currency($amount,
|
||||
'USD',
|
||||
$spans ? array('before'=>'', 'after'=>'') : array());
|
||||
// Use of the $number->currency() function results in the clever,
|
||||
// but problematic, use of cents for amounts less than $1. For
|
||||
// example, 50 cents is shown as '50c', not '$0.50'. We want to
|
||||
// keep everything in terms of dollars, especially for the cases
|
||||
// where this result is placed into a form for input. 50 cents
|
||||
// will end up as 50 dollars upon submission :-(
|
||||
$currency = self::$number->format
|
||||
(abs($amount),
|
||||
array('places' => 2,
|
||||
'before' => $spans ? '' : (isset($dollar_sign) ? $dollar_sign : '$'),
|
||||
'after' => $spans ? '' : null,
|
||||
));
|
||||
|
||||
if ($amount < 0)
|
||||
$currency = '(' . $currency . ')';
|
||||
|
||||
if ($spans)
|
||||
return ('<SPAN CLASS="dollar-sign">$</SPAN>' .
|
||||
@@ -35,22 +47,29 @@ class FormatHelper extends AppHelper {
|
||||
return $currency;
|
||||
}
|
||||
|
||||
function date($date, $age = false) {
|
||||
function date($date, $age = false, $class = null, $time = false) {
|
||||
if (!$date) return null;
|
||||
|
||||
$date_fmt = 'm/d/Y';
|
||||
return (self::$time->format($date_fmt, $date) .
|
||||
($age
|
||||
? ' (' . self::age($date, 60*60*24) . ')'
|
||||
: ''));
|
||||
if (empty($class))
|
||||
$class = '';
|
||||
|
||||
if ($time)
|
||||
$date_html = self::$time->nice($date);
|
||||
else
|
||||
$date_html = self::$time->format('m/d/Y', $date);
|
||||
|
||||
$date_html = '<span class="fmt-date '.$class.'">'.$date_html.'</span>';
|
||||
|
||||
if ($age) {
|
||||
$date_html .= ' (' . self::age($date, $class, $time ? 0 : 60*60*24) . ')';
|
||||
$date_html = '<span class="fmt-dateage '.$class.'">'.$date_html.'</span>';
|
||||
}
|
||||
|
||||
return $date_html;
|
||||
}
|
||||
|
||||
function datetime($datetime, $age = false) {
|
||||
if (!$datetime) return null;
|
||||
return (self::$time->nice($datetime) .
|
||||
($age
|
||||
? ' (' . self::age($datetime) . ')'
|
||||
: ''));
|
||||
function datetime($datetime, $age = false, $class = null) {
|
||||
return self::date($datetime, $age, $class, true);
|
||||
}
|
||||
|
||||
function phone($phone, $ext = null) {
|
||||
@@ -81,10 +100,13 @@ class FormatHelper extends AppHelper {
|
||||
return $comment;
|
||||
}
|
||||
|
||||
function age($datetime, $min_span = 0) {
|
||||
function age($datetime, $class, $min_span = 0) {
|
||||
if (!isset($datetime))
|
||||
return null;
|
||||
|
||||
if (empty($class))
|
||||
$class = '';
|
||||
|
||||
$now = time();
|
||||
$seconds = self::$time->fromString($datetime);
|
||||
$backwards = ($seconds > $now);
|
||||
@@ -95,9 +117,11 @@ class FormatHelper extends AppHelper {
|
||||
|
||||
//pr(compact('now', 'seconds', 'backwards', 'timefrom', 'timeto', 'span', 'min_span'));
|
||||
|
||||
// If now, just return so
|
||||
if ($span === 0)
|
||||
return __('now', true);
|
||||
// If now, just use 'now'
|
||||
if ($span === 0) {
|
||||
$approx = 0;
|
||||
$unit = 'now';
|
||||
}
|
||||
|
||||
// Display seconds if under 45 seconds
|
||||
if ($span < 45 && $span >= $min_span) {
|
||||
@@ -164,20 +188,33 @@ class FormatHelper extends AppHelper {
|
||||
//pr(compact('span', 'min_span', 'approx', 'unit'));
|
||||
|
||||
if ($approx == 0) {
|
||||
if ($unit == 'day')
|
||||
return __('today', true);
|
||||
|
||||
return __('this ' . $unit, true);
|
||||
if ($unit == 'now')
|
||||
$age = 'now';
|
||||
elseif ($unit == 'day')
|
||||
$age = 'today';
|
||||
else
|
||||
$age = 'this ' . $unit;
|
||||
}
|
||||
else {
|
||||
if (isset($relative))
|
||||
$age = $relative;
|
||||
elseif ($approx > $span)
|
||||
$age = 'almost';
|
||||
elseif ($approx < $span)
|
||||
$age = 'over';
|
||||
else
|
||||
$age = '';
|
||||
|
||||
return (__(isset($relative)
|
||||
? $relative
|
||||
: ($approx == $span
|
||||
? ''
|
||||
: ($approx > $span ? 'almost' : 'over')), true)
|
||||
. ' '
|
||||
. self::_n($approx, $unit)
|
||||
. ($backwards ? '' : __(' ago', true)));
|
||||
$age .= ' ' . self::_n($approx, $unit);
|
||||
|
||||
if ($backwards)
|
||||
$age .= ' ago';
|
||||
|
||||
}
|
||||
|
||||
$age = '<span class="fmt-age '.$class.'">'.__($age, true).'</span>';
|
||||
|
||||
return $age;
|
||||
}
|
||||
|
||||
/*****************************
|
||||
|
||||
@@ -166,9 +166,14 @@ class GridHelper extends AppHelper {
|
||||
$included = array_diff(array_merge($this->included, $included),
|
||||
array_merge($this->invalid, $excluded));
|
||||
|
||||
// Extract the columns that correspond to the inclusion set
|
||||
$this->jqGrid_options['jqGridColumns']
|
||||
= array_intersect_key($this->columns, array_flip($included));
|
||||
// Defined the columns, based on the inclusion set,
|
||||
// remapping column names as necessary.
|
||||
$this->jqGrid_options['jqGridColumns'] = array();
|
||||
foreach (array_intersect_key($this->columns, array_flip($included)) AS $name => $col) {
|
||||
if (!empty($config['remap'][$name]))
|
||||
$name = $config['remap'][$name];
|
||||
$this->jqGrid_options['jqGridColumns'][$name] = $col;
|
||||
}
|
||||
|
||||
// Make sure search fields are all part of the inclusion set
|
||||
$this->jqGrid_options['search_fields']
|
||||
@@ -211,8 +216,9 @@ class GridHelper extends AppHelper {
|
||||
|
||||
// Incorporate all other user options
|
||||
if (isset($config))
|
||||
$this->jqGrid_options = array_merge_recursive($this->jqGrid_options, $config);
|
||||
$this->jqGrid_options = array_merge($this->jqGrid_options, $config);
|
||||
|
||||
//pr(compact('config') + array('jqGrid_options' => $this->jqGrid_options));
|
||||
echo $view->element('jqGrid', $this->jqGrid_options);
|
||||
|
||||
// Since we only have one instance of this class
|
||||
@@ -223,4 +229,4 @@ class GridHelper extends AppHelper {
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="apply-deposit input">' . "\n";
|
||||
|
||||
echo ('<DIV CLASS="apply-deposit grid-selection-text">' .
|
||||
|
||||
'Lease #' . $lease['number'] .
|
||||
' / Customer #' . $customer['id'] .
|
||||
': ' . $customer['name'] .
|
||||
' / Unit ' . $unit['name'] .
|
||||
|
||||
'<DIV CLASS="supporting">' .
|
||||
'<TABLE>' .
|
||||
|
||||
/* '<TR><TD CLASS="field">Balance:</TD><TD CLASS="value">' . */
|
||||
/* FormatHelper::currency($lease['stats']['balance']) . */
|
||||
/* '</TD></TR>' . */
|
||||
|
||||
'<TR><TD CLASS="field">Deposit:</TD><TD CLASS="value">' .
|
||||
FormatHelper::currency($depositBalance) .
|
||||
'</TD></TR>' .
|
||||
|
||||
'</TABLE>' .
|
||||
'</DIV>' .
|
||||
|
||||
'</DIV>' . "\n");
|
||||
|
||||
|
||||
echo $form->create(null, array('id' => 'apply-deposit-form',
|
||||
'url' => array('controller' => 'leases',
|
||||
'action' => 'apply_deposit')
|
||||
)
|
||||
);
|
||||
|
||||
echo $form->input("Customer.id",
|
||||
array('id' => 'customer-id',
|
||||
'type' => 'hidden',
|
||||
'value' => $customer['id']));
|
||||
|
||||
echo $form->input("Lease.id",
|
||||
array('id' => 'lease-id',
|
||||
'type' => 'hidden',
|
||||
'value' => $lease['id']));
|
||||
|
||||
echo $form->input("LedgerEntry.Account.id",
|
||||
array('id' => 'account-id',
|
||||
'type' => 'hidden',
|
||||
'value' => $account['id']));
|
||||
|
||||
|
||||
echo $this->element('form_table',
|
||||
array('class' => "item receipt transaction entry",
|
||||
//'with_name_after' => ':',
|
||||
'field_prefix' => 'Transaction',
|
||||
'fields' => array
|
||||
("stamp" => array('opts' => array('type' => 'text'),
|
||||
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'TransactionStamp\'); return false;">Now</A>',
|
||||
),
|
||||
"amount" => array('prefix' => 'LedgerEntry',
|
||||
'opts' => array('value' => $depositBalance),
|
||||
),
|
||||
"comment" => array('opts' => array('size' => 50),
|
||||
),
|
||||
)));
|
||||
|
||||
echo $form->end('Utilize Deposit');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
// Reset the form
|
||||
function resetForm() {
|
||||
datepickerNow('TransactionStamp');
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#TransactionStamp")
|
||||
.attr('autocomplete', 'off')
|
||||
.datepicker({ constrainInput: true,
|
||||
numberOfMonths: [1, 1],
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
resetForm();
|
||||
});
|
||||
--></script>
|
||||
|
||||
</div>
|
||||
@@ -1,80 +0,0 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="bad-debt input">' . "\n";
|
||||
|
||||
echo ('<DIV CLASS="bad-debt grid-selection-text">' .
|
||||
|
||||
'Lease #' . $lease['number'] .
|
||||
' / Customer #' . $customer['id'] .
|
||||
': ' . $customer['name'] .
|
||||
' / Unit ' . $unit['name'] .
|
||||
|
||||
'<DIV CLASS="supporting">' .
|
||||
'<TABLE>' .
|
||||
'<TR><TD CLASS="field">Balance:</TD><TD CLASS="value">'.$lease['stats']['balance'].'</TD></TR>' .
|
||||
'</TABLE>' .
|
||||
'</DIV>' .
|
||||
|
||||
'</DIV>' . "\n");
|
||||
|
||||
|
||||
echo $form->create(null, array('id' => 'receipt-form',
|
||||
'url' => array('controller' => 'transactions',
|
||||
'action' => 'postReceipt')));
|
||||
|
||||
echo $form->input("Customer.id",
|
||||
array('id' => 'customer-id',
|
||||
'type' => 'hidden',
|
||||
'value' => $customer['id']));
|
||||
|
||||
echo $form->input("Lease.id",
|
||||
array('id' => 'lease-id',
|
||||
'type' => 'hidden',
|
||||
'value' => $lease['id']));
|
||||
|
||||
echo $form->input("LedgerEntry.0.account_id",
|
||||
array('id' => 'account-id',
|
||||
'type' => 'hidden',
|
||||
'value' => $account['id']));
|
||||
|
||||
echo $form->input("LedgerEntry.0.amount",
|
||||
array('id' => 'amount',
|
||||
'type' => 'hidden',
|
||||
'value' => $lease['stats']['balance']));
|
||||
|
||||
|
||||
echo $this->element('form_table',
|
||||
array('class' => "item receipt transaction entry",
|
||||
//'with_name_after' => ':',
|
||||
'field_prefix' => 'Transaction',
|
||||
'fields' => array
|
||||
("stamp" => array('opts' => array('type' => 'text'),
|
||||
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'TransactionStamp\'); return false;">Now</A>',
|
||||
),
|
||||
"comment" => array('opts' => array('size' => 50),
|
||||
),
|
||||
)));
|
||||
|
||||
echo $form->end('Write Off Remaining Balance');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
// Reset the form
|
||||
function resetForm() {
|
||||
datepickerNow('TransactionStamp');
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#TransactionStamp")
|
||||
.attr('autocomplete', 'off')
|
||||
.datepicker({ constrainInput: true,
|
||||
numberOfMonths: [1, 1],
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
resetForm();
|
||||
});
|
||||
--></script>
|
||||
|
||||
</div>
|
||||
@@ -4,6 +4,13 @@
|
||||
<?php
|
||||
; // Editor alignment
|
||||
|
||||
$unit = $lease['Unit'];
|
||||
$customer = $lease['Customer'];
|
||||
|
||||
if (isset($lease['Lease']))
|
||||
$lease = $lease['Lease'];
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
**********************************************************************
|
||||
**********************************************************************
|
||||
@@ -11,6 +18,9 @@
|
||||
* Javascript
|
||||
*/
|
||||
|
||||
// Warnings _really_ screw up javascript
|
||||
$saved_debug_state = Configure::read('debug');
|
||||
Configure::write('debug', '0');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
@@ -23,14 +33,8 @@
|
||||
success: showResponse, // post-submit callback
|
||||
|
||||
// other available options:
|
||||
//url: url, // override for form's 'action' attribute
|
||||
//type: 'get', // 'get' or 'post', override for form's 'method' attribute
|
||||
//dataType: null, // 'xml', 'script', or 'json' (expected server response type)
|
||||
//clearForm: true, // clear all form fields after successful submit
|
||||
//resetForm: true, // reset the form after successful submit
|
||||
|
||||
// $.ajax options can be used here too, for example:
|
||||
//timeout: 3000,
|
||||
};
|
||||
|
||||
// bind form using 'ajaxForm'
|
||||
@@ -39,16 +43,7 @@
|
||||
|
||||
// pre-submit callback
|
||||
function verifyRequest(formData, jqForm, options) {
|
||||
// formData is an array; here we use $.param to convert it to a string to display it
|
||||
// but the form plugin does this for you automatically when it submits the data
|
||||
//var_dump(formData);
|
||||
//$('#request-debug').html('<PRE>'+dump(formData)+'</PRE>');
|
||||
$('#request-debug').html('Ommitted');
|
||||
//return false;
|
||||
|
||||
$('#response-debug').html('Loading <BLINK>...</BLINK>');
|
||||
$('#output-debug').html('Loading <BLINK>...</BLINK>');
|
||||
|
||||
$('#results').html('Working <BLINK>...</BLINK>');
|
||||
// here we could return false to prevent the form from being submitted;
|
||||
// returning anything other than false will allow the form submit to continue
|
||||
return true;
|
||||
@@ -56,42 +51,47 @@ function verifyRequest(formData, jqForm, options) {
|
||||
|
||||
// post-submit callback
|
||||
function showResponse(responseText, statusText) {
|
||||
// for normal html responses, the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseText property
|
||||
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'xml' then the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseXML property
|
||||
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'json' then the first argument to the success callback
|
||||
// is the json data object returned by the server
|
||||
|
||||
if (statusText == 'success') {
|
||||
var amount = 0;
|
||||
$("input.invoice.amount").each(function(i) {
|
||||
amount += (+ $(this).val().replace(/\$/,''));
|
||||
});
|
||||
|
||||
$('#results').html('<H3>Invoice Saved<BR>' +
|
||||
$("#invoice-customer").html() +
|
||||
' : ' + fmtCurrency(amount) +
|
||||
'</H3>');
|
||||
|
||||
if (!$("#repeat").attr("checked")) {
|
||||
window.location.href =
|
||||
<?php if (empty($movein)): ?>
|
||||
"<?php echo $html->url(array('controller' => 'leases',
|
||||
'action' => 'view')); ?>"
|
||||
+ "/" + $("#lease-id").val();
|
||||
<?php else: ?>
|
||||
"<?php echo $html->url(array('controller' => 'customers',
|
||||
'action' => 'receipt')); ?>"
|
||||
+ "/" + $("#lease-id").val();
|
||||
<?php endif; ?>
|
||||
return;
|
||||
}
|
||||
|
||||
// get a clean slate
|
||||
//resetForm();
|
||||
resetForm();
|
||||
}
|
||||
else {
|
||||
alert('not successful??');
|
||||
$('#results').html('<H2>Failed to save invoice!</H2>');
|
||||
alert('Failed to save invoice.');
|
||||
}
|
||||
|
||||
|
||||
$('#response-debug').html('<PRE>'+dump(statusText)+'</PRE>');
|
||||
}
|
||||
|
||||
// Reset the form
|
||||
function resetForm() {
|
||||
$("#charge-entry-id").val(1);
|
||||
function resetForm(nocharge) {
|
||||
$('#charge-entry-id').val(1);
|
||||
$('#charges').html('');
|
||||
|
||||
$("#invoice-lease").html("INTERNAL ERROR");
|
||||
$("#invoice-unit").html("INTERNAL ERROR");
|
||||
$("#invoice-customer").html("INTERNAL ERROR");
|
||||
$("#invoice-rent").html("INTERNAL ERROR");
|
||||
$("#invoice-late").html("INTERNAL ERROR");
|
||||
$("#invoice-deposit").html("INTERNAL ERROR");
|
||||
|
||||
addChargeSource(false);
|
||||
datepickerNow('TransactionStamp');
|
||||
if (!nocharge)
|
||||
addChargeSource(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,10 @@ function onRowSelect(grid_id, lease_id) {
|
||||
// This is not intended as a long term solution,
|
||||
// but I need a way to enter data and then view
|
||||
// the results. This link will help.
|
||||
$("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
|
||||
$("#invoice-lease").html('<A HREF="' +
|
||||
"<?php echo $html->url(array('controller' => 'leases',
|
||||
'action' => 'view')); ?>"
|
||||
+ "/" +
|
||||
$(grid_id).getCell(lease_id, 'Lease-id').replace(/^#/,'') +
|
||||
'">' +
|
||||
$(grid_id).getCell(lease_id, 'Lease-number') +
|
||||
@@ -152,7 +155,8 @@ function addChargeSource(flash) {
|
||||
<?php
|
||||
echo FormatHelper::phpVarToJavascript
|
||||
($this->element('form_table',
|
||||
array('class' => "item invoice ledger-entry entry",
|
||||
array('id' => 'Entry%{id}Form',
|
||||
'class' => "item invoice ledger-entry entry",
|
||||
//'with_name_after' => ':',
|
||||
'field_prefix' => 'Entry.%{id}',
|
||||
'fields' => array
|
||||
@@ -170,7 +174,7 @@ function addChargeSource(flash) {
|
||||
array('type' => 'text'),
|
||||
'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>',
|
||||
),
|
||||
"amount" => true,
|
||||
"amount" => array('opts' => array('class' => 'invoice amount')),
|
||||
"comment" => array('opts' => array('size' => 50)),
|
||||
),
|
||||
))) . "+\n";
|
||||
@@ -192,30 +196,35 @@ function addChargeSource(flash) {
|
||||
numberOfMonths: [1, 1],
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
--></script>
|
||||
|
||||
<?php
|
||||
; // align
|
||||
// Re-Enable warnings
|
||||
Configure::write('debug', $saved_debug_state);
|
||||
|
||||
echo $this->element('leases', array
|
||||
('config' => array
|
||||
('grid_div_id' => 'leases-list',
|
||||
'grid_div_class' => 'text-below',
|
||||
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
|
||||
' return false;">Select Lease</A>'),
|
||||
'grid_setup' => array('hiddengrid' => isset($lease['Lease']['id'])),
|
||||
'grid_events' => array('onSelectRow' =>
|
||||
array('ids' =>
|
||||
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
|
||||
'onHeaderClick' =>
|
||||
array('gridstate' =>
|
||||
'onGridState("#"+$(this).attr("id"), gridstate)'),
|
||||
),
|
||||
'nolinks' => true,
|
||||
'limit' => 10,
|
||||
)));
|
||||
if (empty($movein))
|
||||
echo $this->element('leases', array
|
||||
('config' => array
|
||||
('grid_div_id' => 'leases-list',
|
||||
'grid_div_class' => 'text-below',
|
||||
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
|
||||
' return false;">Select Lease</A>'),
|
||||
'grid_setup' => array('hiddengrid' => isset($lease['id'])),
|
||||
'grid_events' => array('onSelectRow' =>
|
||||
array('ids' =>
|
||||
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
|
||||
'onHeaderClick' =>
|
||||
array('gridstate' =>
|
||||
'onGridState("#"+$(this).attr("id"), gridstate)'),
|
||||
),
|
||||
'nolinks' => true,
|
||||
'limit' => 10,
|
||||
)));
|
||||
|
||||
echo ('<DIV CLASS="invoice grid-selection-text">' .
|
||||
|
||||
@@ -267,6 +276,13 @@ echo $this->element('form_table',
|
||||
|
||||
/* echo '</fieldset>' . "\n"; */
|
||||
|
||||
if (empty($movein)) {
|
||||
echo "<BR>\n";
|
||||
echo $form->input('repeat', array('type' => 'checkbox',
|
||||
'id' => 'repeat',
|
||||
'label' => 'Enter Multiple Invoices')) . "\n";
|
||||
}
|
||||
|
||||
echo $form->submit('Generate Invoice') . "\n";
|
||||
?>
|
||||
|
||||
@@ -281,11 +297,20 @@ echo $form->submit('Generate Invoice') . "\n";
|
||||
|
||||
<?php echo $form->end('Generate Invoice'); ?>
|
||||
|
||||
<div><H4>Request</H4><div id="request-debug"></div></div>
|
||||
<div><H4>Response</H4><div id="response-debug"></div></div>
|
||||
<div><H4>Output</H4><div id="output-debug"></div></div>
|
||||
<div id="results"></div>
|
||||
<div id="output-debug" style="display:none"></div>
|
||||
|
||||
<?php
|
||||
// Warnings _really_ screw up javascript
|
||||
Configure::write('debug', '0');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
$.fn.removeCol = function(col){
|
||||
if(!col){ col = 1; }
|
||||
$('tr td:nth-child('+col+'), tr th:nth-child('+col+')', this).remove();
|
||||
};
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#TransactionStamp")
|
||||
.attr('autocomplete', 'off')
|
||||
@@ -294,28 +319,110 @@ echo $form->submit('Generate Invoice') . "\n";
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
resetForm();
|
||||
$("#invoice-lease").html("INTERNAL ERROR");
|
||||
$("#invoice-unit").html("INTERNAL ERROR");
|
||||
$("#invoice-customer").html("INTERNAL ERROR");
|
||||
$("#invoice-rent").html("INTERNAL ERROR");
|
||||
$("#invoice-late").html("INTERNAL ERROR");
|
||||
$("#invoice-deposit").html("INTERNAL ERROR");
|
||||
|
||||
<?php if (isset($lease['Lease']['id'])): ?>
|
||||
$("#lease-id").val(<?php echo $lease['Lease']['id']; ?>);
|
||||
//$("#invoice-lease").html("<?php echo '#'.$lease['Lease']['number']; ?>");
|
||||
$("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
|
||||
"<?php echo $lease['Lease']['id']; ?>" +
|
||||
<?php if (empty($movein)): ?>
|
||||
|
||||
resetForm();
|
||||
datepickerNow('TransactionStamp');
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
var id;
|
||||
resetForm(true);
|
||||
|
||||
$("#TransactionStamp").datepicker('disable');
|
||||
$("#TransactionStamp").val("<?php echo date('m/d/Y', $movein['time']); ?>");
|
||||
$('#TransactionStamp').after
|
||||
('<input type="hidden"' +
|
||||
' name="data[Transaction][stamp]"' +
|
||||
' value="<?php echo date('m/d/Y', $movein['time']); ?>">');
|
||||
$("#TransactionComment").val('Move-In Charges');
|
||||
|
||||
<?php if ($movein['deposit'] != 0): ?>
|
||||
id = addChargeSource(false);
|
||||
$('#Entry'+id+'Form').removeCol(2);
|
||||
$('#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').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').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').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');
|
||||
<?php endif; ?>
|
||||
|
||||
id = addChargeSource(false);
|
||||
$('#Entry'+id+'Form').removeCol(2);
|
||||
$('#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').after
|
||||
('<input type="hidden"' +
|
||||
' name="data[Entry]['+id+'][effective_date]"' +
|
||||
' 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');
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if (isset($lease['id'])): ?>
|
||||
$("#lease-id").val(<?php echo $lease['id']; ?>);
|
||||
//$("#invoice-lease").html("<?php echo '#'.$lease['number']; ?>");
|
||||
$("#invoice-lease").html('<A HREF="' +
|
||||
"<?php echo $html->url(array('controller' => 'leases',
|
||||
'action' => 'view')); ?>"
|
||||
+ "/" +
|
||||
"<?php echo $lease['id']; ?>" +
|
||||
'">#' +
|
||||
"<?php echo $lease['Lease']['number']; ?>" +
|
||||
"<?php echo $lease['number']; ?>" +
|
||||
'</A>');
|
||||
$("#invoice-unit").html("<?php echo $lease['Unit']['name']; ?>");
|
||||
$("#invoice-customer").html("<?php echo $lease['Customer']['name']; ?>");
|
||||
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['Lease']['rent']); ?>");
|
||||
$("#invoice-late").html('$10.00');
|
||||
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['Lease']['deposit']); ?>");
|
||||
$("#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');
|
||||
<?php else: ?>
|
||||
onGridState(null, 'visible');
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($this->params['dev']): ?>
|
||||
$('#output-debug').html('Post Output');
|
||||
$('#output-debug').show();
|
||||
<?php endif; ?>
|
||||
|
||||
});
|
||||
--></script>
|
||||
|
||||
</div>
|
||||
|
||||
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>
|
||||
|
||||
@@ -41,6 +41,12 @@ function onRowSelect(grid_id, item_type, item_id) {
|
||||
// Get the item name from the grid
|
||||
$("#move-"+item_type).html($(grid_id).getCell(item_id, cell_name));
|
||||
|
||||
// If a unit was selected, update the rent and deposit
|
||||
if (item_type == 'unit') {
|
||||
$("#LeaseRent").val($(grid_id).getCell(item_id, 'Unit-rent'));
|
||||
$("#LeaseDeposit").val($(grid_id).getCell(item_id, 'Unit-deposit'));
|
||||
}
|
||||
|
||||
// Hide the "no customer" message and show the current customer
|
||||
$("."+item_type+"-selection-invalid").hide();
|
||||
$("."+item_type+"-selection-valid").show();
|
||||
@@ -120,7 +126,9 @@ if ($move_type !== 'out') {
|
||||
array('gridstate' =>
|
||||
'onGridState("#"+$(this).attr("id"), "unit", gridstate)'),
|
||||
),
|
||||
'action' => 'unoccupied',
|
||||
'include' => array('Deposit'),
|
||||
'exclude' => array('Balance'),
|
||||
'action' => 'vacant',
|
||||
'nolinks' => true,
|
||||
'limit' => 10,
|
||||
)));
|
||||
@@ -169,7 +177,20 @@ echo $this->element('form_table',
|
||||
'id' => "LeaseMoveDate"),
|
||||
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'LeaseMoveDate\', false); return false;">Now</A>',
|
||||
),
|
||||
"comment" =>
|
||||
) +
|
||||
($move_type === 'in' ? array
|
||||
("deposit" =>
|
||||
array('opts' => array
|
||||
('value' => (!empty($unit)
|
||||
? FormatHelper::currency($unit['deposit'])
|
||||
: null))),
|
||||
"rent" =>
|
||||
array('opts' => array
|
||||
('value' => (!empty($unit)
|
||||
? FormatHelper::currency($unit['rent'])
|
||||
: null))),
|
||||
) : array()) + array
|
||||
("comment" =>
|
||||
($move_type !== 'out'
|
||||
? array('opts' => array('size' => 50))
|
||||
: null),
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="account deposit">' . "\n";
|
||||
echo '<H2>Perform Bank Deposit</H2>' . "\n";
|
||||
echo '<P>Make sure to select the checkboxes below for only those types of currency (Cash, Check, etc) which you intend to actually deposit (you can see all the individual items by dropping down the list below the checkbox). Then, select the Deposit Account where you will make the deposit, and click "Perform Deposit" to close the books on the selected currency types and reset them to a zero balance. On the next page, you will be provided with a deposit slip to prepare the actual deposit.' . "\n";
|
||||
echo '<P><BR>' . "\n";
|
||||
|
||||
//pr(compact('tillableAccount', 'depositableAccount'));
|
||||
|
||||
echo $form->create(null, array('id' => 'deposit-form',
|
||||
'url' => array('controller' => 'accounts',
|
||||
'action' => 'deposit')));
|
||||
|
||||
foreach ($tillableAccount AS $acct) {
|
||||
//$acct = $acct['Account'];
|
||||
|
||||
echo "\n";
|
||||
echo $form->input('Tillable.Ledger.'.$acct['CurrentLedger']['id'].'.checked',
|
||||
array(//'label' => $acct['Account']['name'],
|
||||
'type' => 'checkbox',
|
||||
'checked' => true,
|
||||
'value' => true,
|
||||
'label' => (" I have exactly " .
|
||||
FormatHelper::currency($acct['Account']['stats']['Ledger']['balance']) .
|
||||
" in " . ($acct['Account']['name'] === 'Cash'
|
||||
? 'Cash'
|
||||
: Inflector::pluralize($acct['Account']['name'])) .
|
||||
" and will be depositing it all.")
|
||||
));
|
||||
echo "\n";
|
||||
echo $form->input('Tillable.Ledger.'.$acct['CurrentLedger']['id'].'.amount',
|
||||
array('type' => 'hidden',
|
||||
'value' => $acct['Account']['stats']['Ledger']['balance'],
|
||||
));
|
||||
echo "\n";
|
||||
echo $form->input('Tillable.Ledger.'.$acct['CurrentLedger']['id'].'.account_id',
|
||||
array('type' => 'hidden',
|
||||
'value' => $acct['Account']['id'],
|
||||
));
|
||||
echo "\n";
|
||||
echo $form->input('Tillable.Ledger.'.$acct['CurrentLedger']['id'].'.account_name',
|
||||
array('type' => 'hidden',
|
||||
'value' => $acct['Account']['name'],
|
||||
));
|
||||
echo "\n";
|
||||
|
||||
$grid_div_id = 'ledger_entries'.$acct['CurrentLedger']['id'].'-list';
|
||||
echo $this->element('ledger_entries', array
|
||||
(// Element configuration
|
||||
'ledger_id' => $acct['CurrentLedger']['id'],
|
||||
'no_account' => true,
|
||||
|
||||
// Grid configuration
|
||||
'config' => array
|
||||
(
|
||||
'grid_div_id' => $grid_div_id,
|
||||
'caption' => ('<A HREF="#" ONCLICK="$(\'#'.$grid_div_id.' .HeaderButton\').click();'.
|
||||
' return false;">Items in '.$acct['Account']['name'].' Ledger</A>'),
|
||||
'grid_setup' => array('hiddengrid' => true),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
$options = array();
|
||||
foreach ($depositableAccount AS $acct) {
|
||||
$options[$acct['Account']['id']] = $acct['Account']['name'];
|
||||
}
|
||||
|
||||
echo $form->input('Deposit.Account.id', array('label' => 'Deposit Account ',
|
||||
'options' => $options));
|
||||
echo $form->end('Perform Deposit');
|
||||
|
||||
/* End page div */
|
||||
echo '</div>' . "\n";
|
||||
@@ -39,7 +39,6 @@ $rows[] = array('Notice Received', FormatHelper::date($lease['notice_received_d
|
||||
$rows[] = array('Closed', FormatHelper::date($lease['close_date'], true));
|
||||
$rows[] = array('Deposit', FormatHelper::currency($lease['deposit']));
|
||||
$rows[] = array('Rent', FormatHelper::currency($lease['rent']));
|
||||
$rows[] = array('Paid Through', FormatHelper::date($lease['paid_through'], true));
|
||||
$rows[] = array('Comment', $lease['comment']);
|
||||
|
||||
|
||||
@@ -57,7 +56,10 @@ echo $this->element('table',
|
||||
echo '<div class="infobox">' . "\n";
|
||||
$rows = array();
|
||||
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
|
||||
$rows[] = array('Balance:', FormatHelper::currency($outstandingBalance));
|
||||
$rows[] = array('Balance Owed:', FormatHelper::currency($outstandingBalance));
|
||||
$rows[] = array('Paid Through:', FormatHelper::date($lease['paid_through_date'], false));
|
||||
if ($lease['delinquent'])
|
||||
$rows[] = array('Delinquent:', FormatHelper::age($lease['paid_through_date'], 'delinquent'));
|
||||
echo $this->element('table',
|
||||
array('class' => 'summary',
|
||||
'rows' => $rows,
|
||||
@@ -84,10 +86,31 @@ echo '<div CLASS="detail supporting">' . "\n";
|
||||
echo $this->element('statement_entries', array
|
||||
(// Grid configuration
|
||||
'config' => array
|
||||
('caption' => 'Account',
|
||||
('caption' => 'Lease Statement',
|
||||
'filter' => array('Lease.id' => $lease['id']),
|
||||
'include' => array('Through'),
|
||||
'exclude' => array('Customer', 'Lease', 'Unit'),
|
||||
'sort_column' => 'Effective',
|
||||
'sort_order' => 'DESC',
|
||||
)));
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* 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-'
|
||||
),
|
||||
'exclude' => array('Account', 'Cr/Dr'),
|
||||
'sort_column' => 'Date',
|
||||
'sort_order' => 'DESC',
|
||||
)));
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ $ledger = $entry['Ledger'];
|
||||
$account = $ledger['Account'];
|
||||
$tender = $entry['Tender'];
|
||||
$matching = $entry['MatchingEntry'];
|
||||
$double = $entry['DoubleEntry'];
|
||||
$entry = $entry['LedgerEntry'];
|
||||
|
||||
$rows = array();
|
||||
@@ -43,6 +44,10 @@ $rows[] = array('Cr/Dr', ($entry['crdr'] .
|
||||
'action' => 'view',
|
||||
$matching['id'])) .
|
||||
')'));
|
||||
$rows[] = array('Double Entry', $html->link('#'.$double['id'],
|
||||
array('controller' => 'double_entries',
|
||||
'action' => 'view',
|
||||
$double['id'])));
|
||||
$rows[] = array('Comment', $entry['comment']);
|
||||
|
||||
echo $this->element('table',
|
||||
|
||||
@@ -72,7 +72,7 @@ echo $this->element('ledger_entries', array
|
||||
'filter' => array('Ledger.id' => $ledger['id']),
|
||||
'exclude' => array('Ledger', 'Account',
|
||||
'Amount', 'Cr/Dr', 'Balance',
|
||||
empty($account['payments']) ? 'Tender' : null),
|
||||
empty($account['receipts']) ? 'Tender' : null),
|
||||
'include' => array('Debit', 'Credit', 'Sub-Total'),
|
||||
)));
|
||||
|
||||
|
||||
@@ -15,15 +15,18 @@ $customer = $entry['Customer'];
|
||||
$lease = $entry['Lease'];
|
||||
$entry = $entry['StatementEntry'];
|
||||
|
||||
$Ttype = ucwords(strtolower(str_replace('_', ' ', $transaction['type'])));
|
||||
|
||||
$rows = array();
|
||||
$rows[] = array('ID', $entry['id']);
|
||||
$rows[] = array('Transaction', $html->link('#'.$transaction['id'],
|
||||
$rows[] = array($Ttype, $html->link('#'.$transaction['id'],
|
||||
array('controller' => 'transactions',
|
||||
'action' => 'view',
|
||||
$transaction['id'])));
|
||||
$rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp']));
|
||||
$rows[] = array('Effective', FormatHelper::date($entry['effective_date']));
|
||||
$rows[] = array('Through', FormatHelper::date($entry['through_date']));
|
||||
if (in_array($entry['type'], array('CHARGE', 'PAYMENT')))
|
||||
$rows[] = array('Through', FormatHelper::date($entry['through_date']));
|
||||
$rows[] = array('Type', $entry['type']);
|
||||
$rows[] = array('Amount', FormatHelper::currency($entry['amount']));
|
||||
$rows[] = array('Account', $html->link($account['name'],
|
||||
@@ -56,12 +59,12 @@ echo $this->element('table',
|
||||
*/
|
||||
|
||||
if (strtoupper($entry['type']) === 'CHARGE') {
|
||||
$applied_caption = "Payments Applied";
|
||||
$applied_caption = "Disbursements Applied";
|
||||
//$remaining_caption = "Charge Balance";
|
||||
}
|
||||
else {
|
||||
$applied_caption = "Applied to Charges";
|
||||
//$remaining_caption = "Payment Balance";
|
||||
$applied_caption = "Disbursed to Charges";
|
||||
//$remaining_caption = "Disbursement Balance";
|
||||
}
|
||||
|
||||
$remaining_caption = "Remaining Balance";
|
||||
@@ -110,9 +113,9 @@ echo $this->element('statement_entries', array
|
||||
|
||||
// Grid configuration
|
||||
'config' => array
|
||||
('caption' => 'Entries Applied',
|
||||
('caption' => $applied_caption,
|
||||
//'filter' => array('id' => $entry['id']),
|
||||
'exclude' => array('Entry'),
|
||||
'exclude' => array('Transaction'),
|
||||
)));
|
||||
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ foreach ($depositTypes AS $type) {
|
||||
'separator' => '<BR>',
|
||||
'onclick' => "switchSelection({$type['id']})",
|
||||
'legend' => false,
|
||||
'value' => $type['stats']['undeposited'] > 0 ? 'all' : 'none',
|
||||
// REVISIT <AP>: 20080811; Make opt-in, or opt-out?
|
||||
'value' => $type['stats']['undeposited'] > 0 ? 'none' : 'none',
|
||||
'disabled' => $type['stats']['undeposited'] <= 0,
|
||||
'options' => $radioOptions,
|
||||
));
|
||||
|
||||
90
site/views/tenders/edit.ctp
Normal file
90
site/views/tenders/edit.ctp
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="tender edit">' . "\n";
|
||||
|
||||
?>
|
||||
<script type="text/javascript"><!--
|
||||
function switchTenderType(base, radioid) {
|
||||
var type_id = $("#"+radioid).val();
|
||||
if (!$("#"+base+"-"+type_id).is(':visible')) {
|
||||
$("."+base).slideUp();
|
||||
$("#"+base+"-"+type_id).slideDown();
|
||||
}
|
||||
}
|
||||
$(document).ready(function(){
|
||||
switchTenderType("tender-type-div", "TenderTenderTypeId");
|
||||
});
|
||||
|
||||
--></script>
|
||||
<?php
|
||||
; // align
|
||||
|
||||
echo $form->create('Tender', array('action' => 'edit')) . "\n";
|
||||
echo $form->input('id') . "\n";
|
||||
|
||||
if (empty($this->data['Tender']))
|
||||
INTERNAL_ERROR('Creation of new Tender not allowed.');
|
||||
|
||||
echo $form->input('tender_type_id',
|
||||
array('div' => 'tender input',
|
||||
// REVISIT <AP>: 20090810
|
||||
// We're not ready to allow changing the type
|
||||
// of a tender, since it will force us to deal
|
||||
// with changing the LedgerEntry account (easy)
|
||||
// and the associated StatementEntry accounts
|
||||
// (not too hard), and make sure the tender has
|
||||
// not been deposited (easy), and then deal with
|
||||
// any corner cases that pop up.
|
||||
'disabled' => true,
|
||||
'onclick' => ('switchTenderType(' .
|
||||
'"tender-type-div", ' .
|
||||
'$(this).attr("id")' .
|
||||
')'),
|
||||
)) . "\n";
|
||||
|
||||
$form->input('comment');
|
||||
foreach ($types AS $type) {
|
||||
$type = $type['TenderType'];
|
||||
echo('<DIV' .
|
||||
' ID="tender-type-div-'.$type['id'].'"' .
|
||||
' CLASS="tender-type-div"' .
|
||||
($type['id'] != $this->data['TenderType']['id']
|
||||
? ' STYLE="display:none;"' : '') .
|
||||
'>' . "\n");
|
||||
|
||||
echo ('<INPUT TYPE="hidden"' .
|
||||
' NAME="data[type]['.$type['id'].'][tender_type_id]"' .
|
||||
' VALUE="'.$type['id'].'"' .
|
||||
'>' . "\n");
|
||||
|
||||
for ($i=1; $i<=4; ++$i) {
|
||||
if (!empty($type["data{$i}_name"])) {
|
||||
echo $form->input("type.{$type['id']}.data$i",
|
||||
array('label' => $type["data{$i}_name"],
|
||||
'div' => 'input text tender',
|
||||
'value' =>
|
||||
($type['id'] == $this->data['TenderType']['id']
|
||||
? $this->data['Tender']["data$i"] : null),
|
||||
)) . "\n";
|
||||
|
||||
/* echo ('<DIV CLASS="input text required">' . */
|
||||
/* ' <INPUT TYPE="text" SIZE="20"' . */
|
||||
/* ' NAME="data[type]['.$type['id'].'][data'.$i.']"' . */
|
||||
/* ' CLASS="tender"' . */
|
||||
/* ' ID= */
|
||||
/* '<LABEL' . */
|
||||
/* ' CLASS="tender"' . */
|
||||
/* ' FOR="tender-data'.$i.'">' . */
|
||||
/* $type["data{$i}_name"] . */
|
||||
/* '</LABEL>' . "\n" . */
|
||||
/* '</DIV>' . "\n"); */
|
||||
}
|
||||
}
|
||||
|
||||
echo('</DIV>' . "\n");
|
||||
}
|
||||
|
||||
echo $form->submit('Update') . "\n";
|
||||
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
|
||||
echo $form->end() . "\n";
|
||||
echo '</div>' . "\n";
|
||||
74
site/views/tenders/nsf.ctp
Normal file
74
site/views/tenders/nsf.ctp
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="nsf input">' . "\n";
|
||||
|
||||
$customer = $tender['Customer'];
|
||||
$entry = $tender['LedgerEntry'];
|
||||
$transaction = $entry['Transaction'];
|
||||
|
||||
if (isset($tender['Tender']))
|
||||
$tender = $tender['Tender'];
|
||||
|
||||
// We're not actually using a grid to select the customer,
|
||||
// but selection-text makes for reasonable formatting
|
||||
echo ('<DIV CLASS="nsf grid-selection-text">' .
|
||||
'<TABLE>' . "\n");
|
||||
|
||||
echo ('<TR><TD style="padding-right: 1em;">' . $customer['name'] . '</TD>' .
|
||||
' <TD>' . '(Customer #' . $customer['id'] . ')' . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
echo ('<TR><TD style="padding-right: 1em;">' . $tender['name'] . '</TD>' .
|
||||
' <TD>' . '(Tender #' . $tender['id'] . ')' . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
echo ('<TR><TD style="padding-right: 1em;">Amount:</TD>' .
|
||||
' <TD>' . FormatHelper::currency($entry['amount']) . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
echo ('</TABLE>' .
|
||||
'</DIV>' . "\n");
|
||||
|
||||
|
||||
echo $form->create(null, array('id' => 'nsf-form',
|
||||
'url' => array('action' => 'nsf'))) . "\n";
|
||||
|
||||
echo $form->input("Tender.id",
|
||||
array('type' => 'hidden',
|
||||
'value' => $tender['id'])) . "\n";
|
||||
|
||||
echo $this->element('form_table',
|
||||
array('class' => "item receipt transaction entry",
|
||||
//'with_name_after' => ':',
|
||||
'field_prefix' => 'Transaction',
|
||||
'fields' => array
|
||||
("stamp" => array('opts' => array('type' => 'text'),
|
||||
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'TransactionStamp\'); return false;">Now</A>',
|
||||
),
|
||||
"comment" => array('opts' => array('size' => 50),
|
||||
),
|
||||
))) . "\n";
|
||||
|
||||
echo $form->end('Record Item as NSF');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
// Reset the form
|
||||
function resetForm() {
|
||||
datepickerNow('TransactionStamp');
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#TransactionStamp")
|
||||
.attr('autocomplete', 'off')
|
||||
.datepicker({ constrainInput: true,
|
||||
numberOfMonths: [1, 1],
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
resetForm();
|
||||
});
|
||||
--></script>
|
||||
|
||||
</div>
|
||||
89
site/views/transactions/bad_debt.ctp
Normal file
89
site/views/transactions/bad_debt.ctp
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="bad-debt input">' . "\n";
|
||||
|
||||
if (isset($lease)) {
|
||||
$customer = $lease['Customer'];
|
||||
$unit = $lease['Unit'];
|
||||
}
|
||||
|
||||
if (isset($customer['Customer']))
|
||||
$customer = $customer['Customer'];
|
||||
|
||||
if (isset($lease['Lease']))
|
||||
$lease = $lease['Lease'];
|
||||
|
||||
// We're not actually using a grid to select the customer / lease
|
||||
// but we could/should be, and the result would be selection-text
|
||||
echo ('<DIV CLASS="bad-debt grid-selection-text">' .
|
||||
'<TABLE>' . "\n");
|
||||
|
||||
echo ('<TR><TD style="padding-right: 1em;">' . $customer['name'] . '</TD>' .
|
||||
' <TD>' . '(Customer #' . $customer['id'] . ')' . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
if (isset($lease))
|
||||
echo ('<TR><TD style="padding-right: 1em;">' . 'Unit ' . $unit['name'] . '</TD>' .
|
||||
' <TD>' . '(Lease #' . $lease['number'] . ')' . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
echo ('<TR><TD style="padding-right: 1em;">Remaining Balance:</TD>' .
|
||||
' <TD>' . FormatHelper::currency($balance) . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
echo ('</TABLE>' .
|
||||
'</DIV>' . "\n");
|
||||
|
||||
|
||||
echo $form->create(null, array('id' => 'receipt-form',
|
||||
'url' => array('controller' => 'transactions',
|
||||
'action' => 'postWriteOff'))) . "\n";
|
||||
|
||||
echo $form->input("Customer.id",
|
||||
array('type' => 'hidden',
|
||||
'value' => $customer['id'])) . "\n";
|
||||
|
||||
if (isset($lease['id']))
|
||||
echo $form->input("Lease.id",
|
||||
array('type' => 'hidden',
|
||||
'value' => $lease['id'])) . "\n";
|
||||
|
||||
echo $form->input("Entry.0.amount",
|
||||
array('type' => 'hidden',
|
||||
'value' => $balance)) . "\n";
|
||||
|
||||
echo $this->element('form_table',
|
||||
array('class' => "item receipt transaction entry",
|
||||
//'with_name_after' => ':',
|
||||
'field_prefix' => 'Transaction',
|
||||
'fields' => array
|
||||
("stamp" => array('opts' => array('type' => 'text'),
|
||||
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'TransactionStamp\'); return false;">Now</A>',
|
||||
),
|
||||
"comment" => array('opts' => array('size' => 50),
|
||||
),
|
||||
))) . "\n";
|
||||
|
||||
echo $form->end('Write Off Remaining Balance');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
// Reset the form
|
||||
function resetForm() {
|
||||
datepickerNow('TransactionStamp');
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#TransactionStamp")
|
||||
.attr('autocomplete', 'off')
|
||||
.datepicker({ constrainInput: true,
|
||||
numberOfMonths: [1, 1],
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
resetForm();
|
||||
});
|
||||
--></script>
|
||||
|
||||
</div>
|
||||
106
site/views/transactions/refund.ctp
Normal file
106
site/views/transactions/refund.ctp
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="refund input">' . "\n";
|
||||
echo '<H2>Issue Refund</H2>' . "\n";
|
||||
echo '<P>Enter the amount to refund, and the account to pay it from.' . "\n";
|
||||
echo '<P><BR>' . "\n";
|
||||
|
||||
if (isset($lease)) {
|
||||
$customer = $lease['Customer'];
|
||||
$unit = $lease['Unit'];
|
||||
}
|
||||
|
||||
if (isset($customer['Customer']))
|
||||
$customer = $customer['Customer'];
|
||||
|
||||
if (isset($lease['Lease']))
|
||||
$lease = $lease['Lease'];
|
||||
|
||||
// We're not actually using a grid to select the customer / lease
|
||||
// but we could/should be, and the result would be selection-text
|
||||
echo ('<DIV CLASS="refund grid-selection-text">' .
|
||||
'<TABLE>' . "\n");
|
||||
|
||||
echo ('<TR><TD style="padding-right: 1em;">' . $customer['name'] . '</TD>' .
|
||||
' <TD>' . '(Customer #' . $customer['id'] . ')' . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
if (isset($lease))
|
||||
echo ('<TR><TD style="padding-right: 1em;">' . 'Unit ' . $unit['name'] . '</TD>' .
|
||||
' <TD>' . '(Lease #' . $lease['number'] . ')' . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
echo ('<TR><TD style="padding-right: 1em;">Refundable Balance:</TD>' .
|
||||
' <TD>' . FormatHelper::currency($balance) . '</TD>' .
|
||||
'</TR>' . "\n");
|
||||
|
||||
echo ('</TABLE>' .
|
||||
'</DIV>' . "\n");
|
||||
|
||||
|
||||
echo $form->create(null, array('id' => 'refund-form',
|
||||
'url' => array('controller' => 'transactions',
|
||||
'action' => 'postRefund')));
|
||||
|
||||
|
||||
// REVISIT <AP>: 20090805
|
||||
// Add Tender information to log specifically _how_ refund was paid.
|
||||
|
||||
echo $this->element('form_table',
|
||||
array('class' => "item refund transaction entry",
|
||||
//'with_name_after' => ':',
|
||||
'field_prefix' => 'Transaction',
|
||||
'fields' => array
|
||||
("stamp" => array('opts' =>
|
||||
array('type' => 'text'),
|
||||
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'TransactionStamp\'); return false;">Now</A>',
|
||||
),
|
||||
"amount" => array('prefix' => 'Entry.0',
|
||||
'opts' =>
|
||||
array('value' =>
|
||||
FormatHelper::currency($balance),
|
||||
),
|
||||
),
|
||||
"account_id" => array('prefix' => 'Entry.0',
|
||||
'name' => 'Account',
|
||||
'opts' =>
|
||||
array('options' => $refundAccounts,
|
||||
'value' => $defaultAccount,
|
||||
),
|
||||
),
|
||||
"comment" => array('opts' => array('size' => 50),
|
||||
),
|
||||
))) . "\n";
|
||||
|
||||
echo $form->input("Customer.id",
|
||||
array('type' => 'hidden',
|
||||
'value' => $customer['id'])) . "\n";
|
||||
|
||||
if (isset($lease['id']))
|
||||
echo $form->input("Lease.id",
|
||||
array('type' => 'hidden',
|
||||
'value' => $lease['id'])) . "\n";
|
||||
|
||||
echo $form->end('Issue Refund');
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
// Reset the form
|
||||
function resetForm() {
|
||||
datepickerNow('TransactionStamp');
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#TransactionStamp")
|
||||
.attr('autocomplete', 'off')
|
||||
.datepicker({ constrainInput: true,
|
||||
numberOfMonths: [1, 1],
|
||||
showCurrentAtPos: 0,
|
||||
dateFormat: 'mm/dd/yy' });
|
||||
|
||||
resetForm();
|
||||
});
|
||||
--></script>
|
||||
|
||||
</div>
|
||||
@@ -11,13 +11,14 @@ echo '<div class="transaction view">' . "\n";
|
||||
|
||||
$account = $transaction['Account'];
|
||||
$ledger = $transaction['Ledger'];
|
||||
$nsf_tender = $transaction['NsfTender'];
|
||||
|
||||
if (isset($transaction['Transaction']))
|
||||
$transaction = $transaction['Transaction'];
|
||||
|
||||
$rows = array();
|
||||
$rows[] = array('ID', $transaction['id']);
|
||||
$rows[] = array('Type', $transaction['type']);
|
||||
$rows[] = array('Type', str_replace('_', ' ', $transaction['type']));
|
||||
$rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp']));
|
||||
$rows[] = array('Amount', FormatHelper::currency($transaction['amount']));
|
||||
$rows[] = array('Account', $html->link($account['name'],
|
||||
@@ -28,7 +29,11 @@ $rows[] = array('Ledger', $html->link($ledger['name'],
|
||||
array('controller' => 'ledgers',
|
||||
'action' => 'view',
|
||||
$ledger['id'])));
|
||||
$rows[] = array('Comment', $transaction['comment']);
|
||||
if (!empty($nsf_tender['id']))
|
||||
$rows[] = array('NSF Tender', $html->link($nsf_tender['name'],
|
||||
array('controller' => 'tenders',
|
||||
'action' => 'view',
|
||||
$nsf_tender['id'])));
|
||||
|
||||
echo $this->element('table',
|
||||
array('class' => 'item transaction detail',
|
||||
@@ -67,7 +72,11 @@ echo '<div CLASS="detail supporting">' . "\n";
|
||||
* Statement Entries
|
||||
*/
|
||||
|
||||
if ($transaction['type'] === 'INVOICE' || $transaction['type'] === 'RECEIPT') {
|
||||
if ($transaction['type'] === 'INVOICE' ||
|
||||
$transaction['type'] === 'RECEIPT' ||
|
||||
$transaction['type'] === 'CREDIT_NOTE' ||
|
||||
$transaction['type'] === 'PAYMENT'
|
||||
) {
|
||||
echo $this->element('statement_entries', array
|
||||
(// Grid configuration
|
||||
'config' => array
|
||||
@@ -75,7 +84,8 @@ if ($transaction['type'] === 'INVOICE' || $transaction['type'] === 'RECEIPT') {
|
||||
'caption' => 'Statement Entries',
|
||||
'filter' => array('Transaction.id' => $transaction['id'],
|
||||
'type !=' => 'VOID'),
|
||||
'exclude' => array('Transaction', 'Account'),
|
||||
'exclude' => array('Transaction', 'Debit', 'Credit'),
|
||||
'include' => array('Amount'),
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
27
site/views/units/edit.ctp
Normal file
27
site/views/units/edit.ctp
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php /* -*- mode:PHP -*- */
|
||||
|
||||
echo '<div class="unit edit">' . "\n";
|
||||
|
||||
echo $form->create('Unit', array('action' => 'edit')) . "\n";
|
||||
echo $form->input('id') . "\n";
|
||||
|
||||
echo($this->element
|
||||
('form_table',
|
||||
array('class' => 'item unit detail',
|
||||
'caption' => isset($this->data['Unit']) ? 'Edit Unit' : 'New Unit',
|
||||
'fields' => array
|
||||
('name' => true,
|
||||
'unit_size_id' => true,
|
||||
'status' => array('opts' =>
|
||||
array('options' => $statusEnums,
|
||||
),
|
||||
),
|
||||
'deposit' => true,
|
||||
'rent' => true,
|
||||
'comment' => true,
|
||||
))) . "\n");
|
||||
|
||||
echo $form->submit('Update') . "\n";
|
||||
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
|
||||
echo $form->end() . "\n";
|
||||
echo '</div>' . "\n";
|
||||
@@ -81,12 +81,14 @@ if (isset($current_lease['id'])) {
|
||||
'config' => array
|
||||
(
|
||||
'caption' =>
|
||||
('Current Lease Account ('
|
||||
('Current Lease Statement ('
|
||||
. $current_lease['Customer']['name']
|
||||
. ')'),
|
||||
'filter' => array('Lease.id' => $current_lease['id']),
|
||||
'include' => array('Through'),
|
||||
'exclude' => array('Customer', 'Lease', 'Unit'),
|
||||
'sort_column' => 'Effective',
|
||||
'sort_order' => 'DESC',
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,13 @@ div.item.list { margin-bottom: 1.5em; }
|
||||
table.item.list { margin-bottom: 1.5em; }
|
||||
|
||||
|
||||
/************************************************************
|
||||
************************************************************
|
||||
* Date formats
|
||||
*/
|
||||
span.fmt-age.delinquent { color: #f00; }
|
||||
|
||||
|
||||
/************************************************************
|
||||
************************************************************
|
||||
* Cell configuration
|
||||
@@ -195,10 +202,10 @@ table.list.ledger td.evnrow { background: #f4f4f4; }
|
||||
|
||||
/************************************************************
|
||||
************************************************************
|
||||
* Receipt Entry
|
||||
* Receipt Entry / Tender Edit
|
||||
*/
|
||||
|
||||
input.payment {
|
||||
input.payment, div.tender.input input, div.tender.input select {
|
||||
width: 10em;
|
||||
}
|
||||
label.payment {
|
||||
@@ -208,6 +215,16 @@ label.payment {
|
||||
/* display: block; */
|
||||
}
|
||||
|
||||
div.tender.edit div.tender.input {
|
||||
padding-bottom: 0.1em;
|
||||
}
|
||||
|
||||
div.tender.edit div.tender.input label {
|
||||
float: left;
|
||||
width: 12em;
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************
|
||||
************************************************************
|
||||
|
||||
51
todo.notes
51
todo.notes
@@ -4,32 +4,16 @@ 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.
|
||||
|
||||
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.
|
||||
|
||||
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).
|
||||
Invoice
|
||||
- Have some sort of rent-proration tool
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Update unit status between OCCUPIED / LATE / LOCKED depending
|
||||
on the current situation.
|
||||
|
||||
@@ -132,3 +116,28 @@ 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.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user