Compare commits

..

2 Commits

426 changed files with 26610 additions and 9454 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -471,6 +471,7 @@ CREATE TABLE `pmgr_units` (
'DIRTY', 'DIRTY',
'VACANT', 'VACANT',
'OCCUPIED', 'OCCUPIED',
'LATE', -- NOT SURE
'LOCKED', 'LOCKED',
'LIENED') 'LIENED')
NOT NULL DEFAULT 'VACANT', NOT NULL DEFAULT 'VACANT',
@@ -724,9 +725,6 @@ CREATE TABLE `pmgr_leases` (
`notice_received_date` DATE DEFAULT NULL, `notice_received_date` DATE DEFAULT NULL,
`close_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, `deposit` FLOAT(12,2) DEFAULT NULL,
`rent` FLOAT(12,2) DEFAULT NULL, `rent` FLOAT(12,2) DEFAULT NULL,
@@ -874,46 +872,47 @@ CREATE TABLE `pmgr_accounts` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8; ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
LOCK TABLES `pmgr_accounts` WRITE; 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`) INSERT INTO `pmgr_accounts` (`type`, `name`)
VALUES VALUES
('ASSET', 'A/R' ), ('ASSET', 'A/R' ),
('LIABILITY', 'A/P' ), -- REVISIT <AP>: 20090710 : We don't really need NSF, as it
('LIABILITY', 'Credit' ); -- will always run a zero balance. However, it will help
INSERT INTO `pmgr_accounts` (`type`, `name`, `receipts`) -- us identify how serious the NSF situation is.
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' ), ('ASSET', 'NSF' ),
('EXPENSE', 'Waiver' ), ('LIABILITY', 'A/P' );
('EXPENSE', 'Bad Debt' ); INSERT INTO `pmgr_accounts` (`type`, `name`, `receipts`, `refunds`)
VALUES
('ASSET', 'Cash', 1, 0),
('ASSET', 'Check', 1, 0),
('ASSET', 'Money Order', 1, 0),
('ASSET', 'ACH', 1, 0),
('ASSET', 'Closing', 0, 0), -- REVISIT <AP>: Temporary
('EXPENSE', 'Concession', 1, 0),
('EXPENSE', 'Waiver', 0, 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`, `invoices`) INSERT INTO `pmgr_accounts` (`type`, `name`, `invoices`)
VALUES VALUES
('LIABILITY', 'Tax', 0), ('LIABILITY', 'Tax', 1),
('LIABILITY', 'Security Deposit', 1), ('LIABILITY', 'Security Deposit', 1),
('INCOME', 'Rent', 1), ('INCOME', 'Rent', 1),
('INCOME', 'Late Charge', 1), ('INCOME', 'Late Charge', 1),
('INCOME', 'NSF Charge', 1), ('INCOME', 'NSF Charge', 1),
('INCOME', 'Cleaning', 1),
('INCOME', 'Damage', 1); ('INCOME', 'Damage', 1);
INSERT INTO `pmgr_accounts` (`type`, `name`, `deposits`, `refunds`)
VALUES
('ASSET', 'Bank', 1, 1);
INSERT INTO `pmgr_accounts` (`type`, `name`) INSERT INTO `pmgr_accounts` (`type`, `name`)
VALUES VALUES
('EXPENSE', 'Bad Debt' ),
('EXPENSE', 'Maintenance' ); ('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; UNLOCK TABLES;
@@ -971,8 +970,6 @@ CREATE TABLE `pmgr_transactions` (
'CREDIT_NOTE', -- Inverse of Sales Invoice 'CREDIT_NOTE', -- Inverse of Sales Invoice
'PAYMENT', -- Actual payment 'PAYMENT', -- Actual payment
'DEPOSIT', 'DEPOSIT',
'AUTO_DEPOSIT', -- Fundamentally same as DEPOSIT
'WITHDRAWAL',
'CLOSE', -- Essentially an internal (not accounting) transaction 'CLOSE', -- Essentially an internal (not accounting) transaction
-- 'CREDIT', -- 'CREDIT',
-- 'REFUND', -- 'REFUND',
@@ -1080,7 +1077,6 @@ CREATE TABLE `pmgr_statement_entries` (
`type` ENUM('CHARGE', -- Invoiced Charge to Customer `type` ENUM('CHARGE', -- Invoiced Charge to Customer
'DISBURSEMENT', -- Disbursement of Receipt Funds 'DISBURSEMENT', -- Disbursement of Receipt Funds
'REVERSAL', -- Reversal of a charge 'REVERSAL', -- Reversal of a charge
'WRITEOFF', -- Write-off bad debt
'VOUCHER', -- Agreement to pay 'VOUCHER', -- Agreement to pay
'PAYMENT', -- Payment of a Voucher 'PAYMENT', -- Payment of a Voucher
'REFUND', -- Payment due to refund 'REFUND', -- Payment due to refund
@@ -1122,9 +1118,6 @@ CREATE TABLE `pmgr_statement_entries` (
-- Allow the disbursement to reconcile against the charge -- Allow the disbursement to reconcile against the charge
`charge_entry_id` INT(10) UNSIGNED DEFAULT NULL, `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, `comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
@@ -1149,9 +1142,6 @@ CREATE TABLE `pmgr_tender_types` (
-- include credit cards, debit cards, and ACH transfers. -- include credit cards, debit cards, and ACH transfers.
`tillable` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1, `tillable` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
-- Should these items be deposited automatically?
`auto_deposit` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
-- Names of the 4 data fields (or NULL if not used) -- Names of the 4 data fields (or NULL if not used)
-- Not the most robust of solutions, especially since -- Not the most robust of solutions, especially since
-- it requires (or strongly implicates) that all fields -- it requires (or strongly implicates) that all fields
@@ -1164,21 +1154,11 @@ CREATE TABLE `pmgr_tender_types` (
`data3_name` VARCHAR(80) DEFAULT NULL, `data3_name` VARCHAR(80) DEFAULT NULL,
`data4_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 -- When we accept legal tender of this form, where does
-- it go? Each type of legal tender can specify an -- it go? Each type of legal tender can specify an
-- account, either distinct or non-distinct from others -- account, either distinct or non-distinct from others
`account_id` INT(10) UNSIGNED NOT NULL, `account_id` INT(10) UNSIGNED NOT NULL,
-- Which account should these items be deposited in?
-- This may or may not actually be used for all types
-- but will likely get used for auto deposit items.
`deposit_account_id` INT(10) UNSIGNED DEFAULT NULL,
`comment` VARCHAR(255) DEFAULT NULL, `comment` VARCHAR(255) DEFAULT NULL,
@@ -1228,8 +1208,6 @@ CREATE TABLE `pmgr_tenders` (
`ledger_entry_id` INT(10) UNSIGNED NOT NULL, `ledger_entry_id` INT(10) UNSIGNED NOT NULL,
-- The ledger entry if this tender is marked NSF -- The ledger entry if this tender is marked NSF
`nsf_ledger_entry_id` INT(10) UNSIGNED DEFAULT NULL, `nsf_ledger_entry_id` INT(10) UNSIGNED DEFAULT NULL,
-- The ledger entry if this actual deposit transaction
`deposit_ledger_entry_id` INT(10) UNSIGNED DEFAULT NULL,
-- The deposit transaction that included these monies -- The deposit transaction that included these monies
`deposit_transaction_id` INT(10) UNSIGNED DEFAULT NULL, `deposit_transaction_id` INT(10) UNSIGNED DEFAULT NULL,
-- The NSF transaction coming back from the bank. -- The NSF transaction coming back from the bank.

View File

@@ -1,159 +0,0 @@
-- Delete bad transaction(s)
DELETE M
FROM
pmgr_ledger_entries LE,
pmgr_tenders M
WHERE
M.ledger_entry_id = LE.id AND
LE.transaction_id
IN (467);
DELETE LE
FROM
pmgr_ledger_entries LE
WHERE
LE.transaction_id
IN (467);
DELETE SE
FROM
pmgr_statement_entries SE
WHERE
SE.transaction_id
IN (467);
DELETE T
FROM
pmgr_transactions T
WHERE
T.id
IN (467);
-- Delete bad transaction, one variable setting
SET @tid = 467;
DELETE M FROM pmgr_ledger_entries LE, pmgr_tenders M
WHERE M.ledger_entry_id = LE.id AND LE.transaction_id = @tid;
DELETE LE FROM pmgr_ledger_entries LE
WHERE LE.transaction_id = @tid;
DELETE SE FROM pmgr_statement_entries SE
WHERE SE.transaction_id = @tid;
DELETE T FROM pmgr_transactions T
WHERE T.id = @tid;
-- Delete all but one customer
SET @cid = 6;
-- DELETE T FROM pmgr_transactions T
-- LEFT JOIN pmgr_customers C ON C.id = T.customer_id
-- WHERE C.id IS NOT NULL AND C.id <> @cid;
DELETE C FROM pmgr_customers C
WHERE C.id <> @cid;
DELETE L FROM pmgr_leases L
LEFT JOIN pmgr_customers C ON C.id = L.customer_id
WHERE C.id IS NULL;
DELETE T FROM pmgr_transactions T
LEFT JOIN pmgr_customers C ON C.id = T.customer_id
WHERE C.id IS NULL;
DELETE SE FROM pmgr_statement_entries SE
LEFT JOIN pmgr_customers C ON C.id = SE.customer_id
WHERE C.id IS NULL;
DELETE LE FROM pmgr_ledger_entries LE
LEFT JOIN pmgr_transactions T ON T.id = LE.transaction_id
WHERE T.id IS NULL;
DELETE M FROM pmgr_tenders M
LEFT JOIN pmgr_ledger_entries LE ON M.ledger_entry_id = LE.id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
WHERE LE.id IS NULL;
UPDATE pmgr_ledger_entries LE, pmgr_ledgers L, pmgr_accounts A
SET LE.ledger_id = L.id
WHERE A.id = LE.account_id AND L.account_id = A.id AND L.sequence = 1;
DELETE FROM pmgr_ledgers WHERE sequence > 1;
UPDATE pmgr_ledgers SET prior_ledger_id = NULL, close_transaction_id = NULL;
-- Delete a ledger entry, associated double entry, and matching ledger_entry
SET @leid = 1365;
DELETE FROM pmgr_ledger_entries WHERE id = @leid;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
WHERE LE.id IS NULL;
DELETE LE FROM pmgr_ledger_entries LE
LEFT JOIN pmgr_double_entries DE
ON DE.credit_entry_id = LE.id OR DE.debit_entry_id = LE.id
WHERE DE.id IS NULL;
-- Add and update every Tender.ledger_entry_id (for rolling up old databases)
-- Takes a while to complete (~30s at time of writing)
ALTER TABLE `pmgr_tenders`
ADD `deposit_ledger_entry_id` INT UNSIGNED DEFAULT NULL
AFTER `nsf_ledger_entry_id`;
UPDATE
pmgr_tenders Tnd
JOIN pmgr_tender_types TndT ON TndT.id = Tnd.tender_type_id
JOIN pmgr_transactions T ON T.id = Tnd.deposit_transaction_id
JOIN pmgr_ledger_entries LE ON LE.transaction_id = T.id AND LE.account_id = TndT.account_id
JOIN pmgr_double_entries DE ON DE.debit_entry_id = LE.id OR DE.credit_entry_id = LE.id
JOIN pmgr_ledger_entries LEd ON (DE.debit_entry_id = LEd.id OR DE.credit_entry_id = LEd.id)
AND LEd.id <> LE.id
SET Tnd.deposit_ledger_entry_id = LEd.id;
-- Add auto_deposit and deposit_account_id to tenders
ALTER TABLE `pmgr_tender_types`
ADD `auto_deposit` TINYINT(1) UNSIGNED DEFAULT '0' NOT NULL
AFTER `tillable`;
ALTER TABLE `pmgr_tender_types`
ADD `deposit_account_id` INTEGER(10) UNSIGNED DEFAULT NULL
AFTER `account_id`;
-- Determine economic conditions
SELECT `status`, COUNT(id), SUM(rent) FROM pmgr_units
GROUP BY `status` WITH ROLLUP;
-- Check that transaction totals add up correctly
SELECT T.id, T.type, T.amount,
-- T.type, A.type, E.crdr,
SUM(IF(E.account_id = T.account_id,
IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1),0)
*E.amount) AS Tamt,
SUM(IF(E.account_id = T.account_id,
0,IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1))
*E.amount) AS Oamt,
COUNT(E.id) AS Ecnt
FROM pmgr_transactions T
-- LEFT JOIN pmgr_statement_entries E ON E.transaction_id = T.id
LEFT JOIN pmgr_ledger_entries E ON E.transaction_id = T.id
LEFT JOIN pmgr_accounts A ON A.id = T.account_id -- E.account_id
-- WHERE
-- E.account_id != T.account_id
GROUP BY T.id
HAVING
(T.type = 'INVOICE' AND Tamt <> T.amount)
OR
(T.type <> 'INVOICE' AND Oamt <> T.amount)
OR
(Tamt * -1 <> Oamt)
-- Verify that statement entries all have the correct type
SELECT SE.id, SE.type, T.id, T.type
FROM pmgr_statement_entries SE
LEFT JOIN pmgr_transactions T ON T.id = SE.transaction_id
WHERE
((T.type = 'RECEIPT' OR T.type = 'CREDIT_NOTE') AND
SE.type NOT IN ('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS')
)
OR
((T.type = 'INVOICE' OR T.type = 'PAYMENT') AND
SE.type NOT IN ('CHARGE', 'PAYMENT', 'REFUND')
)
-- catch other types not considered in this query
OR T.type NOT IN ('RECEIPT', 'CREDIT_NOTE', 'INVOICE', 'PAYMENT')

View File

@@ -37,7 +37,7 @@ Operations to be functional
X - Create Customer ID/Account X - Create Customer ID/Account
X - Add Contact information to Customer X - Add Contact information to Customer
X - Move Customer into Unit X - Move Customer into Unit
X - Enter Rent Concessions given ? - Enter Rent Concessions given
X - Asses Rent Charges X - Asses Rent Charges
X - Asses Late Charges X - Asses Late Charges
X - Asses Security Deposits X - Asses Security Deposits
@@ -49,7 +49,7 @@ Operations to be functional
X - Handle NSF checks X - Handle NSF checks
X - Assess NSF Fees X - Assess NSF Fees
X - Determine Lease Paid-Through status X - Determine Lease Paid-Through status
X - Report: List of customers overdue - Report: List of customers overdue
X - Flag unit as overlocked X - Flag unit as overlocked
X - Flag unit as evicting X - Flag unit as evicting
X - Flag unit as normal status X - Flag unit as normal status

View File

@@ -5,7 +5,6 @@ use Data::Dumper;
use File::Copy; use File::Copy;
my $closing_one_transaction = 0; my $closing_one_transaction = 0;
my $work_from_scratch = 1;
# Internally adjust all numbers coming from the database to # Internally adjust all numbers coming from the database to
# be in inches. Not necessary to go to this detail, but the # be in inches. Not necessary to go to this detail, but the
@@ -544,18 +543,17 @@ foreach my $tender_name ('Cash', 'Check', 'Money Order', 'ACH',
) { ) {
my ($tillable, $fields) = (0, 0); my ($tillable, $fields) = (0, 0);
my ($name1, $name2, $name3, $name4); my ($name1, $name2, $name3, $name4);
my ($name_field) = ('id');
$tillable = 1 $tillable = 1
if ($tender_name =~ /^Cash|Check|Money Order$/); if ($tender_name =~ /^Cash|Check|Money Order$/);
($name1, $name_field) = ('Check Number', 'data1') ($name1) = ('Check Number')
if ($tender_name eq 'Check'); if ($tender_name eq 'Check');
($name1, $name_field) = ('Money Order Number', 'data1') ($name1) = ('Money Order Number')
if ($tender_name eq 'Money Order'); if ($tender_name eq 'Money Order');
($name1, $name2, $name3, $name_field) = ('Routing Number', 'Account Number', 'Batch Number', 'data3') ($name1, $name2) = ('Routing Number', 'Account Number')
if ($tender_name eq 'ACH'); if ($tender_name eq 'ACH');
($name1, $name2) = ('Debit Card Number', 'Expiration Date') ($name1, $name2) = ('Debit Card Number', 'Expiration Date')
@@ -567,14 +565,11 @@ foreach my $tender_name ('Cash', 'Check', 'Money Order', 'ACH',
addRow('tender_types', { addRow('tender_types', {
'name' => $tender_name, 'name' => $tender_name,
'account_id' => $newdb{'lookup'}{'account'}{$tender_name}{'account_id'}, 'account_id' => $newdb{'lookup'}{'account'}{$tender_name}{'account_id'},
'deposit_account_id' => $newdb{'lookup'}{'account'}{'Bank'}{'account_id'},
'tillable' => $tillable, 'tillable' => $tillable,
'auto_deposit' => ($tender_name eq 'ACH') ? 1 : 0,
'data1_name' => $name1, 'data1_name' => $name1,
'data2_name' => $name2, 'data2_name' => $name2,
'data3_name' => $name3, 'data3_name' => $name3,
'data4_name' => $name4, 'data4_name' => $name4,
'naming_field' => $name_field,
}); });
$newdb{'lookup'}{'tender_type'}{$tender_name} $newdb{'lookup'}{'tender_type'}{$tender_name}
@@ -966,7 +961,7 @@ foreach $row (@{query($sdbh, $query)}) {
'lease_date' => datefmt($row->{'DateIn'}), 'lease_date' => datefmt($row->{'DateIn'}),
'movein_date' => datefmt($row->{'DateIn'}), 'movein_date' => datefmt($row->{'DateIn'}),
'moveout_date' => datefmt($row->{'DateOut'}), 'moveout_date' => datefmt($row->{'DateOut'}),
#'close_date' => datefmt($row->{'DateClosed'}), 'close_date' => datefmt($row->{'DateClosed'}),
'rent' => $row->{'Rent'}, 'rent' => $row->{'Rent'},
#'comment' => "LedgerID: $row->{'LedgerID'}", #'comment' => "LedgerID: $row->{'LedgerID'}",
}); });
@@ -1210,6 +1205,8 @@ foreach $row (@{query($sdbh, $query)}) {
= $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'}; = $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'};
if ($SITELINK_ACCOUNT_TYPE{$row->{'PaymentType'}} eq 'Check') { 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'} $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'data1'}
= $row->{'CheckNum'}; = $row->{'CheckNum'};
} }
@@ -1471,7 +1468,7 @@ addRow('double_entries', {
###################################################################### ######################################################################
## Debug ... work from scratch ## Debug ... work from scratch
if ($work_from_scratch) { if (defined $work_from_scratch) {
# delete $newdb{'tables'}{'contacts'}{'rows'}; # delete $newdb{'tables'}{'contacts'}{'rows'};
# delete $newdb{'tables'}{'contacts_methods'}{'rows'}; # delete $newdb{'tables'}{'contacts_methods'}{'rows'};
# delete $newdb{'tables'}{'contacts_addresses'}{'rows'}; # delete $newdb{'tables'}{'contacts_addresses'}{'rows'};
@@ -1485,11 +1482,6 @@ if ($work_from_scratch) {
delete $newdb{'tables'}{'statement_entries'}{'rows'}; delete $newdb{'tables'}{'statement_entries'}{'rows'};
delete $newdb{'tables'}{'tenders'}{'rows'}; delete $newdb{'tables'}{'tenders'}{'rows'};
delete $newdb{'tables'}{'transactions'}{'rows'}; delete $newdb{'tables'}{'transactions'}{'rows'};
foreach (@{$newdb{'tables'}{'units'}{'rows'}}) {
$_->{'status'} = 'VACANT'
if defined $_ && ($_->{'status'} =~ /^(OCCUPIED)$/ || $_->{'name'} =~ /^Y/);
}
} }
@@ -1578,26 +1570,3 @@ $query = "UPDATE pmgr_transactions T, pmgr_ledger_entries E
WHERE E.transaction_id = T.id AND E.account_id = T.account_id"; WHERE E.transaction_id = T.id AND E.account_id = T.account_id";
query($db_handle, $query); 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);

View File

@@ -38,95 +38,28 @@ class AppController extends Controller {
var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid'); var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid');
var $components = array('DebugKit.Toolbar'); var $components = array('DebugKit.Toolbar');
function __construct() {
$this->params['dev'] = false;
$this->params['admin'] = false;
parent::__construct();
}
function sideMenuLinks() { function sideMenuLinks() {
// Stupid Cake... our constructor sets admin/dev, return array(
// but cake stomps it somewhere along the way array('name' => 'Common', 'header' => true),
// after constructing the CakeError controller. array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)),
if ($this->name === 'CakeError') { array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')),
$this->params['dev'] = false; array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index')),
$this->params['admin'] = false; array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')),
} array('name' => 'Accounts', 'url' => array('controller' => 'accounts', 'action' => 'index')),
array('name' => 'Debug', 'header' => true),
$menu = array(); array('name' => 'Un-Nuke', 'url' => '#', 'htmlAttributes' =>
$menu[] = array('name' => 'Common', 'header' => true); array('onclick' => '$(".pr-section").show(); return false;')),
$menu[] = array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)); array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index')),
$menu[] = array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')); array('name' => 'Ledgers', 'url' => array('controller' => 'ledgers', 'action' => 'index')),
$menu[] = array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index')); array('name' => 'New Ledgers', 'url' => array('controller' => 'accounts', 'action' => 'newledger')),
$menu[] = array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')); array('name' => 'RESET DATA', 'url' => array('controller' => 'accounts', 'action' => 'reset_data')),
$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() { function beforeRender() {
$this->set('sidemenu', $this->sideMenuLinks()); $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() { function reset_data() {
$this->layout = null; $this->layout = null;
$this->autoLayout = false; $this->autoLayout = false;
@@ -228,10 +161,16 @@ class AppController extends Controller {
} }
function gridDataSetup(&$params) { function gridDataSetup(&$params) {
// Debug only if requested // Assume we're debugging.
$params['debug'] = !empty($this->passedArgs['debug']); // The actual grid request will set this to false
$debug = true;
if ($params['debug']) { if (isset($this->passedArgs['debug']))
$debug = $this->passedArgs['debug'];
$params['debug'] = $debug;
if ($debug) {
ob_start(); ob_start();
} }
else { else {
@@ -713,7 +652,7 @@ class AppController extends Controller {
foreach ($records AS &$record) { foreach ($records AS &$record) {
// Add the calculated fields (if any), to the model fields // Add the calculated fields (if any), to the model fields
if (isset($record[0])) { if (isset($record[0])) {
$record[$model_alias] = $record[0] + $record[$model_alias]; $record[$model_alias] += $record[0];
unset($record[0]); unset($record[0]);
} }
} }
@@ -755,12 +694,9 @@ class AppController extends Controller {
if (isset($params['post']['nolinks'])) if (isset($params['post']['nolinks']))
return; return;
App::import('Helper', 'Html');
foreach ($links AS $table => $fields) { foreach ($links AS $table => $fields) {
$special = array('controller', 'action', 'id'); $special = array('controller', 'id');
$controller = Inflector::pluralize(Inflector::underscore($table)); $controller = Inflector::pluralize(Inflector::underscore($table));
$action = 'view';
$id = 'id'; $id = 'id';
extract(array_intersect_key($fields, array_flip($special))); extract(array_intersect_key($fields, array_flip($special)));
foreach ($records AS &$record) { foreach ($records AS &$record) {
@@ -775,8 +711,8 @@ class AppController extends Controller {
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record'); //$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
$record[$table][$field] = $record[$table][$field] =
'<A HREF="' . '<A HREF="' .
HtmlHelper::url(array('controller' => $controller, Router::url(array('controller' => $controller,
'action' => $action, 'action' => 'view',
$record[$table][$id])) . $record[$table][$id])) .
'">' . '">' .
$record[$table][$field] . $record[$table][$field] .
@@ -867,15 +803,5 @@ class AppController extends Controller {
echo " <cell><![CDATA[$data]]></cell>\n"; 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');
}
} }
?> ?>

View File

@@ -37,14 +37,5 @@ App::import('Core', 'Helper');
* @subpackage cake.cake * @subpackage cake.cake
*/ */
class AppHelper extends Helper { 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);
}
} }
?> ?>

View File

@@ -402,10 +402,6 @@ 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) { function recursive_array_replace($find, $replace, &$data) {
if (!isset($data)) if (!isset($data))
return; return;
@@ -480,12 +476,4 @@ class AppModel extends Model {
return date('Y-m-d', strtotime($dateString)); 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();
}
} }

View File

@@ -32,17 +32,16 @@
* *
*/ */
function INTERNAL_ERROR($message, $exit = true, $drop = 0) { function INTERNAL_ERROR($message) {
echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">' . "\n"; echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">';
echo '<H1 style="color:#000; margin-bottom:0.2em; font-size:2em;">INTERNAL ERROR:</H1>' . "\n"; echo '<H1 style="margin-bottom:0.2em">INTERNAL ERROR:</H1>';
echo '<H2 style="color:#000; margin-top:0; margin-left:1.5em; font-size:1.5em">' . $message . '</H2>' . "\n"; echo '<H2 style="margin-top:0; margin-left:1.5em">' . $message . '</H2>';
echo '<H4 style="color:#000;">This error was not caused by anything that you did wrong.' . "\n"; echo '<H4>This error was not caused by anything that you did wrong.';
echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>' . "\n"; echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>';
// Print out the entire stack trace // Print out the entire stack trace
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nStack Trace:\n"; echo "<HR>Stack Trace:<OL>";
echo '<OL style="margin-left:1.5em";>' . "\n"; $trace = debug_backtrace(false);
$trace = array_slice(debug_backtrace(false), $drop);
for ($i = 0; $i < count($trace); ++$i) { for ($i = 0; $i < count($trace); ++$i) {
$bline = $trace[$i]['line']; $bline = $trace[$i]['line'];
$bfile = $trace[$i]['file']; $bfile = $trace[$i]['file'];
@@ -59,15 +58,9 @@ function INTERNAL_ERROR($message, $exit = true, $drop = 0) {
echo("<LI>$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")</LI>\n"); echo("<LI>$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")</LI>\n");
} }
echo "</OL>\n"; echo '</OL>';
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>'; echo '</DIV>';
if ($exit)
die(); die();
} }

View File

@@ -27,29 +27,11 @@
* @license http://www.opensource.org/licenses/mit-license.php The MIT License * @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/ */
$default_path = array('controller' => 'maps', 'action' => 'view', '1');
/** /**
* Here, we are connecting '/' (base path) to our site map. * Here, we are connecting '/' (base path) to our site map.
* It's hardcoded to map #1, but at some point we'll implement * 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. * a login mechanism and the default path will be to log on instead.
*/ */
Router::connect('/', $default_path); Router::connect('/', array('controller' => 'maps', 'action' => 'view', '1'));
/*
* Route for admin functionality
*/
Router::connect('/admin',
array('admin_route' => true) + $default_path);
Router::connect('/admin/:controller/:action/*',
array('admin_route' => true, 'action' => null));
/*
* Route for development functionality
*/
Router::connect('/dev',
array('dev_route' => true) + $default_path);
Router::connect('/dev/:controller/:action/*',
array('dev_route' => true, 'action' => null));
?> ?>

View File

@@ -12,6 +12,9 @@ class AccountsController extends AppController {
array('name' => 'Equity', 'url' => array('controller' => 'accounts', 'action' => 'equity')), array('name' => 'Equity', 'url' => array('controller' => 'accounts', 'action' => 'equity')),
array('name' => 'Income', 'url' => array('controller' => 'accounts', 'action' => 'income')), array('name' => 'Income', 'url' => array('controller' => 'accounts', 'action' => 'income')),
array('name' => 'Expense', 'url' => array('controller' => 'accounts', 'action' => 'expense')), 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')),
); );
@@ -90,10 +93,6 @@ class AccountsController extends AppController {
$conditions[] = array('Account.type' => strtoupper($params['action'])); $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; return $conditions;
} }
@@ -143,9 +142,12 @@ class AccountsController extends AppController {
$account = $this->Account->read(null, $id); $account = $this->Account->read(null, $id);
$account = $account['Account']; $account = $account['Account'];
$accounts = $this->Account->collectableAccounts(); $payment_accounts = $this->Account->collectableAccounts();
$payment_accounts = $accounts['all']; //$payment_accounts[$this->Account->nameToID('Closing')] = 'Closing';
$default_accounts = $accounts['default']; //$payment_accounts[$this->Account->nameToID('Equity')] = 'Equity';
//$payment_accounts[$id] = 'Reversals';
$default_accounts = array_diff_key($this->Account->receiptAccounts(),
array($this->Account->concessionAccountID() => 1));
$this->set(compact('payment_accounts', 'default_accounts')); $this->set(compact('payment_accounts', 'default_accounts'));
$title = ($account['name'] . ': Collected Report'); $title = ($account['name'] . ': Collected Report');
@@ -161,6 +163,12 @@ class AccountsController extends AppController {
*/ */
function view($id = null) { 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 $account = $this->Account->find
('first', ('first',
array('contain' => array('contain' =>
@@ -172,18 +180,14 @@ class AccountsController extends AppController {
array('CloseTransaction' => array array('CloseTransaction' => array
('order' => array('CloseTransaction.stamp' => 'DESC'))), ('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),
),
) )
); );
if (empty($account)) { // Get all ledger entries of the CURRENT ledger
$this->Session->setFlash(__('Invalid Item.', true)); $entries = $this->Account->ledgerEntries($id);
$this->redirect(array('action'=>'index')); //pr(compact('entries'));
} $account['CurrentLedger']['LedgerEntry'] = $entries;
// Obtain stats across ALL ledgers for the summary infobox // Obtain stats across ALL ledgers for the summary infobox
$stats = $this->Account->stats($id, true); $stats = $this->Account->stats($id, true);
@@ -201,4 +205,8 @@ class AccountsController extends AppController {
$this->set(compact('account', 'title', 'stats')); $this->set(compact('account', 'title', 'stats'));
} }
function tst($id) {
//$entries = $this->Account->($id);
pr($entries);
}
} }

View File

@@ -126,6 +126,8 @@ class ContactsController extends AppController {
// Now that the work is done, let the user view the updated contact // Now that the work is done, let the user view the updated contact
$this->redirect(array('action'=>'view', $this->data['Contact']['id'])); $this->redirect(array('action'=>'view', $this->data['Contact']['id']));
//$this->render('/empty');
return;
} }
if ($id) { if ($id) {

View File

@@ -202,19 +202,7 @@ class CustomersController extends AppController {
)); ));
//pr($customer); //pr($customer);
// 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 // Figure out the outstanding balances for this customer
//$this->set('stats', $this->Customer->stats($id));
$outstanding_balance = $this->Customer->balance($id); $outstanding_balance = $this->Customer->balance($id);
$outstanding_deposit = $this->Customer->securityDepositBalance($id); $outstanding_deposit = $this->Customer->securityDepositBalance($id);
@@ -249,17 +237,12 @@ class CustomersController extends AppController {
/* $id)); */ /* $id)); */
/* } */ /* } */
if ($show_payment || $outstanding_balance > 0) if ($show_payment) {
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'New Receipt', array('name' => 'Payment',
'url' => array('action' => 'receipt', 'url' => array('action' => 'receipt',
$id)); $id));
}
if (!$show_moveout && $outstanding_balance > 0)
$this->sidemenu_links[] =
array('name' => 'Write-Off',
'url' => array('action' => 'bad_debt',
$id));
if ($outstanding_balance < 0) if ($outstanding_balance < 0)
$this->sidemenu_links[] = $this->sidemenu_links[] =
@@ -287,20 +270,23 @@ class CustomersController extends AppController {
if (isset($this->params['form']['cancel'])) { if (isset($this->params['form']['cancel'])) {
if (isset($this->data['Customer']['id'])) if (isset($this->data['Customer']['id']))
$this->redirect(array('action'=>'view', $this->data['Customer']['id'])); $this->redirect(array('action'=>'view', $this->data['Customer']['id']));
else
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
return;
} }
// Make sure we have at least one contact // Make sure we have at least one contact
if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) { if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) {
$this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true); $this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true);
$this->redirect(array('action'=>'view', $this->data['Customer']['id'])); $this->redirect(array('action'=>'view', $this->data['Customer']['id']));
return;
} }
// Make sure there is a primary contact // Make sure there is a primary contact
if (!isset($this->data['Customer']['primary_contact_entry'])) { if (!isset($this->data['Customer']['primary_contact_entry'])) {
$this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true); $this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true);
$this->redirect(array('action'=>'view', $this->data['Customer']['id'])); $this->redirect(array('action'=>'view', $this->data['Customer']['id']));
return;
} }
// Go through each customer and strip the bogus ID if new // Go through each customer and strip the bogus ID if new
@@ -317,46 +303,21 @@ class CustomersController extends AppController {
pr("CUSTOMER SAVE FAILED"); pr("CUSTOMER SAVE FAILED");
} }
// If existing customer, then view it. // If existing customer, then view it. Otherwise, since
// this is a new customer, go to the move in screen.
if ($this->data['Customer']['id']) if ($this->data['Customer']['id'])
$this->redirect(array('action'=>'view', $this->Customer->id)); $this->redirect(array('action'=>'view', $this->Customer->id));
else
// Since this is a new customer, go to the move in screen.
$this->redirect(array('action'=>'move_in', $this->Customer->id)); $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;
} }
if ($id) { if ($id) {
// REVISIT <AP>: 20090816 $this->data = $this->Customer->details($id);
// This should never need to be done by a controller.
// However, until things stabilize, this gives the
// user a way to update any cached items on the
// customer, by just clicking Edit then Cancel.
$this->Customer->update($id);
// 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'),
),
),
),
'conditions' => array('Customer.id' => $id),
));
$this->data = $customer;
$title = 'Customer: ' . $this->data['Customer']['name'] . " : Edit"; $title = 'Customer: ' . $this->data['Customer']['name'] . " : Edit";
} }
else { else {
@@ -401,9 +362,20 @@ class CustomersController extends AppController {
$this->Customer->recursive = -1; $this->Customer->recursive = -1;
$customer = $this->Customer->read(null, $id); $customer = $this->Customer->read(null, $id);
$customer = $customer['Customer']; $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 { else {
$customer = null; $customer = null;
$charges = array();
$stats = array('balance' => 0);
} }
$TT = new TenderType(); $TT = new TenderType();
@@ -412,7 +384,7 @@ class CustomersController extends AppController {
$this->set(compact('payment_types', 'default_type')); $this->set(compact('payment_types', 'default_type'));
$title = ($customer['name'] . ': Receipt Entry'); $title = ($customer['name'] . ': Receipt Entry');
$this->set(compact('customer', 'title')); $this->set(compact('customer', 'charges', 'stats', 'title'));
} }
@@ -423,64 +395,64 @@ class CustomersController extends AppController {
* - Refunds customer charges * - Refunds customer charges
*/ */
function refund($id) { function refund() {
$customer = $this->Customer->find $entries = $this->Customer->StatementEntry->find
('first', array ('all', array
('contain' => false, ('contain' => false,
'conditions' => array(array('Customer.id' => $id), 'conditions' => array('StatementEntry.id' =>
//array(199,200,201)
61
), ),
)); ));
if (empty($customer)) { pr(compact('entries'));
$this->redirect(array('action'=>'view', $id));
}
// Determine the customer balance, bailing if the customer owes money $this->Customer->refund($entries);
$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: bad_debt * action: unreconciled
* - Sets up the write-off entry page, so that the * - returns the list of unreconciled entries
* user can write off remaining charges of a customer.
*/ */
function bad_debt($id) { function unreconciled($id) {
$this->Customer->id = $id;
$customer = $this->Customer->find
('first', array
('contain' => false,
));
// Make sure we have a valid customer to write off //$this->layout = 'ajax';
if (empty($customer)) $this->layout = null;
$this->redirect(array('action' => 'index')); $this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
header("Content-type: text/xml;charset=utf-8");
// Get the customer balance App::import('Helper', 'Xml');
$balance = $this->Customer->balance($id); $xml = new XmlHelper();
// Prepare to render // Find the unreconciled entries, then manipulate the structure
$title = ($customer['Customer']['name'] . ': Write Off Bad Debt'); // slightly to accomodate the format necessary for XML Helper.
$this->set(compact('title', 'customer', 'balance')); $unreconciled = $this->Customer->unreconciledCharges($id);
$this->render('/transactions/bad_debt');
foreach ($unreconciled['entries'] AS &$entry)
$entry = array_intersect_key($entry['StatementEntry'],
array('id'=>1));
$unreconciled = array('entries' =>
array('entry' => $unreconciled['entries'],
'balance' => $unreconciled['summary']['balance']));
// XML Helper will dump an empty tag if the array is empty
if (empty($unreconciled['entries']['entry']))
unset($unreconciled['entries']['entry']);
/* pr(compact('unreconciled')); */
/* echo htmlspecialchars($xml->serialize($unreconciled)); */
/* $this->render('/fake'); */
$opts = array();
//$opts['format'] = 'tags';
echo $xml->header();
echo $xml->serialize($unreconciled, $opts);
} }
} }

View File

@@ -36,28 +36,6 @@ class DoubleEntriesController extends AppController {
'conditions' => array('DoubleEntry.id' => $id), '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. // Prepare to render.
$title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}"; $title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}";
$this->set(compact('entry', 'title')); $this->set(compact('entry', 'title'));

View File

@@ -6,7 +6,6 @@ class LeasesController extends AppController {
array(array('name' => 'Leases', 'header' => true), array(array('name' => 'Leases', 'header' => true),
array('name' => 'Active', 'url' => array('controller' => 'leases', 'action' => 'active')), array('name' => 'Active', 'url' => array('controller' => 'leases', 'action' => 'active')),
array('name' => 'Closed', 'url' => array('controller' => 'leases', 'action' => 'closed')), 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')), array('name' => 'All', 'url' => array('controller' => 'leases', 'action' => 'all')),
); );
@@ -31,7 +30,6 @@ class LeasesController extends AppController {
function index() { $this->all(); } function index() { $this->all(); }
function active() { $this->gridView('Active Leases'); } function active() { $this->gridView('Active Leases'); }
function delinquent() { $this->gridView('Delinquent Leases'); }
function closed() { $this->gridView('Closed Leases'); } function closed() { $this->gridView('Closed Leases'); }
function all() { $this->gridView('All Leases', 'all'); } function all() { $this->gridView('All Leases', 'all'); }
@@ -65,8 +63,6 @@ class LeasesController extends AppController {
function gridDataFields(&$params, &$model) { function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model); $fields = parent::gridDataFields($params, $model);
$fields[] = ("IF(" . $this->Lease->conditionDelinquent() . "," .
" 'DELINQUENT', 'CURRENT') AS 'status'");
return array_merge($fields, return array_merge($fields,
$this->Lease->StatementEntry->chargeDisbursementFields(true)); $this->Lease->StatementEntry->chargeDisbursementFields(true));
} }
@@ -77,9 +73,6 @@ class LeasesController extends AppController {
if ($params['action'] === 'active') { if ($params['action'] === 'active') {
$conditions[] = 'Lease.close_date IS NULL'; $conditions[] = 'Lease.close_date IS NULL';
} }
elseif ($params['action'] === 'delinquent') {
$conditions[] = $this->Lease->conditionDelinquent();
}
elseif ($params['action'] === 'closed') { elseif ($params['action'] === 'closed') {
$conditions[] = 'Lease.close_date IS NOT NULL'; $conditions[] = 'Lease.close_date IS NOT NULL';
} }
@@ -142,22 +135,21 @@ class LeasesController extends AppController {
// Handle the move in based on the data given // Handle the move in based on the data given
//pr(array('Move-in data', $this->data)); //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'], $lid = $this->Lease->moveIn($this->data['Lease']['customer_id'],
$this->data['Lease']['unit_id'], $this->data['Lease']['unit_id'],
$this->data['Lease']['deposit'], null, null,
$this->data['Lease']['rent'],
$this->data['Lease']['movein_date'], $this->data['Lease']['movein_date'],
$this->data['Lease']['comment'] $this->data['Lease']['comment']
); );
// Since this is a new lease, go to the invoice // Since this is a new lease, go to the invoice
// screen so we can start assessing charges. // screen so we can start assessing charges.
$this->redirect(array('action'=>'invoice', $lid, 'move-in')); $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');
} }
/************************************************************************** /**************************************************************************
@@ -174,7 +166,9 @@ class LeasesController extends AppController {
$this->Lease->moveOut($this->data['Lease']['id'], $this->Lease->moveOut($this->data['Lease']['id'],
'VACANT', 'VACANT',
$this->data['Lease']['moveout_date'] $this->data['Lease']['moveout_date'],
//true // Close this lease, if able
false
); );
$this->redirect($this->data['redirect']); $this->redirect($this->data['redirect']);
@@ -227,6 +221,8 @@ class LeasesController extends AppController {
/* function promote_surplus($id) { */ /* function promote_surplus($id) { */
/* $this->Lease->promoteSurplus($id); */ /* $this->Lease->promoteSurplus($id); */
/* pr("PREVENTING REDIRECT"); */
/* $this->render('fake'); */
/* $this->redirect(array('controller' => 'leases', */ /* $this->redirect(array('controller' => 'leases', */
/* 'action' => 'view', */ /* 'action' => 'view', */
/* $id)); */ /* $id)); */
@@ -277,7 +273,6 @@ class LeasesController extends AppController {
$lease['Unit']['name'] . ': ' . $lease['Unit']['name'] . ': ' .
$lease['Customer']['name'] . ': Refund'); $lease['Customer']['name'] . ': Refund');
$this->set(compact('title', 'lease', 'balance')); $this->set(compact('title', 'lease', 'balance'));
$this->render('/transactions/refund');
} }
@@ -290,7 +285,6 @@ class LeasesController extends AppController {
*/ */
function bad_debt($id) { function bad_debt($id) {
$this->Lease->id = $id;
$lease = $this->Lease->find $lease = $this->Lease->find
('first', array ('first', array
('contain' => array ('contain' => array
@@ -298,14 +292,20 @@ class LeasesController extends AppController {
'Unit' => array('fields' => array('id', 'name')), 'Unit' => array('fields' => array('id', 'name')),
'Customer' => 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),
),
)); ));
// Make sure we have a valid lease to write off // Make sure we have a valid lease to write off
if (empty($lease)) if (empty($lease))
$this->redirect(array('action' => 'view', $id)); $this->redirect(array('action' => 'view', $id));
// Get the lease balance // Get the lease balance, part of lease stats
$balance = $this->Lease->balance($id); $stats = $this->Lease->stats($id);
$balance = $stats['balance'];
// Prepare to render // Prepare to render
$title = ('Lease #' . $lease['Lease']['number'] . ': ' . $title = ('Lease #' . $lease['Lease']['number'] . ': ' .
@@ -323,23 +323,9 @@ class LeasesController extends AppController {
* - Closes a lease to any further action * - 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) { function close($id) {
// REVISIT <AP>: 20090708 // REVISIT <AP>: 20090708
// We should probably seek confirmation first... // 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->Lease->close($id);
$this->redirect(array('action'=>'view', $id)); $this->redirect(array('action'=>'view', $id));
} }
@@ -376,30 +362,13 @@ class LeasesController extends AppController {
$A = new Account(); $A = new Account();
$charge_accounts = $A->invoiceAccounts(); $charge_accounts = $A->invoiceAccounts();
$default_account = $A->rentAccountID(); $default_account = $A->rentAccountID();
$rent_account = $A->rentAccountID(); $this->set(compact('charge_accounts', 'default_account'));
$security_deposit_account = $A->securityDepositAccountID();
$this->set(compact('charge_accounts', 'default_account',
'rent_account', 'security_deposit_account'));
// REVISIT <AP> 20090705: // REVISIT <AP> 20090705:
// Of course, the late charge should come from the late_schedule // Of course, the late charge should come from the late_schedule
$default_rent = $lease['Lease']['rent'];
$default_late = 10; $default_late = 10;
$this->set(compact('default_late')); $this->set(compact('default_rent', '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'] . ': ' . $title = ('Lease #' . $lease['Lease']['number'] . ': ' .
$lease['Unit']['name'] . ': ' . $lease['Unit']['name'] . ': ' .
@@ -408,27 +377,6 @@ 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'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -447,26 +395,26 @@ class LeasesController extends AppController {
('first', ('first',
array('contain' => array('contain' =>
array(// Models array(// Models
'LeaseType(id,name)', 'LeaseType',
'Unit(id,name)', 'Unit',
'Customer(id,name)', 'Customer',
), ),
'fields' => array('Lease.*', $this->Lease->delinquentField()),
'conditions' => array(array('Lease.id' => $id)), 'conditions' => array(array('Lease.id' => $id)),
) )
); );
$lease['Lease'] += $lease[0];
unset($lease[0]); $lease['Lease']['paid_through'] = $this->Lease->rentPaidThrough($id);
$this->set('charge_gaps', $this->Lease->rentChargeGaps($id));
$this->set('charge_through', $this->Lease->rentChargeThrough($id));
// Figure out the outstanding balances for this lease // Figure out the outstanding balances for this lease
$outstanding_balance = $this->Lease->balance($id); $outstanding_balance = $this->Lease->balance($id);
$outstanding_deposit = $this->Lease->securityDepositBalance($id); $outstanding_deposit = $this->Lease->securityDepositBalance($id);
// Set up dynamic menu items. Normally, these will only be present // Set up dynamic menu items
// on an open lease, but it's possible for a lease to be closed, and if (!isset($lease['Lease']['close_date'])) {
// 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[] = $this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true); array('name' => 'Operations', 'header' => true);
@@ -475,13 +423,12 @@ class LeasesController extends AppController {
array('name' => 'Move-Out', 'url' => array('action' => 'move_out', array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
$id)); $id));
if (!isset($lease['Lease']['close_date']))
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'New Invoice', 'url' => array('action' => 'invoice', array('name' => 'Charges', 'url' => array('action' => 'invoice',
$id)); $id));
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'New Receipt', 'url' => array('controller' => 'customers', array('name' => 'Payments', 'url' => array('controller' => 'customers',
'action' => 'receipt', 'action' => 'receipt',
$lease['Customer']['id'])); $lease['Customer']['id']));
@@ -490,19 +437,10 @@ class LeasesController extends AppController {
/* array('name' => 'Transfer Credit to Customer', */ /* array('name' => 'Transfer Credit to Customer', */
/* 'url' => array('action' => 'promote_surplus', $id)); */ /* 'url' => array('action' => 'promote_surplus', $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) if ($outstanding_balance < 0)
$this->INTERNAL_ERROR("Should not have a customer lease credit."); $this->sidemenu_links[] =
array('name' => 'Issue Refund',
/* if ($outstanding_balance < 0) */ 'url' => array('action' => 'refund', $id));
/* $this->sidemenu_links[] = */
/* array('name' => 'Issue Refund', */
/* 'url' => array('action' => 'refund', $id)); */
if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0) if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0)
$this->sidemenu_links[] = $this->sidemenu_links[] =

View File

@@ -145,6 +145,12 @@ class LedgerEntriesController extends AppController {
*/ */
function view($id = null) { 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 $entry = $this->LedgerEntry->find
('first', ('first',
array('contain' => array array('contain' => array
@@ -157,10 +163,6 @@ class LedgerEntriesController extends AppController {
array('fields' => array('id', 'sequence', 'name'), array('fields' => array('id', 'sequence', 'name'),
'Account' => 'Account' =>
array('fields' => array('id', 'name', 'type'), array('fields' => array('id', 'name', 'type'),
'conditions' =>
// REVISIT <AP>: 20090811
// No security issues have been worked out yet
array('Account.level >=' => 5),
), ),
), ),
@@ -168,9 +170,6 @@ class LedgerEntriesController extends AppController {
array('fields' => array('id', 'name'), array('fields' => array('id', 'name'),
), ),
'DebitDoubleEntry' => array('id'),
'CreditDoubleEntry' => array('id'),
'DebitEntry' => array('fields' => array('id', 'crdr')), 'DebitEntry' => array('fields' => array('id', 'crdr')),
'CreditEntry' => array('fields' => array('id', 'crdr')), 'CreditEntry' => array('fields' => array('id', 'crdr')),
), ),
@@ -178,11 +177,6 @@ class LedgerEntriesController extends AppController {
'conditions' => array('LedgerEntry.id' => $id), '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'])) if (!empty($entry['DebitEntry']) && !empty($entry['CreditEntry']))
die("LedgerEntry has both a matching DebitEntry and CreditEntry"); die("LedgerEntry has both a matching DebitEntry and CreditEntry");
if (empty($entry['DebitEntry']) && empty($entry['CreditEntry'])) if (empty($entry['DebitEntry']) && empty($entry['CreditEntry']))
@@ -197,18 +191,6 @@ class LedgerEntriesController extends AppController {
else else
$entry['MatchingEntry'] = $entry['DebitEntry'][0]; $entry['MatchingEntry'] = $entry['DebitEntry'][0];
if (empty($entry['DebitDoubleEntry']['id']))
$entry['DoubleEntry'] = $entry['CreditDoubleEntry'];
else
$entry['DoubleEntry'] = $entry['DebitDoubleEntry'];
// REVISIT <AP>: 20090816
// This page doesn't seem very useful, let's just keep it
// all to the double entry view.
$this->redirect(array('controller' => 'double_entries',
'action' => 'view',
$entry['DoubleEntry']['id']));
// Prepare to render. // Prepare to render.
$title = "Ledger Entry #{$entry['LedgerEntry']['id']}"; $title = "Ledger Entry #{$entry['LedgerEntry']['id']}";
$this->set(compact('entry', 'title')); $this->set(compact('entry', 'title'));

View File

@@ -50,21 +50,24 @@ class LedgersController extends AppController {
} }
function gridDataCountTables(&$params, &$model) { 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 return array
('link' => ('link' =>
array(// Models array(// Models
'Account', 'Account',
'LedgerEntry',
'CloseTransaction',
), ),
); );
} }
function gridDataTables(&$params, &$model) {
$tables = $this->gridDataCountTables($params, $model);
$tables['link'][] = 'LedgerEntry';
$tables['link'][] = 'CloseTransaction';
return $tables;
}
function gridDataFields(&$params, &$model) { function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model); $fields = parent::gridDataFields($params, $model);
$fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence'; $fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence';
@@ -82,10 +85,6 @@ class LedgersController extends AppController {
$conditions[] = array('Ledger.close_transaction_id !=' => null); $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; return $conditions;
} }
@@ -120,25 +119,22 @@ class LedgersController extends AppController {
*/ */
function view($id = null) { 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 $ledger = $this->Ledger->find
('first', ('first',
array('contain' => array('contain' =>
array(// Models array(// Models
'Account', '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 // Get ledger stats for our summary box
$stats = $this->Ledger->stats($id); $stats = $this->Ledger->stats($id);

View File

@@ -85,34 +85,10 @@ class MapsController extends AppController {
'units' => array()); 'units' => array());
// Find all of the map/unit information from this SiteArea // Find all of the map/unit information from this SiteArea
$map = $this->Map->find('first', array('contain' => false, $this->Map->recursive = 2;
'conditions' => array('id' => $id))); $this->Map->SiteArea->unbindModel(array('hasOne' => array('Map')));
$map = $this->Map->read(null, $id);
$units = $this->Map->Unit->find //pr($map);
('all',
array('link' =>
array('Map' =>
array('fields' => array()),
'CurrentLease' =>
array('fields' => array('id', 'paid_through_date',
$this->Map->Unit->CurrentLease->
delinquentField('CurrentLease')),
'Customer'),
'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 * The preference would be to leave all things "screen" related
@@ -137,7 +113,7 @@ class MapsController extends AppController {
$info['depth'] = $bottom * $screen_adjustment_factor; $info['depth'] = $bottom * $screen_adjustment_factor;
// Go through each unit in the map, calculating the map location // Go through each unit in the map, calculating the map location
foreach ($units AS $unit) { foreach ($map['Unit'] AS $unit) {
$lft = $unit['MapsUnit']['pt_left'] + $boundary_adjustment; $lft = $unit['MapsUnit']['pt_left'] + $boundary_adjustment;
$top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment; $top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment;
@@ -156,9 +132,10 @@ class MapsController extends AppController {
$width *= $screen_adjustment_factor; $width *= $screen_adjustment_factor;
$depth *= $screen_adjustment_factor; $depth *= $screen_adjustment_factor;
//$info['units'][$unit['id']] =
$info['units'][] = $info['units'][] =
array( 'id' => $unit['Unit']['id'], array( 'id' => $unit['id'],
'name' => $unit['Unit']['name'], 'name' => $unit['name'],
'left' => $lft, 'left' => $lft,
'right' => $lft + $width, 'right' => $lft + $width,
'top' => $top, 'top' => $top,
@@ -166,15 +143,11 @@ class MapsController extends AppController {
'width' => $width, 'width' => $width,
'depth' => $depth, 'depth' => $depth,
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1, 'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
'status' => (($unit['Unit']['status'] === 'OCCUPIED' && 'status' => $unit['status']
!empty($unit[0]['delinquent']))
? 'LATE' : $unit['Unit']['status']),
'data' => $unit,
); );
} }
/* pr($info); */ //pr($info);
/* $this->render('/empty'); exit(); */
return $info; return $info;
} }
@@ -187,10 +160,8 @@ class MapsController extends AppController {
*/ */
function legend($id = null, $requested_width = 400) { function legend($id = null, $requested_width = 400) {
$status = array_keys($this->Map->Unit->activeStatusEnums()); $status = $this->Map->Unit->activeStatusEnums();
$occupied_key = array_search('OCCUPIED', $status); //pr($status);
array_splice($status, $occupied_key+1, 0, array('LATE'));
$rows = 2; $rows = 2;
$cols = (int)((count($status) + $rows - 1) / $rows); $cols = (int)((count($status) + $rows - 1) / $rows);
@@ -220,7 +191,7 @@ class MapsController extends AppController {
$item_width *= $screen_adjustment_factor; $item_width *= $screen_adjustment_factor;
$item_depth *= $screen_adjustment_factor; $item_depth *= $screen_adjustment_factor;
foreach ($status AS $code) { foreach ($status AS $code => $value) {
$info['units'][] = array('name' => $code, $info['units'][] = array('name' => $code,
'status' => $code, 'status' => $code,
'width' => $item_width, 'width' => $item_width,
@@ -270,9 +241,9 @@ class MapsController extends AppController {
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192); $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']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255); $info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192); $info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
$info['palate']['unit']['LOCKED']['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' => 0, 'blue' => 128); $info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
// Determine text color to go with each background // Determine text color to go with each background
foreach ($info['palate']['unit'] AS &$code) { foreach ($info['palate']['unit'] AS &$code) {

View File

@@ -35,7 +35,7 @@ class StatementEntriesController extends AppController {
* to jqGrid. * to jqGrid.
*/ */
function gridDataCountTables(&$params, &$model) { function gridDataTables(&$params, &$model) {
$link = $link =
array(// Models array(// Models
'Transaction' => 'Transaction' =>
@@ -58,26 +58,27 @@ class StatementEntriesController extends AppController {
), ),
); );
if (!empty($params['post']['custom']['statement_entry_id'])) { if (isset($params['post']['custom']['statement_entry_id'])) {
$link['ChargeEntry'] = array();
$link['DisbursementEntry'] = array(); $link['DisbursementEntry'] = array();
$link['ChargeEntry'] = array();
} }
/* if ($params['action'] === 'collected') { */
/* $link['DisbursementEntry'] = array('Receipt' => array('class' => 'Transaction')); */
/* $link['ChargeEntry'] = array('Invoice' => array('class' => 'Transaction')); */
/* } */
/* if (count(array_intersect($params['fields'], array('applied'))) == 1) { */
/* $link['DisbursementEntry'] = array(); */
/* $link['ChargeEntry'] = array(); */
/* } */
/* elseif (isset($params['post']['custom']['customer_id']) || isset($params['post']['custom']['lease_id'])) { */
/* $link['DisbursementEntry'] = array(); */
/* } */
return array('link' => $link); 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) { function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model); $fields = parent::gridDataFields($params, $model);
@@ -86,13 +87,11 @@ class StatementEntriesController extends AppController {
" SUM(COALESCE(DisbursementEntry.amount,0))," . " SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" . " SUM(COALESCE(ChargeEntry.amount,0)))" .
" AS 'applied'"); " AS 'applied'");
}
if (in_array('unapplied', $params['post']['fields'])) {
$fields[] = ("StatementEntry.amount - (" . $fields[] = ("StatementEntry.amount - (" .
"IF(StatementEntry.type = 'CHARGE'," . "IF(StatementEntry.type = 'CHARGE'," .
" SUM(COALESCE(DisbursementEntry.amount,0))," . " SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" . " SUM(COALESCE(ChargeEntry.amount,0)))" .
") AS 'unapplied'"); ") AS 'balance'");
} }
$fields = array_merge($fields, $fields = array_merge($fields,
@@ -118,27 +117,12 @@ class StatementEntriesController extends AppController {
if (isset($account_id)) if (isset($account_id))
$conditions[] = array('StatementEntry.account_id' => $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)) { if (isset($statement_entry_id)) {
$conditions[] = array('OR' => $conditions[] = array('OR' =>
array(array('ChargeEntry.id' => $statement_entry_id), array(array('ChargeEntry.id' => $statement_entry_id),
array('DisbursementEntry.id' => $statement_entry_id))); array('DisbursementEntry.id' => $statement_entry_id)));
} }
if ($params['action'] === 'unreconciled') {
$query = array('conditions' => $conditions);
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
$entries = array();
foreach ($set['entries'] AS $entry)
$entries[] = $entry['StatementEntry']['id'];
$conditions[] = array('StatementEntry.id' => $entries);
$params['userdata']['balance'] = $set['summary']['balance'];
}
return $conditions; return $conditions;
} }
@@ -167,26 +151,26 @@ class StatementEntriesController extends AppController {
} }
function gridDataRecordsExecute(&$params, &$model, $query) { function gridDataRecordsExecute(&$params, &$model, $query) {
/* if ($params['action'] === '???') { */ if (in_array('applied', $params['post']['fields'])) {
/* $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1)); */ $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
/* $tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," . */ $tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," .
/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */ " SUM(COALESCE(DisbursementEntry.amount,0))," .
/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */ " SUM(COALESCE(ChargeEntry.amount,0)))" .
/* " AS 'applied'", */ " AS 'applied'",
/* "StatementEntry.amount - (" . */ "StatementEntry.amount - (" .
/* "IF(StatementEntry.type = 'CHARGE'," . */ "IF(StatementEntry.type = 'CHARGE'," .
/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */ " SUM(COALESCE(DisbursementEntry.amount,0))," .
/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */ " SUM(COALESCE(ChargeEntry.amount,0)))" .
/* ") AS 'balance'", */ ") AS 'balance'",
/* ); */ );
/* //pr(compact('tquery')); */ //pr(compact('tquery'));
/* $total = $model->find('first', $tquery); */ $total = $model->find('first', $tquery);
/* $params['userdata']['total'] = $total[0]['applied']; */ $params['userdata']['total'] = $total[0]['applied'];
/* $params['userdata']['balance'] = $total[0]['balance']; */ $params['userdata']['balance'] = $total[0]['balance'];
/* } */ }
if ($params['action'] === 'collected') { else {
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1)); $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'"); $tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
$total = $model->find('first', $tquery); $total = $model->find('first', $tquery);
@@ -203,44 +187,12 @@ class StatementEntriesController extends AppController {
* action: reverse the ledger entry * action: reverse the ledger entry
*/ */
function reverse($id = null) { function reverse($id) {
if ($this->data) { $this->StatementEntry->reverse($id);
//pr($this->data); die(); $this->render('/FAKE');
$this->StatementEntry->reverse
($this->data['StatementEntry']['id'],
$this->data['Transaction']['stamp'],
$this->data['Transaction']['comment']);
$this->redirect(array('action'=>'view',
$this->data['StatementEntry']['id']));
$this->INTERNAL_ERROR('SHOULD HAVE REDIRECTED');
}
$this->StatementEntry->id = $id;
$entry = $this->StatementEntry->find
('first', array
('contain' => array('Customer', 'Transaction', 'Account'),
));
if (empty($entry)) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'customers',
'action'=>'index'));
}
if (!$this->StatementEntry->reversable($id)) {
$this->Session->setFlash(__('Item not reversable.', true));
$this->redirect(array('action'=>'view', $id)); $this->redirect(array('action'=>'view', $id));
} }
// Prepare to render.
$title = ("Charge #{$entry['StatementEntry']['id']}" .
" : {$entry['StatementEntry']['amount']}" .
" : Reverse");
$this->set(compact('entry', 'title'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -262,6 +214,12 @@ class StatementEntriesController extends AppController {
*/ */
function view($id = null) { 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 $entry = $this->StatementEntry->find
('first', ('first',
array('contain' => array array('contain' => array
@@ -271,17 +229,10 @@ class StatementEntriesController extends AppController {
'Lease' => array('fields' => array('id')), 'Lease' => array('fields' => array('id')),
), ),
'conditions' => array(array('StatementEntry.id' => $id), 'conditions' => array('StatementEntry.id' => $id),
// REVISIT <AP>: 20090811
// No security issues have been worked out yet
array('Account.level >=' => 5)
),
)); ));
if (empty($entry)) { $reconciled = $this->StatementEntry->reconciledEntries($id);
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
}
$stats = $this->StatementEntry->stats($id); $stats = $this->StatementEntry->stats($id);
@@ -293,14 +244,19 @@ class StatementEntriesController extends AppController {
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') { if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
$reversable = $this->StatementEntry->reversable($id); $reversal = $this->StatementEntry->find
('first',
array('link' => array('DisbursementEntry'),
'conditions' => array(array('StatementEntry.id' => $id),
array('DisbursementEntry.type' => 'REVERSAL')),
));
// Set up dynamic menu items // Set up dynamic menu items
if ($reversable || $stats['balance'] > 0) if (empty($reversal) || $stats['balance'] > 0)
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true); array('name' => 'Operations', 'header' => true);
if ($reversable) if (empty($reversal))
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Reverse', array('name' => 'Reverse',
'url' => array('action' => 'reverse', 'url' => array('action' => 'reverse',
@@ -315,7 +271,7 @@ class StatementEntriesController extends AppController {
// Prepare to render. // Prepare to render.
$title = "Statement Entry #{$entry['StatementEntry']['id']}"; $title = "Statement Entry #{$entry['StatementEntry']['id']}";
$this->set(compact('entry', 'title', 'stats')); $this->set(compact('entry', 'title', 'reconciled', 'stats'));
} }
} }

View File

@@ -115,33 +115,15 @@ class TendersController extends AppController {
*/ */
function nsf($id = null) { 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) { if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true)); $this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
} }
$this->Tender->id = $id; $this->Tender->nsf($id);
$tender = $this->Tender->find $this->redirect(array('action'=>'view', $id));
('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'));
} }
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -156,31 +138,22 @@ class TendersController extends AppController {
} }
// Get the Tender and related fields // Get the Tender and related fields
$this->Tender->id = $id;
$tender = $this->Tender->find $tender = $this->Tender->find
('first', array ('first', array
('contain' => array('TenderType', 'Customer', 'LedgerEntry' => array('Transaction')), ('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']) if (!empty($tender['Tender']['deposit_transaction_id'])
&& empty($tender['Tender']['nsf_transaction_id']) && empty($tender['Tender']['nsf_transaction_id'])
// Hard to tell what types of items can come back as NSF. // 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. // For now, assume iff it is a named item, it can be NSF.
// (or if we're in development mode) && !empty($tender['TenderType']['data1_name'])
&& (!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[] = $this->sidemenu_links[] =
array('name' => 'NSF', array('name' => 'NSF',
'url' => array('action' => 'nsf', 'url' => array('action' => 'nsf',
@@ -188,71 +161,7 @@ class TendersController extends AppController {
} }
// Prepare to render. // Prepare to render.
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']}"; $title = "Tender #{$tender['Tender']['id']}";
$this->set(compact('tender', 'title')); $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'));
}
} }

View File

@@ -35,13 +35,7 @@ class TransactionsController extends AppController {
function all() { $this->gridView('All Transactions', 'all'); } function all() { $this->gridView('All Transactions', 'all'); }
function invoice() { $this->gridView('Invoices'); } function invoice() { $this->gridView('Invoices'); }
function receipt() { $this->gridView('Receipts'); } function receipt() { $this->gridView('Receipts'); }
function deposit() { function deposit() { $this->gridView('Deposits'); }
$this->sidemenu_links = array
(array('name' => 'Operations', 'header' => true),
array('name' => 'New Deposit', 'url' => array('controller' => 'tenders',
'action' => 'deposit')));
$this->gridView('Deposits');
}
/************************************************************************** /**************************************************************************
@@ -54,12 +48,7 @@ class TransactionsController extends AppController {
*/ */
function gridDataCountTables(&$params, &$model) { function gridDataCountTables(&$params, &$model) {
return array return parent::gridDataTables($params, $model);
('link' =>
array(// Models
'Account' => array('fields' => array()),
),
);
} }
function gridDataTables(&$params, &$model) { function gridDataTables(&$params, &$model) {
@@ -84,16 +73,11 @@ class TransactionsController extends AppController {
if (in_array($params['action'], array('invoice', 'receipt', 'deposit'))) if (in_array($params['action'], array('invoice', 'receipt', 'deposit')))
$conditions[] = array('Transaction.type' => strtoupper($params['action'])); $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; return $conditions;
} }
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) { function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit' $links['Transaction'] = array('id');
? 'deposit_slip' : 'view'));
return parent::gridDataPostProcessLinks($params, $model, $records, $links); return parent::gridDataPostProcessLinks($params, $model, $records, $links);
} }
@@ -291,6 +275,9 @@ class TransactionsController extends AppController {
} }
$data = $this->data; $data = $this->data;
$data['Entry'][0]['account_id'] =
$this->Transaction->Account->badDebtAccountID();
if (empty($data['Customer']['id'])) if (empty($data['Customer']['id']))
$data['Customer']['id'] = null; $data['Customer']['id'] = null;
if (empty($data['Lease']['id'])) if (empty($data['Lease']['id']))
@@ -298,7 +285,7 @@ class TransactionsController extends AppController {
pr(compact('data')); pr(compact('data'));
if (!$this->Transaction->addWriteOff($data, if (!$this->Transaction->addReceipt($data,
$data['Customer']['id'], $data['Customer']['id'],
$data['Lease']['id'])) { $data['Lease']['id'])) {
$this->Session->setFlash("WRITE OFF FAILED", true); $this->Session->setFlash("WRITE OFF FAILED", true);
@@ -308,6 +295,8 @@ class TransactionsController extends AppController {
die("<H1>WRITE-OFF FAILED</H1>"); die("<H1>WRITE-OFF FAILED</H1>");
} }
$this->render('/fake');
// Return to viewing the lease/customer // Return to viewing the lease/customer
if (empty($data['Lease']['id'])) if (empty($data['Lease']['id']))
$this->redirect(array('controller' => 'customers', $this->redirect(array('controller' => 'customers',
@@ -349,6 +338,8 @@ class TransactionsController extends AppController {
die("<H1>REFUND FAILED</H1>"); die("<H1>REFUND FAILED</H1>");
} }
$this->render('/fake');
// Return to viewing the lease/customer // Return to viewing the lease/customer
if (empty($data['Lease']['id'])) if (empty($data['Lease']['id']))
$this->redirect(array('controller' => 'customers', $this->redirect(array('controller' => 'customers',
@@ -361,21 +352,6 @@ class TransactionsController extends AppController {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* 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'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -384,45 +360,33 @@ class TransactionsController extends AppController {
*/ */
function view($id = null) { function view($id = null) {
$transaction = $this->Transaction->find if (!$id) {
('first',
array('contain' =>
array(// Models
'Account(id,name)',
'Ledger(id,name)',
'NsfTender(id,name)',
),
'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))),
),
));
// REVISIT <AP>: 20090815
// for debug purposes only (pr output)
$this->Transaction->stats($id);
if (empty($transaction)) {
$this->Session->setFlash(__('Invalid Item.', true)); $this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
} }
if ($transaction['Transaction']['type'] === 'DEPOSIT' || $this->params['dev']) { $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'),
),
),
'conditions' => array('Transaction.id' => $id),
));
if ($transaction['Transaction']['type'] === 'DEPOSIT') {
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true); array('name' => 'Operations', 'header' => true);
if ($transaction['Transaction']['type'] === 'DEPOSIT')
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'View Slip', 'url' => array('action' => 'deposit_slip', $id)); 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. // OK, prepare to render.
@@ -475,12 +439,15 @@ class TransactionsController extends AppController {
$type['TenderType'] + $type[0]; $type['TenderType'] + $type[0];
} }
$deposit_total = 0; // For each form of tender in the deposit, get the deposit items
foreach ($deposit['types'] AS $type) /* foreach ($deposit['types'] AS $type_id => &$type) { */
$deposit_total += $type['total']; /* $type['entries'] = $this->Transaction->DepositTender->find */
/* ('all', */
if ($deposit['Transaction']['amount'] != $deposit_total) /* array('contain' => array('Customer', 'LedgerEntry'), */
$this->INTERNAL_ERROR("Deposit items do not add up to deposit slip total"); /* 'conditions' => array(array('DepositTender.deposit_transaction_id' => $id), */
/* array('DepositTender.tender_type_id' => $type_id)), */
/* )); */
/* } */
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true); array('name' => 'Operations', 'header' => true);

View File

@@ -245,22 +245,20 @@ class UnitsController extends AppController {
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Move-Out', 'url' => array('action' => 'move_out', array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
$id)); $id));
} elseif ($this->Unit->available($unit['Unit']['status'])) { } else {
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Move-In', 'url' => array('action' => 'move_in', array('name' => 'Move-In', 'url' => array('action' => 'move_in',
$id)); $id));
} else {
// Unit is unavailable (dirty, damaged, reserved, business-use, etc)
} }
if (isset($unit['CurrentLease']['id']) && if (isset($unit['CurrentLease']['id']) &&
!isset($unit['CurrentLease']['close_date'])) { !isset($unit['CurrentLease']['close_date'])) {
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'New Invoice', 'url' => array('controller' => 'leases', array('name' => 'Charge', 'url' => array('controller' => 'leases',
'action' => 'invoice', 'action' => 'invoice',
$unit['CurrentLease']['id'])); $unit['CurrentLease']['id']));
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'New Receipt', 'url' => array('controller' => 'customers', array('name' => 'Payment', 'url' => array('controller' => 'customers',
'action' => 'receipt', 'action' => 'receipt',
$unit['CurrentLease']['customer_id'])); $unit['CurrentLease']['customer_id']));
} }
@@ -307,6 +305,11 @@ class UnitsController extends AppController {
} }
$this->redirect(array('action'=>'view', $this->Unit->id)); $this->redirect(array('action'=>'view', $this->Unit->id));
// For debugging, only if the redirects above have been
// commented out, otherwise this section isn't reached.
$this->render('/fake');
return;
} }
if ($id) { if ($id) {

View File

@@ -121,42 +121,24 @@ class Account extends AppModel {
* - Returns the ID of the desired account * - Returns the ID of the desired account
*/ */
function lookup($name, $check = true) { function securityDepositAccountID() { return $this->nameToID('Security Deposit'); }
$id = $this->nameToID($name); function rentAccountID() { return $this->nameToID('Rent'); }
if (empty($id) && $check) function lateChargeAccountID() { return $this->nameToID('Late Charge'); }
$this->INTERNAL_ERROR("Missing Account '$name'"); function nsfAccountID() { return $this->nameToID('NSF'); }
return $id; 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 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 securityDepositAccountID() { return $this->lookup('Security Deposit'); }
function rentAccountID() { return $this->lookup('Rent'); }
function lateChargeAccountID() { return $this->lookup('Late Charge'); }
function nsfAccountID() { return $this->lookup('NSF'); }
function nsfChargeAccountID() { return $this->lookup('NSF Charge'); }
function taxAccountID() { return $this->lookup('Tax'); }
function accountReceivableAccountID() { return $this->lookup('A/R'); }
function accountPayableAccountID() { return $this->lookup('A/P'); }
function cashAccountID() { return $this->lookup('Cash'); }
function checkAccountID() { return $this->lookup('Check'); }
function moneyOrderAccountID() { return $this->lookup('Money Order'); }
function achAccountID() { return $this->lookup('ACH'); }
function concessionAccountID() { return $this->lookup('Concession'); }
function waiverAccountID() { return $this->lookup('Waiver'); }
function pettyCashAccountID() { return $this->lookup('Petty Cash'); }
function invoiceAccountID() { return $this->lookup('Invoice'); }
function receiptAccountID() { return $this->lookup('Receipt'); }
function badDebtAccountID() { return $this->lookup('Bad Debt'); }
function customerCreditAccountID() { return $this->lookup(
// 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'
); }
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -240,28 +222,12 @@ class Account extends AppModel {
function collectableAccounts() { function collectableAccounts() {
$accounts = $this->receiptAccounts(); $accounts = $this->receiptAccounts();
foreach(array($this->customerCreditAccountID(), foreach(array($this->nsfAccountID(),
$this->securityDepositAccountID(), $this->securityDepositAccountID())
$this->nsfAccountID(),
$this->waiverAccountID(),
$this->badDebtAccountID(),
//$this->lookup('Closing'),
//$this->lookup('Equity'),
)
AS $account_id) { AS $account_id) {
$accounts[$account_id] = $this->name($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; return $accounts;
} }
@@ -377,7 +343,6 @@ class Account extends AppModel {
$this->queryInit($query); $this->queryInit($query);
$query['link'] = array('Account' => $query['link']); $query['link'] = array('Account' => $query['link']);
$stats = array();
foreach ($this->ledgers($id, $all) AS $ledger) foreach ($this->ledgers($id, $all) AS $ledger)
$this->statsMerge($stats['Ledger'], $this->statsMerge($stats['Ledger'],
$this->Ledger->stats($ledger, $query)); $this->Ledger->stats($ledger, $query));

View File

@@ -101,35 +101,12 @@ class Customer extends AppModel {
$this->prEnter(compact('id', 'query')); $this->prEnter(compact('id', 'query'));
$this->queryInit($query); $this->queryInit($query);
$sd_account_id = $query['conditions'][] = array('StatementEntry.customer_id' => $id);
$this->StatementEntry->Account->securityDepositAccountID(); $query['conditions'][] = array('StatementEntry.account_id' =>
$this->StatementEntry->Account->securityDepositAccountID());
$squery = $query; $stats = $this->StatementEntry->stats(null, $query);
$squery['conditions'][] = array('StatementEntry.customer_id' => $id); return $this->prReturn($stats['account_balance']);
$squery['conditions'][] = array('StatementEntry.account_id' => $sd_account_id);
$stats = $this->StatementEntry->stats(null, $squery);
$this->pr(26, compact('squery', 'stats'));
// OK, we know now how much we charged for a security
// deposit, as well as how much we received to pay for it.
// Now we need to know if any has been released.
// Yes... this sucks.
$lquery = $query;
$lquery['link'] = array('Transaction' =>
array('fields' => array(),
'Customer' =>
(empty($query['link'])
? array('fields' => array())
: $query['link'])));
$lquery['conditions'][] = array('Transaction.customer_id' => $id);
$lquery['conditions'][] = array('LedgerEntry.account_id' => $sd_account_id);
$lquery['conditions'][] = array('LedgerEntry.crdr' => 'DEBIT');
$lquery['fields'][] = 'SUM(LedgerEntry.amount) AS total';
$released = $this->StatementEntry->Transaction->LedgerEntry->find
('first', $lquery);
$this->pr(26, compact('lquery', 'released'));
return $this->prReturn($stats['Charge']['disbursement'] - $released[0]['total']);
} }
@@ -165,8 +142,10 @@ class Customer extends AppModel {
continue; continue;
$I = new Contact(); $I = new Contact();
if (!$I->saveContact(null, array('Contact' => $contact))) $I->create();
if (!$I->save($contact, false)) {
return false; return false;
}
$contact['id'] = $I->id; $contact['id'] = $I->id;
} }
@@ -224,52 +203,6 @@ class Customer extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
$this->prEnter(compact('id'));
if (empty($id)) {
$customers = $this->find('all', array('contain' => false, 'fields' => array('id')));
foreach ($customers AS $customer) {
// This SHOULDN'T happen, but check to be sure
// or we'll get infinite recursion.
if (empty($customer['Customer']['id']))
continue;
$this->update($customer['Customer']['id']);
}
return;
}
// 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',
// REVISIT <AP>: 20090816
// Do we need to update leases other than the current ones?
// It may be necessary. For example, a non-current lease
// can still be hit with an NSF item. In that case, it
// could have stale data if we look only to current leases.
//array('link' => array('CurrentLease' => array('type' => 'INNER')),
array('link' => array('Lease' => array('type' => 'INNER')),
'conditions' => array('Customer.id' => $id)));
foreach ($current_leases AS $lease) {
if (!empty($lease['CurrentLease']['id']))
$this->Lease->update($lease['CurrentLease']['id']);
if (!empty($lease['Lease']['id']))
$this->Lease->update($lease['Lease']['id']);
}
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -53,27 +53,12 @@ class DoubleEntry extends AppModel {
*/ */
function addDoubleEntry($entry1, $entry2, $entry1_tender = null) { function addDoubleEntry($entry1, $entry2, $entry1_tender = null) {
//$this->prFunctionLevel(16); /* pr(array('DoubleEntry::addDoubleEntry' => */
$this->prEnter(compact('entry1', 'entry2', 'entry1_tender')); /* compact('entry1', 'entry2', 'entry1_tender'))); */
$ret = array(); $ret = array();
if (!$this->verifyDoubleEntry($entry1, $entry2, $entry1_tender)) if (!$this->verifyDoubleEntry($entry1, $entry2, $entry1_tender))
return $this->prReturn(array('error' => true) + $ret); return 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... // Since this model only relates to DebitEntry and CreditEntry...
$LE = new LedgerEntry(); $LE = new LedgerEntry();
@@ -82,13 +67,13 @@ class DoubleEntry extends AppModel {
$result = $LE->addLedgerEntry($entry1, $entry1_tender); $result = $LE->addLedgerEntry($entry1, $entry1_tender);
$ret['Entry1'] = $result; $ret['Entry1'] = $result;
if ($result['error']) if ($result['error'])
return $this->prReturn(array('error' => true) + $ret); return array('error' => true) + $ret;
// Add the second ledger entry to the database // Add the second ledger entry to the database
$result = $LE->addLedgerEntry($entry2); $result = $LE->addLedgerEntry($entry2);
$ret['Entry2'] = $result; $ret['Entry2'] = $result;
if ($result['error']) if ($result['error'])
return $this->prReturn(array('error' => true) + $ret); return array('error' => true) + $ret;
// Now link them as a double entry // Now link them as a double entry
$double_entry = array(); $double_entry = array();
@@ -97,13 +82,15 @@ class DoubleEntry extends AppModel {
$double_entry['credit_entry_id'] = $double_entry['credit_entry_id'] =
($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id']; ($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
$ret['data'] = $double_entry; /* pr(array('DoubleEntry::addDoubleEntry' => */
/* array('checkpoint' => 'Pre-Save') */
/* + compact('double_entry'))); */
$this->create(); $this->create();
if (!$this->save($double_entry)) if (!$this->save($double_entry))
return $this->prReturn(array('error' => true) + $ret); return array('error' => true) + $ret;
$ret['double_entry_id'] = $this->id; $ret['double_entry_id'] = $this->id;
return $this->prReturn($ret + array('error' => false)); return $ret + array('error' => false);
} }
} }

View File

@@ -12,7 +12,7 @@ class Lease extends AppModel {
'StatementEntry', 'StatementEntry',
); );
//var $default_log_level = array('log' => 30, 'show' => 30); //var $default_log_level = array('log' => 30, 'show' => 15);
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -44,26 +44,26 @@ class Lease extends AppModel {
$this->prEnter(compact('id', 'query')); $this->prEnter(compact('id', 'query'));
$this->queryInit($query); $this->queryInit($query);
// 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.
$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.lease_id' => $id);
$query['conditions'][] = array('StatementEntry.account_id' => $query['conditions'][] = array('StatementEntry.account_id' =>
$this->StatementEntry->Account->securityDepositAccountID()); $this->StatementEntry->Account->securityDepositAccountID());
// REVISIT <AP>: 20090804
// Dilemma... how to handle security deposits used to pay
// charges on the lease, yet are not part of the lease
// security deposit(s)? For example, Lease A & Lease B,
// each with $25 Sec. Dep. Move out of Lease A, and
// promote the lease surplus to the customer. A new
// charge on Lease B for $15, which is assigned $15/$25
// from the promoted Lease A surplus. They way this
// function works at present, it will presume the $15 is
// part of the security deposit balance, and will end up
// calculating it as only $10, which is wrong. Perhaps
// the fix is to release security deposits into some sort
// of income account.
$stats = $this->StatementEntry->stats(null, $query); $stats = $this->StatementEntry->stats(null, $query);
return $this->prReturn($stats['Charge']['disbursement']); return $this->prReturn($stats['account_balance']);
} }
@@ -113,12 +113,8 @@ class Lease extends AppModel {
$customer_id = $secdeps[0]['StatementEntry']['customer_id']; $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 $result = $this->StatementEntry->Transaction->addReceipt
($release, $customer_id, null); ($release, $customer_id, $lease_id);
return $this->prReturn($result); return $this->prReturn($result);
} }
@@ -150,7 +146,6 @@ class Lease extends AppModel {
'conditions' => array 'conditions' => array
('SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)', ('SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
'SEx.lease_id = StatementEntry.lease_id', 'SEx.lease_id = StatementEntry.lease_id',
'SEx.reverse_transaction_id IS NULL',
), ),
), ),
), ),
@@ -160,7 +155,6 @@ class Lease extends AppModel {
'conditions' => array(array('Lease.id' => $id), 'conditions' => array(array('Lease.id' => $id),
array('StatementEntry.type' => 'CHARGE'), array('StatementEntry.type' => 'CHARGE'),
array('StatementEntry.account_id' => $rent_account_id), array('StatementEntry.account_id' => $rent_account_id),
array('StatementEntry.reverse_transaction_id IS NULL'),
array('SEx.id' => null), array('SEx.id' => null),
), ),
) )
@@ -170,35 +164,6 @@ 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);
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -261,9 +226,7 @@ class Lease extends AppModel {
'conditions' => 'conditions' =>
array(array('StatementEntry.lease_id' => $id), array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id), array('StatementEntry.account_id' => $rent_account_id)),
array('StatementEntry.reverse_transaction_id IS NULL'),
),
'order' => array('StatementEntry.effective_date'), 'order' => array('StatementEntry.effective_date'),
), ),
@@ -282,9 +245,7 @@ class Lease extends AppModel {
('CHARGE', ('CHARGE',
array('conditions' => array('conditions' =>
array(array('StatementEntry.lease_id' => $id), array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id), array('StatementEntry.account_id' => $rent_account_id)),
array('StatementEntry.reverse_transaction_id IS NULL'),
),
'order' => array('StatementEntry.through_date DESC'), 'order' => array('StatementEntry.through_date DESC'),
), ),
@@ -302,261 +263,6 @@ 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->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 10 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'");
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -655,7 +361,7 @@ class Lease extends AppModel {
*/ */
function moveOut($id, $status = 'VACANT', function moveOut($id, $status = 'VACANT',
$stamp = null, $close = true) $stamp = null, $close = false)
{ {
$this->prEnter(compact('id', 'status', 'stamp', 'close')); $this->prEnter(compact('id', 'status', 'stamp', 'close'));
@@ -745,13 +451,12 @@ class Lease extends AppModel {
if (isset($this->data['Lease']['close_date'])) if (isset($this->data['Lease']['close_date']))
return $this->prReturn(false); return $this->prReturn(false);
// A lease can only be closed if there are no outstanding $deposit_balance = $this->securityDepositBalance($id);
// security deposits ... $stats = $this->stats($id);
if ($this->securityDepositBalance($id) != 0)
return $this->prReturn(false);
// ... and if the account balance is zero. // A lease can only be closed if there are no outstanding
if ($this->balance($id) != 0) // security deposits, and if the account balance is zero.
if ($deposit_balance != 0)
return $this->prReturn(false); return $this->prReturn(false);
// Apparently this lease meets all the criteria! // Apparently this lease meets all the criteria!
@@ -790,25 +495,6 @@ class Lease extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
$this->prEnter(compact('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'));
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -8,22 +8,8 @@ class LedgerEntry extends AppModel {
); );
var $hasOne = array( var $hasOne = array(
'Tender' => array( 'Tender',
'dependent' => true, 'DoubleEntry',
),
'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( var $hasMany = array(
@@ -127,20 +113,24 @@ class LedgerEntry extends AppModel {
* - Inserts new Ledger Entry into the database * - Inserts new Ledger Entry into the database
*/ */
function addLedgerEntry($entry, $tender = null) { function addLedgerEntry($entry, $tender = null) {
//$this->prFunctionLevel(16); /* pr(array('LedgerEntry::addLedgerEntry' => */
$this->prEnter(compact('entry', 'tender')); /* compact('entry', 'tender'))); */
$ret = array('data' => $entry); $ret = array();
if (!$this->verifyLedgerEntry($entry, $tender)) if (!$this->verifyLedgerEntry($entry, $tender))
return $this->prReturn(array('error' => true) + $ret); return array('error' => true) + $ret;
if (empty($entry['ledger_id'])) if (empty($entry['ledger_id']))
$entry['ledger_id'] = $entry['ledger_id'] =
$this->Account->currentLedgerID($entry['account_id']); $this->Account->currentLedgerID($entry['account_id']);
/* pr(array('LedgerEntry::addLedgerEntry' => */
/* array('checkpoint' => 'Pre-Save') */
/* + compact('entry'))); */
$this->create(); $this->create();
if (!$this->save($entry)) if (!$this->save($entry))
return $this->prReturn(array('error' => true) + $ret); return array('error' => true) + $ret;
$ret['ledger_entry_id'] = $this->id; $ret['ledger_entry_id'] = $this->id;
@@ -150,10 +140,10 @@ class LedgerEntry extends AppModel {
$result = $this->Tender->addTender($tender); $result = $this->Tender->addTender($tender);
$ret['Tender'] = $result; $ret['Tender'] = $result;
if ($result['error']) if ($result['error'])
return $this->prReturn(array('error' => true) + $ret); return array('error' => true) + $ret;
} }
return $this->prReturn($ret + array('error' => false)); return $ret + array('error' => false);
} }
@@ -165,13 +155,53 @@ class LedgerEntry extends AppModel {
*/ */
function stats($id = null, $query = null, $set = null) { function stats($id = null, $query = null, $set = null) {
$this->queryInit($query); $this->queryInit($query);
unset($query['group']);
// REVISIT <AP>: 20090816 if (!isset($query['link']['DoubleEntry']))
// This function appeared to be dramatically broken, $query['link']['DoubleEntry'] = array();
// a throwback to an earlier time. I deleted its /* if (!isset($query['link']['DoubleEntry']['fields'])) */
// contents and added this error to ensure it does /* $query['link']['DoubleEntry']['fields'] = array(); */
// not get used.
$this->INTERNAL_ERROR('This function should not be used'); if (isset($id))
$query['conditions'][] = array('Entry.id' => $id);
if (isset($set))
$set = strtoupper($set);
//pr(array('stats()', compact('id', 'query', 'set')));
$rtypes = array('charge', 'disbursement',
// 'debit', 'credit',
);
$stats = array();
foreach($rtypes AS $rtype) {
$Rtype = ucfirst($rtype);
if (($rtype == 'charge' && (!isset($set) || $set == 'DISBURSEMENT')) ||
($rtype == 'disbursement' && (!isset($set) || $set == 'CHARGE'))
) {
$rquery = $query;
$rquery['link'][$Rtype] =
array('fields' => array("SUM(COALESCE(Applied{$Rtype}.amount,0)) AS reconciled"));
$rquery['fields'] = array();
//$rquery['fields'][] = "SUM(DoubleEntry.amount) AS total";
$rquery['fields'][] = "SUM(DoubleEntry.amount) - SUM(COALESCE(Applied{$Rtype}.amount,0)) AS balance";
$rquery['conditions'][] = array("Applied{$Rtype}.id !=" => null);
$result = $this->find('first', $rquery);
//pr(compact('Rtype', 'rquery', 'result'));
$sumfld = $Rtype;
$stats[$sumfld] = $result[0];
/* if (!isset($stats[$sumfld]['applied'])) */
/* $stats[$sumfld]['applied'] = 0; */
}
}
return $stats;
} }
} }

15
site/models/maps_unit.php Normal file
View File

@@ -0,0 +1,15 @@
<?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')
);
}
?>

View File

@@ -18,13 +18,11 @@ class StatementEntry extends AppModel {
'DisbursementEntry' => array( 'DisbursementEntry' => array(
'className' => 'StatementEntry', 'className' => 'StatementEntry',
'foreignKey' => 'charge_entry_id', 'foreignKey' => 'charge_entry_id',
'dependent' => true,
), ),
); );
//var $default_log_level = array('log' => 30, 'show' => 15); var $default_log_level = array('log' => 30, 'show' => 15);
var $max_log_level = 19;
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -37,7 +35,7 @@ class StatementEntry extends AppModel {
} }
function creditTypes() { function creditTypes() {
return array('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS'); return array('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'SURPLUS');
} }
function voidTypes() { function voidTypes() {
@@ -125,13 +123,16 @@ class StatementEntry extends AppModel {
function addStatementEntry($entry) { function addStatementEntry($entry) {
$this->prEnter(compact('entry')); $this->prEnter(compact('entry'));
$ret = array('data' => $entry); $ret = array();
if (!$this->verifyStatementEntry($entry)) if (!$this->verifyStatementEntry($entry))
return $this->prReturn(array('error' => true, 'verify_data' => $entry) + $ret); return array('error' => true, 'verify_data' => $entry) + $ret;
$this->pr(20, array('checkpoint' => 'Pre-Save')
+ compact('entry'));
$this->create(); $this->create();
if (!$this->save($entry)) if (!$this->save($entry))
return $this->prReturn(array('error' => true, 'save_data' => $entry) + $ret); return array('error' => true, 'save_data' => $entry) + $ret;
$ret['statement_entry_id'] = $this->id; $ret['statement_entry_id'] = $this->id;
return $this->prReturn($ret + array('error' => false)); return $this->prReturn($ret + array('error' => false));
@@ -154,7 +155,7 @@ class StatementEntry extends AppModel {
$charge = $charge['StatementEntry']; $charge = $charge['StatementEntry'];
if ($charge['type'] !== 'CHARGE') if ($charge['type'] !== 'CHARGE')
$this->INTERNAL_ERROR("Waiver item is not CHARGE."); INTERNAL_ERROR("Waiver item is not CHARGE.");
// Query the stats to get the remaining balance // Query the stats to get the remaining balance
$stats = $this->stats($id); $stats = $this->stats($id);
@@ -167,6 +168,7 @@ class StatementEntry extends AppModel {
// Add the charge waiver // Add the charge waiver
$waiver['Entry'][] = $waiver['Entry'][] =
array('amount' => $stats['Charge']['balance'], array('amount' => $stats['Charge']['balance'],
'account_id' => $this->Account->waiverAccountID(),
'comment' => null, 'comment' => null,
); );
@@ -176,64 +178,89 @@ class StatementEntry extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reversable
* - Returns true if the charge can be reversed; false otherwise
*/
function reversable($id) {
$this->prEnter(compact('id'));
if (empty($id))
return $this->prReturn(false);
// 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 * function: reverse
* - Reverses the charges * - Reverses the charges
*
*/ */
function reverse($id, $stamp = null, $comment) { function reverse($id, $balance = false, $stamp = null) {
$this->prEnter(compact('id', 'stamp')); $this->prEnter(compact('id', 'balance', 'stamp'));
// Verify the item can be reversed $ret = array();
if (!$this->reversable($id))
$this->INTERNAL_ERROR("Item is not reversable.");
// Get the basic information about this charge // Get the basic information about the entry to be reversed.
$charge = $this->find('first', array('contain' => true)); $this->recursive = -1;
//$charge = $charge['StatementEntry']; $charge = $this->read(null, $id);
$charge = $charge['StatementEntry'];
if ($charge['type'] !== 'CHARGE')
INTERNAL_ERROR("Reversal item is not CHARGE.");
// Build a transaction
$reversal = array('Transaction' => array(), 'Entry' => array());
$reversal['Transaction']['stamp'] = $stamp;
$reversal['Transaction']['comment'] = "Credit Note: Charge Reversal";
$voided_entry_transactions = array();
$reconciled = $this->reconciledEntries($id);
$this->pr(21, compact('reconciled'));
if ($reconciled && !$balance) {
foreach ($reconciled['entries'] AS $entry) {
if ($entry['DisbursementEntry']['type'] === 'REVERSAL')
INTERNAL_ERROR("Charge has already been reversed");
/* $voided_entry_transactions[$entry['DisbursementEntry']['transaction_id']] */
/* = array_intersect_key($entry['DisbursementEntry'], */
/* array('customer_id'=>1, 'lease_id'=>1)); */
/* $reversal['Entry'][] = */
/* array_intersect_key($entry['DisbursementEntry'], */
/* array_flip(array('amount', 'account_id', 'charge_entry_id'))) */
/* + array('type' => 'SURPLUS', */
/* 'comment' => 'Release of funds applied to reversed charge', */
/* ); */
}
/* $this->pr(17, compact('voided_entry_transactions')); */
}
// Query the stats to get the remaining balance // Query the stats to get the remaining balance
$stats = $this->stats($id); $stats = $this->stats($id);
$charge['paid'] = $stats['Charge']['disbursement'];
// Add the charge reversal
$reversal['Entry'][] =
array('charge_entry_id' => $id,
'amount' => -1 * $stats['Charge'][$balance ? 'balance' : 'total'],
'account_id' => $charge['account_id'],
'comment' => 'Charge Reversal',
);
// Record the reversal transaction // Record the reversal transaction
$result = $this->Transaction->addReversal $result = $this->Transaction->addReversal
($charge, $stamp, $comment ? $comment : 'Charge Reversal'); ($reversal, $id, $charge['customer_id'], $charge['lease_id']);
$this->pr(21, compact('result'));
$ret['reversal'] = $result;
if ($result['error'])
$ret['error'] = true;
if (empty($result['error'])) { foreach ($voided_entry_transactions AS $transaction_id => $tx) {
// Mark the charge as reversed $result = $this->assignCredits
$this->id = $id; (null,
$this->saveField('reverse_transaction_id', $result['transaction_id']); $transaction_id,
null,
null,
$tx['customer_id'],
$tx['lease_id']
);
$this->pr(21, compact('result'));
$ret['assigned'][] = $result;
if ($result['error'])
$ret['error'] = true;
} }
return $this->prReturn($result); return $this->prReturn($ret + array('error' => false));
} }
@@ -369,11 +396,10 @@ class StatementEntry extends AppModel {
// First, find all known credits, unless this call is to make // First, find all known credits, unless this call is to make
// credit adjustments to a specific charge // credit adjustments to a specific charge
if (empty($receipt_id)) { // REVISIT <AP>: 20090806
// If the theory below is correct, we should only search for
if (!empty($charge_ids)) // explicit credits if we don't have a receipt_id
$this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt"); if (empty($charge_ids)) {
$lquery = $query; $lquery = $query;
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS'); $lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
// REVISIT <AP>: 20090804 // REVISIT <AP>: 20090804
@@ -398,13 +424,20 @@ class StatementEntry extends AppModel {
"Credits Established"); "Credits Established");
} }
else { else {
// Establish credit from the (newly added) receipt if (empty($receipt_id))
INTERNAL_ERROR("Can't make adjustments to a charge without a receipt ID.");
}
// Next, establish credit from the newly added receipt
$receipt_credit = null;
if (!empty($receipt_id)) {
$lquery = $lquery =
array('link' => array('link' =>
array('StatementEntry', array('StatementEntry',
'LedgerEntry' => 'LedgerEntry' =>
array('conditions' => array('conditions' =>
array('LedgerEntry.account_id <> Transaction.account_id') array('LedgerEntry.account_id !=' =>
$this->Account->accountReceivableAccountID()),
), ),
), ),
'conditions' => array('Transaction.id' => $receipt_id), 'conditions' => array('Transaction.id' => $receipt_id),
@@ -412,14 +445,15 @@ class StatementEntry extends AppModel {
); );
$receipt_credit = $this->Transaction->find('first', $lquery); $receipt_credit = $this->Transaction->find('first', $lquery);
if (!$receipt_credit) if (!$receipt_credit)
$this->INTERNAL_ERROR("Unable to locate receipt."); INTERNAL_ERROR("Unable to locate receipt.");
//$reconciled = $this->reconciledEntries($id);
$stats = $this->Transaction->stats($receipt_id); $stats = $this->Transaction->stats($receipt_id);
$receipt_credit['balance'] = $stats['undisbursed']; $receipt_credit['balance'] =
$receipt_credit['Transaction']['amount'] - $stats['Disbursement']['total'];
$receipt_credit['receipt'] = true; $this->pr(18, compact('receipt_credit'),
$credits = array($receipt_credit);
$this->pr(18, compact('credits'),
"Receipt Credit Added"); "Receipt Credit Added");
} }
@@ -442,44 +476,61 @@ class StatementEntry extends AppModel {
$this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries"); $this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries");
} }
// Initialize our list of used credits
$used_credits = array();
// REVISIT <AP>: 20090806
// Testing a theory. We should never have
// explicit credits, as well as a new receipt,
// and yet have outstanding charges.
if (!empty($credits) && !empty($receipt_credit) && !empty($charges))
INTERNAL_ERROR("Explicit credits that haven't already been applied.");
// Work through all unpaid charges, applying disbursements as we go // Work through all unpaid charges, applying disbursements as we go
foreach ($charges AS $charge) { foreach ($charges AS $charge) {
$this->pr(20, compact('charge'), $this->pr(20, compact('charge'),
'Process Charge'); 'Process Charge');
$charge['balance'] = $charge['StatementEntry']['balance']; // Check that we have available credits.
// Technically, this isn't necessary, since the loop
// Use explicit credits before using the new receipt credit // will handle everything just fine. However, this
foreach ($credits AS &$credit) { // just saves extra processing if/when there is no
if (empty($charge['balance'])) // means to resolve a charge anyway.
if (empty($credits) && empty($receipt_credit['balance'])) {
$this->pr(17, 'No more available credits');
break; break;
if ($charge['balance'] < 0) }
$this->INTERNAL_ERROR("Negative Charge Balance");
if (!isset($credit['balance'])) $charge['balance'] = $charge['StatementEntry']['balance'];
$credit['balance'] = $credit['StatementEntry']['amount']; while ($charge['balance'] > 0 &&
(!empty($credits) || !empty($receipt_credit['balance']))) {
if (empty($credit['balance']))
continue;
if ($credit['balance'] < 0)
$this->INTERNAL_ERROR("Negative Credit Balance");
$this->pr(20, compact('charge'), $this->pr(20, compact('charge'),
'Attempt Charge Reconciliation'); 'Attempt Charge Reconciliation');
if (empty($credit['receipt'])) // Use explicit credits before using implicit credits
// (Not sure it matters though).
if (!empty($credits)) {
// Peel off the first credit available
$credit =& $credits[0];
$disbursement_date = $credit['StatementEntry']['effective_date'];
$disbursement_transaction_id = $credit['StatementEntry']['transaction_id'];
$disbursement_account_id = $credit['StatementEntry']['account_id']; $disbursement_account_id = $credit['StatementEntry']['account_id'];
else
$disbursement_account_id = $credit['LedgerEntry']['account_id'];
// REVISIT <AP>: 20090811 if (!isset($credit['balance']))
// Need to come up with a better strategy for handling $credit['balance'] = $credit['StatementEntry']['amount'];
// concessions. For now, just restricting concessions }
// to apply only towards rent will resolve the most elseif (!empty($receipt_credit['balance'])) {
// predominant (or only) needed usage case. // Use our only receipt credit
if ($disbursement_account_id == $this->Account->concessionAccountID() && $credit =& $receipt_credit;
$charge['StatementEntry']['account_id'] != $this->Account->rentAccountID()) $disbursement_date = $credit['Transaction']['stamp'];
continue; $disbursement_transaction_id = $credit['Transaction']['id'];
$disbursement_account_id = $credit['LedgerEntry']['account_id'];
}
else {
die("HOW DID WE GET HERE WITH NO SURPLUS?");
}
// Set the disbursement amount to the maximum amount // Set the disbursement amount to the maximum amount
// possible without exceeding the charge or credit balance // possible without exceeding the charge or credit balance
@@ -492,67 +543,35 @@ class StatementEntry extends AppModel {
$this->pr(20, compact('credit'), $this->pr(20, compact('credit'),
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') . ($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
(empty($credit['receipt']) ? ' Credit' : ' Receipt')); (!empty($credits) ? ' Credit' : ' Receipt'));
if (strtotime($charge['StatementEntry']['effective_date']) > if ($credit['balance'] < 0)
strtotime($credit['StatementEntry']['effective_date'])) die("HOW DID WE END UP WITH NEGATIVE SURPLUS BALANCE?");
$disbursement_edate = $charge['StatementEntry']['effective_date'];
else
$disbursement_edate = $credit['StatementEntry']['effective_date'];
if (empty($credit['receipt'])) { // If we've exhausted the credit, get it out of the
// Explicit Credit // available credit pool (but keep track of it for later).
$result = $this->Transaction->addTransactionEntries if ($credit['balance'] <= 0 && !empty($credits))
(array('include_ledger_entry' => true, $used_credits[] = array_shift($credits);
'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'],
),
));
$ret['Disbursement'][] = $result;
if ($result['error'])
$ret['error'] = true;
}
else {
// Receipt Credit
if (strtotime($charge['StatementEntry']['effective_date']) >
strtotime($credit['Transaction']['stamp']))
$disbursement_edate = $charge['StatementEntry']['effective_date'];
else
$disbursement_edate = $credit['Transaction']['stamp'];
// Add a disbursement that uses the available credit to pay the charge // Add a disbursement that uses the available credit to pay the charge
$disbursement = $disbursement = array('type' => $disbursement_type,
array('type' => $disbursement_type, 'account_id' => $disbursement_account_id,
'effective_date' => $disbursement_edate,
'amount' => $disbursement_amount, 'amount' => $disbursement_amount,
'account_id' => $credit['LedgerEntry']['account_id'], 'effective_date' => $disbursement_date,
'transaction_id' => $credit['Transaction']['id'], 'transaction_id' => $disbursement_transaction_id,
'customer_id' => $charge['StatementEntry']['customer_id'], 'customer_id' => $charge['StatementEntry']['customer_id'],
'lease_id' => $charge['StatementEntry']['lease_id'], 'lease_id' => $charge['StatementEntry']['lease_id'],
'charge_entry_id' => $charge['StatementEntry']['id'], 'charge_entry_id' => $charge['StatementEntry']['id'],
'comment' => null, 'comment' => null,
); );
$this->pr(20, compact('disbursement'), 'New Disbursement Entry'); $this->pr(20, compact('disbursement'),
'New Disbursement Entry');
$result = $this->addStatementEntry($disbursement); $result = $this->addStatementEntry($disbursement);
$ret['Disbursement'][] = $result; $ret['Disbursement'][] = $result;
if ($result['error']) if ($result['error'])
$ret['error'] = true; $ret['error'] = true;
}
// Adjust the charge balance to reflect the new disbursement // Adjust the charge balance to reflect the new disbursement
$charge['balance'] -= $disbursement_amount; $charge['balance'] -= $disbursement_amount;
@@ -562,21 +581,18 @@ class StatementEntry extends AppModel {
if ($charge['balance'] <= 0) if ($charge['balance'] <= 0)
$this->pr(20, 'Fully Paid Charge'); $this->pr(20, 'Fully Paid Charge');
} }
// Break the $credit reference to avoid future problems
unset($credit);
} }
$this->pr(18, compact('credits'), // Partially used credits must be added to the used list
'Disbursements complete'); if (isset($credits[0]['applied']))
$used_credits[] = array_shift($credits);
$this->pr(18, compact('credits', 'used_credits', 'receipt_credit'),
'Disbursements added');
// Clean up any explicit credits that have been used // Clean up any explicit credits that have been used
foreach ($credits AS $credit) { foreach ($used_credits AS $credit) {
if (!empty($credit['receipt']))
continue;
if (empty($credit['applied']))
continue;
if ($credit['balance'] > 0) { if ($credit['balance'] > 0) {
$this->pr(20, compact('credit'), $this->pr(20, compact('credit'),
'Update Credit Entry'); 'Update Credit Entry');
@@ -588,21 +604,14 @@ class StatementEntry extends AppModel {
$this->pr(20, compact('credit'), $this->pr(20, compact('credit'),
'Delete Exhausted Credit Entry'); 'Delete Exhausted Credit Entry');
$this->delete($credit['StatementEntry']['id'], false); $this->del($credit['StatementEntry']['id'], false);
} }
} }
// Check for any implicit receipt credits, converting // Convert non-exhausted receipt credit to an explicit one
// into explicit credits if there is a remaining balance. if (!empty($receipt_credit['balance'])) {
foreach ($credits AS $credit) { $credit =& $receipt_credit;
if (empty($credit['receipt']))
continue;
if (empty($credit['balance']))
continue;
// See if there is an existing explicit credit
// for this transaction.
$explicit_credit = $this->find $explicit_credit = $this->find
('first', array('contain' => false, ('first', array('contain' => false,
'conditions' => 'conditions' =>
@@ -610,31 +619,30 @@ class StatementEntry extends AppModel {
array('type' => 'SURPLUS')), array('type' => 'SURPLUS')),
)); ));
if (!empty($explicit_credit)) { if (empty($explicit_credit)) {
// REVISIT <AP>: 20090815 $this->pr(18, compact('credit'),
// Testing whether or not this case occurs 'Create Explicit Credit');
$this->INTERNAL_ERROR('Existing explicit credit unexpected');
// Since there IS an existing explicit credit, we must update $result = $this->addStatementEntry
// its balance instead of creating a new one, since it has (array('type' => 'SURPLUS',
// already been incorporated in the overall credit balance. 'account_id' => $credit['LedgerEntry']['account_id'],
// If we were to create a new one, we would erroneously create 'amount' => $credit['balance'],
// an excess of credit available. 'effective_date' => $credit['Transaction']['stamp'],
'transaction_id' => $credit['Transaction']['id'],
'customer_id' => $customer_id,
'lease_id' => $lease_id,
));
$ret['Credit'] = $result;
if ($result['error'])
$ret['error'] = true;
}
else {
$this->pr(18, compact('explicit_credit', 'credit'), $this->pr(18, compact('explicit_credit', 'credit'),
'Update existing explicit credit'); 'Update Explicit Credit');
$EC = new StatementEntry(); $EC = new StatementEntry();
$EC->id = $explicit_credit['StatementEntry']['id']; $EC->id = $explicit_credit['StatementEntry']['id'];
$EC->saveField('amount', $credit['balance']); $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)); return $this->prReturn($ret + array('error' => false));
@@ -648,7 +656,7 @@ class StatementEntry extends AppModel {
* - Returns summary data from the requested statement entry * - Returns summary data from the requested statement entry
*/ */
function stats($id = null, $query = null) { function stats($id = null, $query = null) {
//$this->prFunctionLevel(array('log' => 16, 'show' => 10)); $this->prFunctionLevel(array('log' => 19, 'show' => 10));
$this->prEnter(compact('id', 'query')); $this->prEnter(compact('id', 'query'));
$this->queryInit($query); $this->queryInit($query);

View File

@@ -8,73 +8,12 @@ class Tender extends AppModel {
'DepositTransaction' => array( 'DepositTransaction' => array(
'className' => 'Transaction', 'className' => 'Transaction',
), ),
'DepositLedgerEntry' => array(
'className' => 'LedgerEntry',
),
'NsfTransaction' => array( 'NsfTransaction' => array(
'className' => 'Transaction', '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);
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -104,10 +43,29 @@ class Tender extends AppModel {
function addTender($tender) { function addTender($tender) {
$this->prEnter(compact('tender')); $this->prEnter(compact('tender'));
$ret = array('data' => $tender); $ret = array();
if (!$this->verifyTender($tender)) if (!$this->verifyTender($tender))
return $this->prReturn(array('error' => true) + $ret); 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(); $this->create();
if (!$this->save($tender)) if (!$this->save($tender))
return $this->prReturn(array('error' => true) + $ret); return $this->prReturn(array('error' => true) + $ret);
@@ -122,10 +80,31 @@ class Tender extends AppModel {
************************************************************************** **************************************************************************
* function: nsf * function: nsf
* - Flags the ledger entry as having insufficient funds * - 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 Disbursement SE of Tx:
* - Add new StatementEntry (S1n); T1; DISBURSEMENT; -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, $comment = null) { function nsf($id, $stamp = null) {
$this->prEnter(compact('id', 'stamp', 'comment')); $this->prFunctionLevel(30);
$this->prEnter(compact('id'));
// Get information about this NSF item. // Get information about this NSF item.
$this->id = $id; $this->id = $id;
@@ -134,7 +113,6 @@ class Tender extends AppModel {
('contain' => ('contain' =>
array('LedgerEntry', array('LedgerEntry',
'DepositTransaction', 'DepositTransaction',
'DepositLedgerEntry',
'NsfTransaction'), 'NsfTransaction'),
)); ));
$this->pr(20, compact('tender')); $this->pr(20, compact('tender'));
@@ -150,15 +128,16 @@ class Tender extends AppModel {
unset($tender['NsfTransaction']); unset($tender['NsfTransaction']);
$T = new Transaction(); $T = new Transaction();
$result = $T->addNsf($tender, $stamp, $comment); $result = $T->addNsf($tender, $stamp);
if (empty($result['error'])) { if ($result['error'])
return $this->prReturn(false);
// Flag the tender as NSF, using the items created from addNsf // Flag the tender as NSF, using the items created from addNsf
$this->id = $id; $this->id = $id;
$this->saveField('nsf_transaction_id', $result['nsf_transaction_id']); $this->saveField('nsf_transaction_id', $result['nsf_transaction_id']);
$this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']); $this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']);
}
return $this->prReturn($result); return $this->prReturn(true);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -55,50 +55,10 @@ class Unit extends AppModel {
return $this->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() { function conditionOccupied() {
return ('Unit.status >= ' . $this->statusValue('OCCUPIED')); return ('Unit.status >= ' . $this->statusValue('OCCUPIED'));
} }
function vacant($enum) {
return $this->statusCheck($enum, 'UNAVAILABLE', true, 'OCCUPIED', true);
}
function conditionVacant() { function conditionVacant() {
return ('Unit.status BETWEEN ' . return ('Unit.status BETWEEN ' .
($this->statusValue('UNAVAILABLE')+1) . ($this->statusValue('UNAVAILABLE')+1) .
@@ -106,16 +66,10 @@ class Unit extends AppModel {
($this->statusValue('OCCUPIED')-1)); ($this->statusValue('OCCUPIED')-1));
} }
function unavailable($enum) {
return $this->statusCheck($enum, null, false, 'UNAVAILABLE', false);
}
function conditionUnavailable() { function conditionUnavailable() {
return ('Unit.status <= ' . $this->statusValue('UNAVAILABLE')); return ('Unit.status <= ' . $this->statusValue('UNAVAILABLE'));
} }
function available($enum) { return $this->vacant($enum); }
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -181,16 +135,6 @@ class Unit extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -15,8 +15,7 @@ echo '<div class="account collected">' . "\n";
// Reset the form // Reset the form
function resetForm() { function resetForm() {
// Kick off the grid /* updateEntriesGrid(); */
updateEntriesGrid();
} }
function onGridLoadComplete() { function onGridLoadComplete() {
@@ -40,15 +39,12 @@ function updateEntriesGrid() {
$('#collected-total').html('Calculating...'); $('#collected-total').html('Calculating...');
$('#collected-entries-jqGrid').clearGridData(); $('#collected-entries-jqGrid').clearGridData();
$('#collected-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post)); $('#collected-entries-jqGrid').setPostDataItem('dynamic_post', serialize(dynamic_post));
$('#collected-entries-jqGrid') $('#collected-entries-jqGrid')
.setGridParam({ page: 1 }) .setGridParam({ page: 1 })
.trigger("reloadGrid"); .trigger("reloadGrid");
//$('#debug').html("<PRE>\n"+htmlEncode(dump($('#collected-entries-jqGrid').getGridParam()))+"\n</PRE>") //$('#collected-entries .HeaderButton').click();
var gridstate = $('#collected-entries-jqGrid').getGridParam('gridstate');
if (gridstate == 'hidden')
$('#collected-entries .HeaderButton').click();
} }
@@ -165,12 +161,12 @@ echo $this->element('statement_entries', array
'grid_div_id' => 'collected-entries', 'grid_div_id' => 'collected-entries',
'grid_div_class' => 'text-below', 'grid_div_class' => 'text-below',
'grid_events' => array('loadComplete' => 'onGridLoadComplete()'), 'grid_events' => array('loadComplete' => 'onGridLoadComplete()'),
'grid_setup' => array('hiddengrid' => true), //'grid_setup' => array('hiddengrid' => true),
//'caption' => '<SPAN id="receipt-charges-caption"></SPAN>',
'caption' => 'Collected ' . Inflector::pluralize($account['name']), 'caption' => 'Collected ' . Inflector::pluralize($account['name']),
'action' => 'collected', 'filter' => array(//'StatementEntry.type' => 'DISBURSEMENT',
'filter' => array('ChargeEntry.account_id' => $account['id']), 'ChargeEntry.account_id' => $account['id']),
'include' => array('Amount'), 'exclude' => array('Account', 'Charge', 'Type'),
'exclude' => array(/*'Type',*/ 'Debit', 'Credit'),
), ),
)); ));
@@ -205,3 +201,5 @@ echo '</div>' . "\n";
echo '</div>' . "\n"; echo '</div>' . "\n";
?> ?>
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>

View File

@@ -11,9 +11,6 @@
* Javascript * Javascript
*/ */
// Warnings _really_ screw up javascript
$saved_debug_state = Configure::read('debug');
Configure::write('debug', '0');
?> ?>
<script type="text/javascript"><!-- <script type="text/javascript"><!--
@@ -26,8 +23,14 @@ Configure::write('debug', '0');
success: showResponse, // post-submit callback success: showResponse, // post-submit callback
// other available options: // 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 //clearForm: true, // clear all form fields after successful submit
//resetForm: true, // reset the form 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' // bind form using 'ajaxForm'
@@ -36,7 +39,16 @@ Configure::write('debug', '0');
// pre-submit callback // pre-submit callback
function verifyRequest(formData, jqForm, options) { function verifyRequest(formData, jqForm, options) {
$('#results').html('Working <BLINK>...</BLINK>'); // 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>');
// here we could return false to prevent the form from being submitted; // here we could return false to prevent the form from being submitted;
// returning anything other than false will allow the form submit to continue // returning anything other than false will allow the form submit to continue
return true; return true;
@@ -44,32 +56,29 @@ function verifyRequest(formData, jqForm, options) {
// post-submit callback // post-submit callback
function showResponse(responseText, statusText) { 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') { 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 // get a clean slate
resetForm(); //resetForm();
// REVISIT <AP>: 20090806 Add to resetForm()
updateCharges($("#customer-id").val());
} }
else { else {
$('#results').html('<H2>Failed to save receipt!</H2>'); alert('not successful??');
alert('Failed to save receipt.');
} }
$('#response-debug').html('<PRE>'+dump(statusText)+'</PRE>');
} }
// Reset the form // Reset the form
@@ -77,35 +86,13 @@ function resetForm() {
$('#payment-entry-id').val(1); $('#payment-entry-id').val(1);
$('#payments').html(''); $('#payments').html('');
addPaymentSource(false); $("#receipt-customer-id").html("INTERNAL ERROR");
updateCharges($("#customer-id").val()); $("#receipt-customer-name").html("INTERNAL ERROR");
} $("#receipt-balance").html("INTERNAL ERROR");
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"); $("#receipt-charges-caption").html("Outstanding Charges");
addPaymentSource(false);
datepickerNow('TransactionStamp');
} }
function onRowSelect(grid_id, customer_id) { function onRowSelect(grid_id, customer_id) {
@@ -118,10 +105,7 @@ function onRowSelect(grid_id, customer_id) {
// This is not intended as a long term solution, // This is not intended as a long term solution,
// but I need a way to enter data and then view // but I need a way to enter data and then view
// the results. This link will help. // the results. This link will help.
$("#receipt-customer-id").html('<A HREF="' + $("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
"<?php echo $html->url(array('controller' => 'customers',
'action' => 'view')); ?>"
+ "/" +
$(grid_id).getCell(customer_id, 'Customer-id').replace(/^#/,'') + $(grid_id).getCell(customer_id, 'Customer-id').replace(/^#/,'') +
'">' + '">' +
$(grid_id).getCell(customer_id, 'Customer-id') + $(grid_id).getCell(customer_id, 'Customer-id') +
@@ -190,7 +174,7 @@ function addPaymentSource(flash) {
'<DIV ID="payment-amount-div-%{id}" CLASS="input text required">' + '<DIV ID="payment-amount-div-%{id}" CLASS="input text required">' +
' <INPUT TYPE="text" SIZE="20"' + ' <INPUT TYPE="text" SIZE="20"' +
' NAME="data[Entry][%{id}][amount]"' + ' NAME="data[Entry][%{id}][amount]"' +
' CLASS="payment amount"' + ' CLASS="payment"' +
' ID="payment-amount-%{id}" />' + ' ID="payment-amount-%{id}" />' +
' <LABEL CLASS="payment" FOR="payment-amount-%{id}">Amount</LABEL>' + ' <LABEL CLASS="payment" FOR="payment-amount-%{id}">Amount</LABEL>' +
'</DIV>' + '</DIV>' +
@@ -236,20 +220,59 @@ function addPaymentSource(flash) {
} }
function switchPaymentType(paymentid_base, paymentid, radioid) { function switchPaymentType(paymentid_base, paymentid, radioid) {
$("."+paymentid_base+"-"+paymentid).slideUp();
var type_id = $("#"+radioid).val(); var type_id = $("#"+radioid).val();
$("."+paymentid_base+"-"+paymentid+
":not(" +
"#"+paymentid_base+"-"+paymentid+"-"+type_id +
")").slideUp();
$("#"+paymentid_base+"-"+paymentid+"-"+type_id).slideDown(); $("#"+paymentid_base+"-"+paymentid+"-"+type_id).slideDown();
}
function updateChargesGrid(idlist) {
var dynamic_post = new Array();
dynamic_post['idlist'] = idlist;
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#charge-entries-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
} }
--></script> function updateCharges(id) {
var url = '<?php echo ($html->url(array("controller" => $this->params["controller"],
"action" => "unreconciled"))); ?>';
url += '/'+id;
$('#charge-entries-jqGrid').clearGridData();
$("#receipt-balance").html("Calculating...");
$("#receipt-charges-caption").html("Please Wait...");
$.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);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
/* alert('ERROR'); */
/* $('#debug').html('<P>request<BR>'+escape(XMLHttpRequest)); */
/* $('#debug').append('<P>status<BR>'+escape(textStatus)); */
/* $('#debug').append('<P>error<BR>'+escape(errorThrown)); */
}
});
}
--></script>
<?php <?php
; // align ; // align
// Re-Enable warnings //echo '<DIV ID="dialog">' . "\n";
Configure::write('debug', $saved_debug_state);
echo $this->element('customers', array echo $this->element('customers', array
('config' => array ('config' => array
@@ -265,7 +288,6 @@ echo $this->element('customers', array
array('gridstate' => array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'), 'onGridState("#"+$(this).attr("id"), gridstate)'),
), ),
'action' => 'current',
'nolinks' => true, 'nolinks' => true,
'limit' => 10, 'limit' => 10,
))); )));
@@ -292,19 +314,17 @@ echo ('<DIV CLASS="receipt grid-selection-text">' .
echo $this->element('statement_entries', array echo $this->element('statement_entries', array
(// Grid configuration (// Element configuration
'account_ftype' => 'credit',
'limit' => 8,
// Grid configuration
'config' => array 'config' => array
( (
'grid_div_id' => 'charge-entries', 'grid_div_id' => 'charge-entries',
'grid_div_class' => 'text-below', 'grid_div_class' => 'text-below',
'grid_events' => array('loadComplete' => 'onGridLoadComplete()'),
'grid_setup' => array('hiddengrid' => true),
'caption' => '<SPAN id="receipt-charges-caption"></SPAN>', 'caption' => '<SPAN id="receipt-charges-caption"></SPAN>',
'action' => 'unreconciled', 'rows' => $charges,
'exclude' => array('Customer', 'Type', 'Debit', 'Credit'),
'include' => array('Applied', 'Balance'),
'remap' => array('Applied' => 'Paid'),
'limit' => 8,
), ),
)); ));
@@ -343,10 +363,6 @@ 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"; echo $form->submit('Generate Receipt') . "\n";
?> ?>
@@ -367,13 +383,9 @@ echo $form->submit('Generate Receipt') . "\n";
<?php /* echo '</DIV>' . "\n"; // End of the dialog DIV */ ?> <?php /* echo '</DIV>' . "\n"; // End of the dialog DIV */ ?>
<div id="results"></div> <div><H4>Request</H4><div id="request-debug"></div></div>
<div id="output-debug" style="display:none"></div> <div><H4>Response</H4><div id="response-debug"></div></div>
<div><H4>Output</H4><div id="output-debug"></div></div>
<?php
// Warnings _really_ screw up javascript
Configure::write('debug', '0');
?>
<script type="text/javascript"><!-- <script type="text/javascript"><!--
$(document).ready(function(){ $(document).ready(function(){
@@ -384,18 +396,12 @@ Configure::write('debug', '0');
showCurrentAtPos: 0, showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' }); dateFormat: 'mm/dd/yy' });
$("#receipt-customer-id").html("INTERNAL ERROR"); resetForm();
$("#receipt-customer-name").html("INTERNAL ERROR");
$("#receipt-balance").html("INTERNAL ERROR");
$("#receipt-charges-caption").html("Outstanding Charges");
<?php if (isset($customer['id'])): ?> <?php if (isset($customer['id'])): ?>
$("#customer-id").val(<?php echo $customer['id']; ?>); $("#customer-id").val(<?php echo $customer['id']; ?>);
//$("#receipt-customer-id").html("<?php echo '#'.$customer['id']; ?>"); //$("#receipt-customer-id").html("<?php echo '#'.$customer['id']; ?>");
$("#receipt-customer-id").html('<A HREF="' + $("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
"<?php echo $html->url(array('controller' => 'customers',
'action' => 'view')); ?>"
+ "/" +
"<?php echo $customer['id']; ?>" + "<?php echo $customer['id']; ?>" +
'">#' + '">#' +
"<?php echo $customer['id']; ?>" + "<?php echo $customer['id']; ?>" +
@@ -407,15 +413,37 @@ Configure::write('debug', '0');
onGridState(null, 'visible'); onGridState(null, 'visible');
<?php endif; ?> <?php endif; ?>
resetForm();
datepickerNow('TransactionStamp');
<?php if ($this->params['dev']): ?>
$('#output-debug').html('Post Output'); /* $("#dialog").dialog({ */
$('#output-debug').show(); /* bgiframe: true, */
<?php endif; ?> /* 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'); */
/* }); */
}); });
--></script> --></script>
</div> </div>
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>

View File

@@ -11,9 +11,6 @@ echo '<div class="customer view">' . "\n";
$rows = array(); $rows = array();
$rows[] = array('Name', $customer['Customer']['name']); $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']); $rows[] = array('Comment', $customer['Customer']['comment']);
echo $this->element('table', echo $this->element('table',
@@ -30,9 +27,7 @@ echo $this->element('table',
echo '<div class="infobox">' . "\n"; echo '<div class="infobox">' . "\n";
$rows = array(); $rows = array();
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit)); $rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
//$rows[] = array('Charges:', FormatHelper::currency($stats['charges'])); $rows[] = array('Balance:', FormatHelper::currency($outstandingBalance));
//$rows[] = array('Payments:', FormatHelper::currency($stats['disbursements']));
$rows[] = array('Balance Owed:', FormatHelper::currency($outstandingBalance));
echo $this->element('table', echo $this->element('table',
array('class' => 'summary', array('class' => 'summary',
'rows' => $rows, 'rows' => $rows,
@@ -85,7 +80,7 @@ echo $this->element('leases', array
echo $this->element('statement_entries', array echo $this->element('statement_entries', array
(// Grid configuration (// Grid configuration
'config' => array 'config' => array
('caption' => 'Customer Statement', ('caption' => 'Account',
'filter' => array('Customer.id' => $customer['Customer']['id'], 'filter' => array('Customer.id' => $customer['Customer']['id'],
'type !=' => 'VOID'), 'type !=' => 'VOID'),
'exclude' => array('Customer'), 'exclude' => array('Customer'),
@@ -95,19 +90,27 @@ echo $this->element('statement_entries', array
/********************************************************************** /**********************************************************************
* Receipt History * Customer Ledger 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 echo $this->element('ledger_entries', array
(// Grid configuration (// Grid configuration
'config' => array 'config' => array
('caption' => 'Receipts', ('caption' => 'Ledger Entries',
'filter' => array('Customer.id' => $customer['Customer']['id'], 'filter' => array('Customer.id' => $customer['Customer']['id'],
'Transaction.type' => 'RECEIPT', 'Account.id !=' => '-AR-'),
'Tender.id !=' => null, 'exclude' => array('Customer'),
//'Account.id !=' => '-AR-'
),
'exclude' => array('Account', 'Cr/Dr'),
'sort_column' => 'Date', 'sort_column' => 'Date',
'sort_order' => 'DESC', 'sort_order' => 'DESC',
))); )));

View File

@@ -52,6 +52,8 @@ $ledgers = array('debit' => $entry['DebitLedger'],
'credit' => $entry['CreditLedger']); 'credit' => $entry['CreditLedger']);
$entries = array('debit' => $entry['DebitEntry'], $entries = array('debit' => $entry['DebitEntry'],
'credit' => $entry['CreditEntry']); 'credit' => $entry['CreditEntry']);
$customer = $entry['Customer'];
$lease = $entry['Lease'];
$entry = $entry['DoubleEntry']; $entry = $entry['DoubleEntry'];
$rows = array(); $rows = array();
@@ -61,6 +63,20 @@ $rows[] = array('Transaction', $html->link('#'.$transaction['id'],
'action' => 'view', 'action' => 'view',
$transaction['id']))); $transaction['id'])));
$rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp'])); $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', echo $this->element('table',
@@ -103,17 +119,10 @@ echo ('<DIV CLASS="ledger-double-entry">' . "\n");
foreach ($ledgers AS $type => $ledger) { foreach ($ledgers AS $type => $ledger) {
$rows = array(); $rows = array();
// REVISIT <AP>: 20090816 $rows[] = array('ID', $html->link('#' . $entries[$type]['id'],
// Due to low priority, the ledger_entry/double_entry stuff array('controller' => 'entries',
// is a bit piecemeal at the moment (trying to reuse old 'action' => 'view',
// code as much as possible). So, LedgerEntry view is just $entries[$type]['id'])));
// redirecting here. Of course, presenting a link for the
// LedgerEntry then is, well, quite pointless.
$rows[] = array('ID', '#' . $entries[$type]['id']);
/* $rows[] = array('ID', $html->link('#' . $entries[$type]['id'], */
/* array('controller' => 'entries', */
/* 'action' => 'view', */
/* $entries[$type]['id']))); */
$rows[] = array('Account', $html->link($ledger['Account']['name'], $rows[] = array('Account', $html->link($ledger['Account']['name'],
array('controller' => 'accounts', array('controller' => 'accounts',
'action' => 'view', 'action' => 'view',
@@ -123,8 +132,8 @@ foreach ($ledgers AS $type => $ledger) {
array('controller' => 'ledgers', array('controller' => 'ledgers',
'action' => 'view', 'action' => 'view',
$ledger['id']))); $ledger['id'])));
$rows[] = array('Amount', FormatHelper::currency($entries[$type]['amount'])); $rows[] = array('Amount', FormatHelper::currency($entry['amount']));
//$rows[] = array('Effect', $ledger['Account']['ftype'] == $type ? 'INCREASE' : 'DECREASE'); $rows[] = array('Effect', $ledger['Account']['ftype'] == $type ? 'INCREASE' : 'DECREASE');
echo $this->element('table', echo $this->element('table',
array('class' => array('item', $type, 'detail'), array('class' => array('item', $type, 'detail'),

View File

@@ -123,7 +123,7 @@ foreach ($fields AS $field => $config) {
} }
echo $this->element('table', echo $this->element('table',
compact('id', 'class', 'caption', 'headers', compact('class', 'caption', 'headers',
'rows', 'row_class', 'suppress_alternate_rows', 'rows', 'row_class', 'suppress_alternate_rows',
'column_class') 'column_class')
); );

View File

@@ -19,7 +19,6 @@ if (!isset($limitOptions)) {
} }
sort($limitOptions, SORT_NUMERIC); sort($limitOptions, SORT_NUMERIC);
$limitOptions = array_unique($limitOptions, SORT_NUMERIC); $limitOptions = array_unique($limitOptions, SORT_NUMERIC);
//$limitOptions[] = 'ALL'; // Would be nice... jqGrid shows 'NaN of NaN'
if (!isset($height)) if (!isset($height))
$height = 'auto'; $height = 'auto';
@@ -47,9 +46,12 @@ if (!isset($grid_setup))
$grid_setup = array(); $grid_setup = array();
// Do some prework to bring in the appropriate libraries // Do some prework to bring in the appropriate libraries
$html->css('ui.jqgrid', null, null, false); $imgpath = '/pmgr/site/css/jqGrid/basic/images';
$javascript->link('jqGrid/grid.locale-en', false); $html->css('jqGrid/basic/grid', null, null, false);
$javascript->link('jqGrid/jquery.jqGrid.min', false); $html->css('jqGrid/jqModal', null, null, false);
$javascript->link('jqGrid/jquery.jqGrid.js', false);
$javascript->link('jqGrid/js/jqModal', false);
$javascript->link('jqGrid/js/jqDnR', false);
$javascript->link('pmgr_jqGrid', false); $javascript->link('pmgr_jqGrid', false);
@@ -61,6 +63,7 @@ $javascript->link('pmgr_jqGrid', false);
// as part of the data fetch. // as part of the data fetch.
$url = $html->url(array('controller' => $controller, $url = $html->url(array('controller' => $controller,
'action' => 'gridData', 'action' => 'gridData',
'debug' => 0,
)); ));
// Create extra parameters that jqGrid will pass to our // Create extra parameters that jqGrid will pass to our
@@ -185,12 +188,9 @@ if (isset($sort_order)) {
$sortorder = 'ASC'; $sortorder = 'ASC';
} }
$debug = !empty($this->params['dev']); if (1) { // debug
if ($debug)
$caption .= '<span class="debug grid-query"> :: <span id="'.$grid_id.'-query"></span></span>'; $caption .= '<span class="debug grid-query"> :: <span id="'.$grid_id.'-query"></span></span>';
}
$caption .= ('<span class="grid-error" id="'.$grid_id.'-error"' .
' style="display:none"> :: Error (Please Reload)</span>');
foreach (array_merge(array('loadComplete' => '', 'loadError' => ''), foreach (array_merge(array('loadComplete' => '', 'loadError' => ''),
$grid_events) AS $event => $statement) { $grid_events) AS $event => $statement) {
@@ -200,21 +200,13 @@ foreach (array_merge(array('loadComplete' => '', 'loadError' => ''),
$statement = current($statement); $statement = current($statement);
} }
if ($event == 'loadComplete' && $debug) { if ($event == 'loadComplete') {
$grid_events[$event] = $grid_events[$event] =
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;}"); 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;}");
} }
elseif ($event == 'loadError' && $debug) { elseif ($event == 'loadError') {
$grid_events[$event] = $grid_events[$event] =
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;}"); 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;}");
}
elseif ($event == 'loadComplete' && !$debug) {
$grid_events[$event] =
array('--special' => "function($params) {jQuery('#{$grid_id}-error').hide(); $statement;}");
}
elseif ($event == 'loadError' && !$debug) {
$grid_events[$event] =
array('--special' => "function($params) {jQuery('#{$grid_id}-error').show(); $statement;}");
} }
else { else {
$grid_events[$event] = $grid_events[$event] =
@@ -239,8 +231,8 @@ $jqGrid_setup = array_merge
'sortname' => $sortname, 'sortname' => $sortname,
'sortorder' => $sortorder, 'sortorder' => $sortorder,
'caption' => $caption, 'caption' => $caption,
'imgpath' => $imgpath,
'viewrecords' => true, 'viewrecords' => true,
'gridview' => true,
'pager' => $grid_id.'-pager', 'pager' => $grid_id.'-pager',
), ),
$grid_events, $grid_events,
@@ -259,16 +251,16 @@ $jqGrid_setup = array_merge
<script type="text/javascript"><!-- <script type="text/javascript"><!--
jQuery(document).ready(function(){ jQuery(document).ready(function(){
currencyFormatter = function(cellval, opts, rowObject) { currencyFormatter = function(el, cellval, opts) {
if (!cellval) if (!cellval)
return ""; return;
return fmtCurrency(cellval); $(el).html(fmtCurrency(cellval));
} }
idFormatter = function(cellval, opts, rowObject) { idFormatter = function(el, cellval, opts) {
if (!cellval) if (!cellval)
return cellval; return;
return '#'+cellval; $(el).html('#'+cellval);
} }
jQuery('#<?php echo $grid_id; ?>').jqGrid( jQuery('#<?php echo $grid_id; ?>').jqGrid(
@@ -280,6 +272,36 @@ jQuery(document).ready(function(){
del:false, del:false,
search:true, search:true,
refresh:true}); refresh:true});
<?php
/* jQuery('#t_<?php echo $grid_id; ?>').height(25).hide() */
/* .filterGrid('#<?php echo $grid_id; ?>', { */
/* gridModel:true, */
/* gridToolbar:true, */
/* autosearch:true, */
/* }); */
/* jQuery('#<?php echo $grid_id; ?>').navGrid('#<?php echo $grid_id; ?>-pager', */
/* { view:false, */
/* edit:false, */
/* add:false, */
/* del:false, */
/* search:false, */
/* refresh:false}) */
/* .navButtonAdd('#<?php echo $grid_id; ?>-pager',{ */
/* caption:"Search", */
/* title:"Toggle Search", */
/* buttonimg:'<?php echo $imgpath; ?>' + '/find.gif', */
/* onClickButton:function(){ */
/* if(jQuery('#t_<?php echo $grid_id; ?>').css("display")=="none") { */
/* jQuery('#t_<?php echo $grid_id; ?>').css("display",""); */
/* } else { */
/* jQuery('#t_<?php echo $grid_id; ?>').css("display","none"); */
/* } */
/* } */
/* }); */
?>
}); });
--></script> --></script>

View File

@@ -11,21 +11,9 @@ $cols['Deposit'] = array('index' => 'Lease.deposit', 'formatter' => 'cur
$cols['Signed'] = array('index' => 'Lease.lease_date', 'formatter' => 'date'); $cols['Signed'] = array('index' => 'Lease.lease_date', 'formatter' => 'date');
$cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date'); $cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date');
$cols['Move-Out'] = array('index' => 'Lease.moveout_date', 'formatter' => 'date'); $cols['Move-Out'] = array('index' => 'Lease.moveout_date', 'formatter' => 'date');
$cols['Closed'] = array('index' => 'Lease.close_date', 'formatter' => 'date');
$cols['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['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
$cols['Comment'] = array('index' => 'Lease.comment', 'formatter' => 'comment'); $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 // Render the grid
$grid $grid
->columns($cols) ->columns($cols)
@@ -33,4 +21,4 @@ $grid
->defaultFields(array('LeaseID', 'Lease')) ->defaultFields(array('LeaseID', 'Lease'))
->searchFields(array('Customer', 'Unit')) ->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Signed', 'Status', 'Comment'))); array_diff(array_keys($cols), array('Comment')));

View File

@@ -9,6 +9,8 @@ $cols['Date'] = array('index' => 'Transaction.stamp', 'formatter' =>
$cols['Effective'] = array('index' => 'StatementEntry.effective_date', 'formatter' => 'date'); $cols['Effective'] = array('index' => 'StatementEntry.effective_date', 'formatter' => 'date');
$cols['Through'] = array('index' => 'StatementEntry.through_date', 'formatter' => 'date'); $cols['Through'] = array('index' => 'StatementEntry.through_date', 'formatter' => 'date');
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name');
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname'); $cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id'); $cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id');
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname'); $cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname');
@@ -16,15 +18,10 @@ $cols['Unit'] = array('index' => 'Unit.name', 'formatter' =>
$cols['Comment'] = array('index' => 'StatementEntry.comment', 'formatter' => 'comment', 'width'=>150); $cols['Comment'] = array('index' => 'StatementEntry.comment', 'formatter' => 'comment', 'width'=>150);
$cols['Type'] = array('index' => 'StatementEntry.type', 'formatter' => 'enum', 'width'=>120); $cols['Type'] = array('index' => 'StatementEntry.type', 'formatter' => 'enum', 'width'=>120);
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name');
$cols['Debit'] = array('index' => 'charge', 'formatter' => 'currency'); $cols['Debit'] = array('index' => 'charge', 'formatter' => 'currency');
$cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency'); $cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency');
$cols['Amount'] = array('index' => "StatementEntry.amount", 'formatter' => 'currency');
$cols['Applied'] = array('index' => "applied", '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); $cols['Sub-Total'] = array('index' => 'subtotal-balance', 'formatter' => 'currency', 'sortable' => false);
@@ -43,6 +40,6 @@ $grid
->searchFields(array('Customer', 'Unit')) ->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Through', 'Lease', array_diff(array_keys($cols), array('Through', 'Lease',
'Amount', 'Applied', 'Balance', 'Sub-Total', 'Applied', 'Sub-Total',
'Comment'))); 'Comment')));

View File

@@ -64,10 +64,7 @@ if (isset($rows) && is_array($rows) && count($rows)) {
$class = implode(' ', $class); $class = implode(' ', $class);
// OK, output the table HTML // OK, output the table HTML
echo('<TABLE' . echo('<TABLE' . (isset($class) ? ' CLASS="'.$class.'"' : '') . '>' . "\n");
(isset($id) ? ' ID="'.$id.'"' : '') .
(isset($class) ? ' CLASS="'.$class.'"' : '') .
'>' . "\n");
if (isset($caption)) if (isset($caption))
echo(' <CAPTION>' . $caption . '</CAPTION>' . "\n"); echo(' <CAPTION>' . $caption . '</CAPTION>' . "\n");

View File

@@ -8,7 +8,6 @@ $cols['ID'] = array('index' => 'Unit.id', 'formatter' => 'id');
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname'); $cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname');
$cols['Size'] = array('index' => 'UnitSize.name', 'formatter' => 'shortname'); $cols['Size'] = array('index' => 'UnitSize.name', 'formatter' => 'shortname');
$cols['Rent'] = array('index' => 'Unit.rent', 'formatter' => 'currency'); $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['Status'] = array('index' => 'Unit.status', 'formatter' => 'name'); // We have enough real estate
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency'); $cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
$cols['Comment'] = array('index' => 'Unit.comment', 'formatter' => 'comment'); $cols['Comment'] = array('index' => 'Unit.comment', 'formatter' => 'comment');
@@ -20,4 +19,4 @@ $grid
->defaultFields(array('Sort', 'ID', 'Unit')) ->defaultFields(array('Sort', 'ID', 'Unit'))
->searchFields(array('Unit', 'Size', 'Status')) ->searchFields(array('Unit', 'Size', 'Status'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Walk', 'Deposit', 'Comment'))); array_diff(array_keys($cols), array('Walk', 'Comment')));

View File

@@ -1,5 +0,0 @@
<?php /* -*- mode:PHP -*- */
if (!empty($message))
echo $message;

View File

@@ -24,21 +24,9 @@ class FormatHelper extends AppHelper {
return '-'; return '-';
//return null; //return null;
// Use of the $number->currency() function results in the clever, $currency = self::$number->currency($amount,
// but problematic, use of cents for amounts less than $1. For isset($dollar_sign) ? $dollar_sign : 'USD',
// example, 50 cents is shown as '50c', not '$0.50'. We want to $spans ? array('before'=>'', 'after'=>'') : array());
// 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) if ($spans)
return ('<SPAN CLASS="dollar-sign">$</SPAN>' . return ('<SPAN CLASS="dollar-sign">$</SPAN>' .
@@ -47,29 +35,22 @@ class FormatHelper extends AppHelper {
return $currency; return $currency;
} }
function date($date, $age = false, $class = null, $time = false) { function date($date, $age = false) {
if (!$date) return null; if (!$date) return null;
if (empty($class)) $date_fmt = 'm/d/Y';
$class = ''; return (self::$time->format($date_fmt, $date) .
($age
if ($time) ? ' (' . self::age($date, 60*60*24) . ')'
$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, true, $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) .
function datetime($datetime, $age = false, $class = null) { ($age
return self::date($datetime, $age, $class, true); ? ' (' . self::age($datetime) . ')'
: ''));
} }
function phone($phone, $ext = null) { function phone($phone, $ext = null) {
@@ -100,13 +81,10 @@ class FormatHelper extends AppHelper {
return $comment; return $comment;
} }
function age($datetime, $class, $suffix = false, $min_span = 0) { function age($datetime, $min_span = 0) {
if (!isset($datetime)) if (!isset($datetime))
return null; return null;
if (empty($class))
$class = '';
$now = time(); $now = time();
$seconds = self::$time->fromString($datetime); $seconds = self::$time->fromString($datetime);
$backwards = ($seconds > $now); $backwards = ($seconds > $now);
@@ -117,11 +95,9 @@ class FormatHelper extends AppHelper {
//pr(compact('now', 'seconds', 'backwards', 'timefrom', 'timeto', 'span', 'min_span')); //pr(compact('now', 'seconds', 'backwards', 'timefrom', 'timeto', 'span', 'min_span'));
// If now, just use 'now' // If now, just return so
if ($span === 0) { if ($span === 0)
$approx = 0; return __('now', true);
$unit = 'now';
}
// Display seconds if under 45 seconds // Display seconds if under 45 seconds
if ($span < 45 && $span >= $min_span) { if ($span < 45 && $span >= $min_span) {
@@ -188,36 +164,20 @@ class FormatHelper extends AppHelper {
//pr(compact('span', 'min_span', 'approx', 'unit')); //pr(compact('span', 'min_span', 'approx', 'unit'));
if ($approx == 0) { if ($approx == 0) {
if ($unit == 'now') if ($unit == 'day')
$age = 'now'; return __('today', true);
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 = '';
$age .= ' ' . self::_n($approx, $unit); return __('this ' . $unit, true);
if ($suffix) {
if ($backwards)
$age .= ' from now';
else
$age .= ' ago';
}
} }
$age = '<span class="fmt-age '.$class.'">'.__($age, true).'</span>'; return (__(isset($relative)
? $relative
return $age; : ($approx == $span
? ''
: ($approx > $span ? 'almost' : 'over')), true)
. ' '
. self::_n($approx, $unit)
. ($backwards ? '' : __(' ago', true)));
} }
/***************************** /*****************************

View File

@@ -166,14 +166,9 @@ class GridHelper extends AppHelper {
$included = array_diff(array_merge($this->included, $included), $included = array_diff(array_merge($this->included, $included),
array_merge($this->invalid, $excluded)); array_merge($this->invalid, $excluded));
// Defined the columns, based on the inclusion set, // Extract the columns that correspond to the inclusion set
// remapping column names as necessary. $this->jqGrid_options['jqGridColumns']
$this->jqGrid_options['jqGridColumns'] = array(); = array_intersect_key($this->columns, array_flip($included));
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 // Make sure search fields are all part of the inclusion set
$this->jqGrid_options['search_fields'] $this->jqGrid_options['search_fields']

View File

@@ -35,12 +35,12 @@
echo $html->css('layout') . "\n"; echo $html->css('layout') . "\n";
echo $html->css('print', null, array('media' => 'print')) . "\n"; echo $html->css('print', null, array('media' => 'print')) . "\n";
echo $html->css('sidemenu') . "\n"; echo $html->css('sidemenu') . "\n";
echo $javascript->link('http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js') . "\n"; //echo $html->css('jquery/base/ui.all') . "\n";
echo $javascript->link('http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js') . "\n"; //echo $html->css('jquery/smoothness/ui.all') . "\n";
//echo $html->css('themes/base/ui.all') . "\n"; //echo $html->css('jquery/dotluv/ui.all') . "\n";
//echo $html->css('themes/smoothness/ui.all') . "\n"; echo $html->css('jquery/start/ui.all') . "\n";
//echo $html->css('themes/dotluv/ui.all') . "\n"; echo $javascript->link('jquery/jquery') . "\n";
echo $html->css('themes/start/ui.all') . "\n"; echo $javascript->link('jquery/jquery-ui') . "\n";
echo $javascript->link('jquery.form') . "\n"; echo $javascript->link('jquery.form') . "\n";
echo $javascript->link('pmgr') . "\n"; echo $javascript->link('pmgr') . "\n";
echo $scripts_for_layout . "\n"; echo $scripts_for_layout . "\n";

View File

@@ -4,13 +4,6 @@
<?php <?php
; // Editor alignment ; // Editor alignment
$unit = $lease['Unit'];
$customer = $lease['Customer'];
if (isset($lease['Lease']))
$lease = $lease['Lease'];
/********************************************************************** /**********************************************************************
********************************************************************** **********************************************************************
********************************************************************** **********************************************************************
@@ -18,9 +11,6 @@ if (isset($lease['Lease']))
* Javascript * Javascript
*/ */
// Warnings _really_ screw up javascript
$saved_debug_state = Configure::read('debug');
Configure::write('debug', '0');
?> ?>
<script type="text/javascript"><!-- <script type="text/javascript"><!--
@@ -33,8 +23,14 @@ Configure::write('debug', '0');
success: showResponse, // post-submit callback success: showResponse, // post-submit callback
// other available options: // 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 //clearForm: true, // clear all form fields after successful submit
//resetForm: true, // reset the form 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' // bind form using 'ajaxForm'
@@ -43,7 +39,16 @@ Configure::write('debug', '0');
// pre-submit callback // pre-submit callback
function verifyRequest(formData, jqForm, options) { function verifyRequest(formData, jqForm, options) {
$('#results').html('Working <BLINK>...</BLINK>'); // 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>');
// here we could return false to prevent the form from being submitted; // here we could return false to prevent the form from being submitted;
// returning anything other than false will allow the form submit to continue // returning anything other than false will allow the form submit to continue
return true; return true;
@@ -51,47 +56,42 @@ function verifyRequest(formData, jqForm, options) {
// post-submit callback // post-submit callback
function showResponse(responseText, statusText) { 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') { 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')); ?>"
+ "/" + "<?php echo $customer['id']; ?>";
<?php endif; ?>
return;
}
// get a clean slate // get a clean slate
resetForm(); //resetForm();
} }
else { else {
$('#results').html('<H2>Failed to save invoice!</H2>'); alert('not successful??');
alert('Failed to save invoice.');
} }
$('#response-debug').html('<PRE>'+dump(statusText)+'</PRE>');
} }
// Reset the form // Reset the form
function resetForm(nocharge) { function resetForm() {
$('#charge-entry-id').val(1); $("#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");
if (!nocharge)
addChargeSource(false); addChargeSource(false);
datepickerNow('TransactionStamp');
} }
@@ -105,10 +105,7 @@ function onRowSelect(grid_id, lease_id) {
// This is not intended as a long term solution, // This is not intended as a long term solution,
// but I need a way to enter data and then view // but I need a way to enter data and then view
// the results. This link will help. // the results. This link will help.
$("#invoice-lease").html('<A HREF="' + $("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
"<?php echo $html->url(array('controller' => 'leases',
'action' => 'view')); ?>"
+ "/" +
$(grid_id).getCell(lease_id, 'Lease-id').replace(/^#/,'') + $(grid_id).getCell(lease_id, 'Lease-id').replace(/^#/,'') +
'">' + '">' +
$(grid_id).getCell(lease_id, 'Lease-number') + $(grid_id).getCell(lease_id, 'Lease-number') +
@@ -155,8 +152,7 @@ function addChargeSource(flash) {
<?php <?php
echo FormatHelper::phpVarToJavascript echo FormatHelper::phpVarToJavascript
($this->element('form_table', ($this->element('form_table',
array('id' => 'Entry%{id}Form', array('class' => "item invoice ledger-entry entry",
'class' => "item invoice ledger-entry entry",
//'with_name_after' => ':', //'with_name_after' => ':',
'field_prefix' => 'Entry.%{id}', 'field_prefix' => 'Entry.%{id}',
'fields' => array 'fields' => array
@@ -174,7 +170,7 @@ function addChargeSource(flash) {
array('type' => 'text'), array('type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>', 'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>',
), ),
"amount" => array('opts' => array('class' => 'invoice amount')), "amount" => true,
"comment" => array('opts' => array('size' => 50)), "comment" => array('opts' => array('size' => 50)),
), ),
))) . "+\n"; ))) . "+\n";
@@ -196,25 +192,20 @@ function addChargeSource(flash) {
numberOfMonths: [1, 1], numberOfMonths: [1, 1],
showCurrentAtPos: 0, showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' }); dateFormat: 'mm/dd/yy' });
return id;
} }
--></script> --></script>
<?php <?php
; // align ; // align
// Re-Enable warnings
Configure::write('debug', $saved_debug_state);
if (empty($movein)) echo $this->element('leases', array
echo $this->element('leases', array
('config' => array ('config' => array
('grid_div_id' => 'leases-list', ('grid_div_id' => 'leases-list',
'grid_div_class' => 'text-below', 'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'. 'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
' return false;">Select Lease</A>'), ' return false;">Select Lease</A>'),
'grid_setup' => array('hiddengrid' => isset($lease['id'])), 'grid_setup' => array('hiddengrid' => isset($lease['Lease']['id'])),
'grid_events' => array('onSelectRow' => 'grid_events' => array('onSelectRow' =>
array('ids' => array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'), 'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
@@ -222,7 +213,6 @@ if (empty($movein))
array('gridstate' => array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'), 'onGridState("#"+$(this).attr("id"), gridstate)'),
), ),
'action' => 'active',
'nolinks' => true, 'nolinks' => true,
'limit' => 10, 'limit' => 10,
))); )));
@@ -277,13 +267,6 @@ echo $this->element('form_table',
/* echo '</fieldset>' . "\n"; */ /* 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"; echo $form->submit('Generate Invoice') . "\n";
?> ?>
@@ -298,20 +281,11 @@ echo $form->submit('Generate Invoice') . "\n";
<?php echo $form->end('Generate Invoice'); ?> <?php echo $form->end('Generate Invoice'); ?>
<div id="results"></div> <div><H4>Request</H4><div id="request-debug"></div></div>
<div id="output-debug" style="display:none"></div> <div><H4>Response</H4><div id="response-debug"></div></div>
<div><H4>Output</H4><div id="output-debug"></div></div>
<?php
// Warnings _really_ screw up javascript
Configure::write('debug', '0');
?>
<script type="text/javascript"><!-- <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(){ $(document).ready(function(){
$("#TransactionStamp") $("#TransactionStamp")
.attr('autocomplete', 'off') .attr('autocomplete', 'off')
@@ -320,110 +294,28 @@ Configure::write('debug', '0');
showCurrentAtPos: 0, showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' }); dateFormat: 'mm/dd/yy' });
$("#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 (empty($movein)): ?>
resetForm(); resetForm();
datepickerNow('TransactionStamp');
<?php else: ?> <?php if (isset($lease['Lease']['id'])): ?>
$("#lease-id").val(<?php echo $lease['Lease']['id']; ?>);
var id; //$("#invoice-lease").html("<?php echo '#'.$lease['Lease']['number']; ?>");
resetForm(true); $("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
"<?php echo $lease['Lease']['id']; ?>" +
$("#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['number']; ?>" + "<?php echo $lease['Lease']['number']; ?>" +
'</A>'); '</A>');
$("#invoice-unit").html("<?php echo $unit['name']; ?>"); $("#invoice-unit").html("<?php echo $lease['Unit']['name']; ?>");
$("#invoice-customer").html("<?php echo $customer['name']; ?>"); $("#invoice-customer").html("<?php echo $lease['Customer']['name']; ?>");
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['rent']); ?>"); $("#invoice-rent").html("<?php echo FormatHelper::currency($lease['Lease']['rent']); ?>");
$("#invoice-late").html("<?php echo FormatHelper::currency($defaultLate); ?>"); $("#invoice-late").html('$10.00');
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['deposit']); ?>"); $("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['Lease']['deposit']); ?>");
onGridState(null, 'hidden'); onGridState(null, 'hidden');
<?php else: ?> <?php else: ?>
onGridState(null, 'visible'); onGridState(null, 'visible');
<?php endif; ?> <?php endif; ?>
<?php if ($this->params['dev']): ?>
$('#output-debug').html('Post Output');
$('#output-debug').show();
<?php endif; ?>
}); });
--></script> --></script>
</div> </div>
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>

View File

@@ -41,12 +41,6 @@ function onRowSelect(grid_id, item_type, item_id) {
// Get the item name from the grid // Get the item name from the grid
$("#move-"+item_type).html($(grid_id).getCell(item_id, cell_name)); $("#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 // Hide the "no customer" message and show the current customer
$("."+item_type+"-selection-invalid").hide(); $("."+item_type+"-selection-invalid").hide();
$("."+item_type+"-selection-valid").show(); $("."+item_type+"-selection-valid").show();
@@ -126,9 +120,7 @@ if ($move_type !== 'out') {
array('gridstate' => array('gridstate' =>
'onGridState("#"+$(this).attr("id"), "unit", gridstate)'), 'onGridState("#"+$(this).attr("id"), "unit", gridstate)'),
), ),
'include' => array('Deposit'), 'action' => 'unoccupied',
'exclude' => array('Balance'),
'action' => 'vacant',
'nolinks' => true, 'nolinks' => true,
'limit' => 10, 'limit' => 10,
))); )));
@@ -177,20 +169,7 @@ echo $this->element('form_table',
'id' => "LeaseMoveDate"), 'id' => "LeaseMoveDate"),
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'LeaseMoveDate\', false); return false;">Now</A>', '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' ($move_type !== 'out'
? array('opts' => array('size' => 50)) ? array('opts' => array('size' => 50))
: null), : null),

View File

@@ -58,7 +58,7 @@ echo $this->element('form_table',
"amount" => array('prefix' => 'Entry.0', "amount" => array('prefix' => 'Entry.0',
'opts' => 'opts' =>
array('value' => array('value' =>
FormatHelper::currency($balance), FormatHelper::currency($balance, false, ''),
), ),
), ),
"account_id" => array('prefix' => 'Entry.0', "account_id" => array('prefix' => 'Entry.0',

View File

@@ -39,6 +39,7 @@ $rows[] = array('Notice Received', FormatHelper::date($lease['notice_received_d
$rows[] = array('Closed', FormatHelper::date($lease['close_date'], true)); $rows[] = array('Closed', FormatHelper::date($lease['close_date'], true));
$rows[] = array('Deposit', FormatHelper::currency($lease['deposit'])); $rows[] = array('Deposit', FormatHelper::currency($lease['deposit']));
$rows[] = array('Rent', FormatHelper::currency($lease['rent'])); $rows[] = array('Rent', FormatHelper::currency($lease['rent']));
$rows[] = array('Paid Through', FormatHelper::date($lease['paid_through'], true));
$rows[] = array('Comment', $lease['comment']); $rows[] = array('Comment', $lease['comment']);
@@ -56,10 +57,7 @@ echo $this->element('table',
echo '<div class="infobox">' . "\n"; echo '<div class="infobox">' . "\n";
$rows = array(); $rows = array();
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit)); $rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
$rows[] = array('Balance Owed:', FormatHelper::currency($outstandingBalance)); $rows[] = array('Balance:', 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', echo $this->element('table',
array('class' => 'summary', array('class' => 'summary',
'rows' => $rows, 'rows' => $rows,
@@ -86,7 +84,7 @@ echo '<div CLASS="detail supporting">' . "\n";
echo $this->element('statement_entries', array echo $this->element('statement_entries', array
(// Grid configuration (// Grid configuration
'config' => array 'config' => array
('caption' => 'Lease Statement', ('caption' => 'Account',
'filter' => array('Lease.id' => $lease['id']), 'filter' => array('Lease.id' => $lease['id']),
'include' => array('Through'), 'include' => array('Through'),
'exclude' => array('Customer', 'Lease', 'Unit'), 'exclude' => array('Customer', 'Lease', 'Unit'),
@@ -95,25 +93,6 @@ echo $this->element('statement_entries', array
))); )));
/**********************************************************************
* Receipt History
*/
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('caption' => 'Customer Receipts',
'filter' => array('Customer.id' => $customer['id'],
'Transaction.type' => 'RECEIPT',
'Tender.id !=' => null,
//'Account.id !=' => '-AR-'
),
'exclude' => array('Account', 'Cr/Dr'),
'sort_column' => 'Date',
'sort_order' => 'DESC',
)));
/* End "detail supporting" div */ /* End "detail supporting" div */
echo '</div>' . "\n"; echo '</div>' . "\n";

View File

@@ -14,7 +14,6 @@ $ledger = $entry['Ledger'];
$account = $ledger['Account']; $account = $ledger['Account'];
$tender = $entry['Tender']; $tender = $entry['Tender'];
$matching = $entry['MatchingEntry']; $matching = $entry['MatchingEntry'];
$double = $entry['DoubleEntry'];
$entry = $entry['LedgerEntry']; $entry = $entry['LedgerEntry'];
$rows = array(); $rows = array();
@@ -44,10 +43,6 @@ $rows[] = array('Cr/Dr', ($entry['crdr'] .
'action' => 'view', 'action' => 'view',
$matching['id'])) . $matching['id'])) .
')')); ')'));
$rows[] = array('Double Entry', $html->link('#'.$double['id'],
array('controller' => 'double_entries',
'action' => 'view',
$double['id'])));
$rows[] = array('Comment', $entry['comment']); $rows[] = array('Comment', $entry['comment']);
echo $this->element('table', echo $this->element('table',

View File

@@ -16,20 +16,8 @@
$html->url(array('controller' => 'units', $html->url(array('controller' => 'units',
'action' => 'view', 'action' => 'view',
$unit['id'])) . $unit['id'])) .
'" alt="Unit #' . '" alt="' .
$unit['name'] . $unit['name'] .
'" title="Unit #' .
$unit['name'] .
(empty($unit['data']['CurrentLease']['id'])
? ''
: ('; ' .
/* 'Lease #' . */
/* $unit['data']['CurrentLease']['id'] . */
/* '; ' . */
$unit['data']['Customer']['name'] .
'; Paid Through ' .
$unit['data']['CurrentLease']['paid_through_date'])
) .
'">' . "\n"); '">' . "\n");
} }
}// for indentation purposes }// for indentation purposes

View File

@@ -1,74 +0,0 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="reverse input">' . "\n";
$customer = $entry['Customer'];
$transaction = $entry['Transaction'];
$account = $entry['Account'];
if (isset($entry['StatementEntry']))
$entry = $entry['StatementEntry'];
// We're not actually using a grid to select the customer,
// but selection-text makes for reasonable formatting
echo ('<DIV CLASS="reverse 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;">' . $account['name'] . '</TD>' .
' <TD>' . '(StatementEntry #' . $entry['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' => 'reverse-form',
'url' => array('action' => 'reverse'))) . "\n";
echo $form->input("StatementEntry.id",
array('type' => 'hidden',
'value' => $entry['id'])) . "\n";
echo $this->element('form_table',
array('class' => "item reverse 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('Reverse Charge');
?>
<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>

View File

@@ -15,7 +15,7 @@ $customer = $entry['Customer'];
$lease = $entry['Lease']; $lease = $entry['Lease'];
$entry = $entry['StatementEntry']; $entry = $entry['StatementEntry'];
$Ttype = ucwords(strtolower(str_replace('_', ' ', $transaction['type']))); $Ttype = ucfirst(strtolower($transaction['type']));
$rows = array(); $rows = array();
$rows[] = array('ID', $entry['id']); $rows[] = array('ID', $entry['id']);
@@ -113,9 +113,9 @@ echo $this->element('statement_entries', array
// Grid configuration // Grid configuration
'config' => array 'config' => array
('caption' => $applied_caption, ('caption' => 'Entries Applied',
//'filter' => array('id' => $entry['id']), //'filter' => array('id' => $entry['id']),
'exclude' => array('Transaction'), 'exclude' => array('Entry'),
))); )));

View File

@@ -30,8 +30,7 @@ foreach ($depositTypes AS $type) {
'separator' => '<BR>', 'separator' => '<BR>',
'onclick' => "switchSelection({$type['id']})", 'onclick' => "switchSelection({$type['id']})",
'legend' => false, 'legend' => false,
// REVISIT <AP>: 20080811; Make opt-in, or opt-out? 'value' => $type['stats']['undeposited'] > 0 ? 'all' : 'none',
'value' => $type['stats']['undeposited'] > 0 ? 'none' : 'none',
'disabled' => $type['stats']['undeposited'] <= 0, 'disabled' => $type['stats']['undeposited'] <= 0,
'options' => $radioOptions, 'options' => $radioOptions,
)); ));

View File

@@ -1,90 +0,0 @@
<?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";

View File

@@ -1,74 +0,0 @@
<?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>

View File

@@ -11,14 +11,13 @@ echo '<div class="transaction view">' . "\n";
$account = $transaction['Account']; $account = $transaction['Account'];
$ledger = $transaction['Ledger']; $ledger = $transaction['Ledger'];
$nsf_tender = $transaction['NsfTender'];
if (isset($transaction['Transaction'])) if (isset($transaction['Transaction']))
$transaction = $transaction['Transaction']; $transaction = $transaction['Transaction'];
$rows = array(); $rows = array();
$rows[] = array('ID', $transaction['id']); $rows[] = array('ID', $transaction['id']);
$rows[] = array('Type', str_replace('_', ' ', $transaction['type'])); $rows[] = array('Type', $transaction['type']);
$rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp'])); $rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp']));
$rows[] = array('Amount', FormatHelper::currency($transaction['amount'])); $rows[] = array('Amount', FormatHelper::currency($transaction['amount']));
$rows[] = array('Account', $html->link($account['name'], $rows[] = array('Account', $html->link($account['name'],
@@ -29,11 +28,6 @@ $rows[] = array('Ledger', $html->link($ledger['name'],
array('controller' => 'ledgers', array('controller' => 'ledgers',
'action' => 'view', 'action' => 'view',
$ledger['id']))); $ledger['id'])));
if (!empty($nsf_tender['id']))
$rows[] = array('NSF Tender', $html->link($nsf_tender['name'],
array('controller' => 'tenders',
'action' => 'view',
$nsf_tender['id'])));
$rows[] = array('Comment', $transaction['comment']); $rows[] = array('Comment', $transaction['comment']);
echo $this->element('table', echo $this->element('table',
@@ -85,8 +79,7 @@ if ($transaction['type'] === 'INVOICE' ||
'caption' => 'Statement Entries', 'caption' => 'Statement Entries',
'filter' => array('Transaction.id' => $transaction['id'], 'filter' => array('Transaction.id' => $transaction['id'],
'type !=' => 'VOID'), 'type !=' => 'VOID'),
'exclude' => array('Transaction', 'Debit', 'Credit'), 'exclude' => array('Transaction', 'Account'),
'include' => array('Amount'),
))); )));
} }

View File

@@ -81,14 +81,12 @@ if (isset($current_lease['id'])) {
'config' => array 'config' => array
( (
'caption' => 'caption' =>
('Current Lease Statement (' ('Current Lease Account ('
. $current_lease['Customer']['name'] . $current_lease['Customer']['name']
. ')'), . ')'),
'filter' => array('Lease.id' => $current_lease['id']), 'filter' => array('Lease.id' => $current_lease['id']),
'include' => array('Through'), 'include' => array('Through'),
'exclude' => array('Customer', 'Lease', 'Unit'), 'exclude' => array('Customer', 'Lease', 'Unit'),
'sort_column' => 'Effective',
'sort_order' => 'DESC',
))); )));
} }

View File

@@ -0,0 +1,447 @@
.GridHeader {
}
.Header {
width: 100%;
}
.Header th {
font-size: 100%; font-weight: bold; text-align: left;
padding: 2px;
background-image: url(images/headerbg.gif) ;
color: #FFFFFF;
width: 100%;
white-space: nowrap;
}
.HeaderLeft {
background-image: url(images/headerleft.gif);
}
.HeaderRight {
background-image: url(images/headerright.gif);
}
.HeaderButton {
background-image: url(images/headerbg.gif);
}
.HeaderButton img{
width: 17px;
}
.HeaderLeft img{
width: 14px;
}
.HeaderRight img{
width: 10px;
}
.GridHeader table {margin:0;}
.GridHeader td, tr {padding:0;}
/* Grid */
table.scroll {
table-layout: fixed;
/*border-right: 1px solid #D4D0C8;*/
margin-bottom:0;
}
table.scroll tbody tr {
background-color: #ffffff;
}
table.scroll tbody tr.alt {
background-color: #F9F9F9;
}
table.scroll tr.over td{
background-color: #E1DCF4;
}
table.scroll tr.selected td {
background: #3d84cc;
color: White;
}
table.scroll tbody td {
padding: 2px;
text-align: left;
border-bottom: 1px solid #D4D0C8;
border-left: 1px solid #D4D0C8;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
height : auto;
}
table.scroll thead th {
padding: 2px;
border-bottom: 1px solid #CBC7B8;
border-left: 1px solid #D4D0C8;
text-align: left;
font-weight: normal;
overflow: hidden;
white-space: nowrap;
background-image: url(images/grid-blue-hd.gif);
height : 17px;
}
table.scroll th div {
overflow: hidden;
/* white-space: nowrap;*/
word-wrap: break-word;
height : 17px;
}
table.scroll th span {
cursor: e-resize;
/* border-right: 1px solid #D6D2C2; */
width: 10px;
float: right;
display: block;
margin: -2px -1px -2px 0px;
height: 17px;
overflow: hidden;
white-space: nowrap;
}
/* End Grid */
/* Pager */
div.scroll {
vertical-align: top;
height: 23px;
white-space: nowrap;
text-align: center;
background-image: url(images/grid-blue-ft.gif);
}
div.scroll span {
vertical-align : top;
}
.selbox {
font-size: x-small;
vertical-align : top;
}
input.selbox{
font-size: x-small;
vertical-align : top;
}
.pgbuttons {
margin-top :2px;
}
.nav-table-left {
padding:1px;
float: left;
/* position:absolute;*/
}
.nav-table-right {
padding:1px;
float: right;
}
table.navtable {margin-bottom:0; width: auto;}
table.navtable tr{
background-image: url(images/grid-blue-ft.gif);
}
table.navtable td.nav-button {
border: 1px solid #E2ECF8;
white-space: nowrap;
}
table.navtable td.nav-hover {
border: 1px solid #83B4D8;
}
table.tbutton tr td{
border : none;
padding:0px;
}
img.jsHover { /*not used */
border: 1px solid #99CCFF;
}
/* End Pager */
/*multiselect checkbox */
.cbox {
height: 10px;
width: 10px;
/*border:1px solid #999;*/
}
/* end multiselect */
/* loading div */
div.loading {
position: absolute;
padding: 3px;
text-align: center;
font-weight: bold;
background: red;
color: white;
display: none;
}
div.loadingui {
display:none;
z-index:6000;
position:absolute;
}
div.loadingui div.msgbox {
position: relative;
z-index:6001;
left: 35%;
top:45%;
background: url(images/loading.gif) no-repeat left;
width: 100px;
border: 2px solid #B2D2FF;
text-align: right;
height: auto;
padding:2px;
margin: 0px;
}
/* end loading div */
/* toolbar */
div.userdata {
margin-top: 0px;
background-color : #EAF9F9;
height : 20px;
overflow: hidden;
}
/* end toolbar */
/*Subgrid text mode*/
.subgrid {
height: 100%;
overflow: auto;
}
.tablediv {
background-color: White;
border-spacing: 1px; /*cellspacing:poor IE support for this*/
border-collapse: separate;
width:100%; /* FF hack poor when scroling subgrid */
}
.celldiv {
float: left;
display: table-cell;
border: 1px dotted #CCCCCC;
overflow: auto;
white-space: normal;
}
.celldivth {
float: left; /*fix for buggy browsers*/
border: 1px solid #CCCCCC;
background-color: #99CCFF;
border-bottom: 1px solid #CBC7B8;
text-align: left;
overflow: auto;
}
.rowdiv {
display: table-row;
background: #F9F9F9 none;
color: #000000;
width: 100%;
overflow:auto;
}
/* End Subgrid */
/* InLine editing */
input.editable[type="text"] {
font-size: x-small;
overflow: hidden;
height : 15px;
}
input.editable[type="checkbox"] {
}
textarea.editable {
overflow: hidden;
}
select.editable {
font-size: x-small;
}
/* End Inline Editing */
/*Modal Window */
.modaltext{
text-align : left;
}
.modalwin{
border:1px solid #555555;
background:#F9F9F9;
text-align:left;
margin: 0 auto;
overflow: auto;
}
.modalhead {
background-image: url(images/grid-blue-hd.gif);
height: 20px;
}
.modalcontent {
overflow: auto;
margin-bottom: 9px;
margin-left: 5px;
}
/* end Modal window*/
/* Search window */
input.search {
margin: 2px;
width: 70px;
font-size: 10px;
color: #15428B;
}
select.search {
margin: 2px;
width: 70px;
font-size: 10px;
color: #15428B;
}
.buttonsearch {
width : 50px;
font-size: 10px;
color: #15428B;
}
/*End search */
/* Form edit */
.FormGrid {
margin: 0px;
}
.EditTable {
width: 100%;
}
.FormData { /* tr */
}
#FormError td {
font-size: 90%;
color: #FF0000;
vertical-align: top;
background-color: #f7f7f7;
}
.CaptionTD{ /* td */
font-weight: normal; text-align: left; vertical-align: top;
padding: 1px;
border-top: 1px solid #D4D0C8;
white-space: nowrap;
color: #000000;
}
.DataTD { /* td */
padding: 1px;
border-top: 1px solid #D4D0C8;
vertical-align: top;
}
.navButton{
border-top: 1px solid #D4D0C8;
border-bottom: 1px solid #D4D0C8;
text-align: center;
}
.navButton input{
width:17px;
}
input.EditButton { /* buttons are at footer tr */
font-size: 10px;
color: #15428B;
}
td.EditButton {
text-align: right;
border-top: 1px solid #D4D0C8;
border-bottom: 1px solid #D4D0C8;
}
.FormElement { /* form element - input -text,textarea,checkbox - select */
}
.FormElement {
font-size: 10px;
}
input[type="text"].FormElement{
color: #15428B;
}
input[type="checkbox"].FormElement{
width: 15px;
color: #15428B;
}
input[type="textarea"].FormElement{
color: #15428B;
}
select.FormElement {
font-size: 10px;
color: #15428B;
}
/* End Eorm edit */
/* Delete Dialog */
.DelButton > input { /* buttons are at footer tr */
font-size: 10px;
color: #15428B;
}
.DelButton {
text-align: right;
}
/* End Delete Dialog */
img.jqResize {
position:absolute;
bottom: 0px;
right: 0px;
cursor :se-resize;
}
.dirty-cell {
background: transparent url(images/dirty.gif) no-repeat 0 0;
}
#DelError td {
font-size: 90%;
color: #FF0000;
vertical-align: top;
background-color: #f7f7f7;
}
/* Tree Grid */
.tree-wrap
{
float: left;
position: relative;
height: 18px;
white-space: nowrap;
overflow: hidden;
}
.tree-minus
{
position: absolute;
height: 18px;
width: 16px;
overflow: hidden;
background: url(images/tree_minus.gif) no-repeat;
}
.tree-plus
{
position: absolute;
height: 18px;
width: 16px;
overflow: hidden;
background: url(images/tree_plus.gif) no-repeat;
}
.tree-leaf
{
position: absolute;
height: 18px;
width: 16px;
overflow: hidden;
background: url(images/tree_leaf.gif) no-repeat;
}
.treeclick
{
cursor: pointer;
}
.edit-cell {
background-color: #E1DCF4 !important;
}
.selected-row, .selected-row TD {
background-color: #3d84cc;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 986 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 923 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

View File

@@ -0,0 +1,457 @@
.GridHeader {
}
.Header {
width: 100%;
}
.Header th {
font-size: 100%; font-weight: bold; text-align: left;
padding: 2px;
background-image: url(images/headerbg.gif); color: #ffffff;
width: 100%;
white-space: nowrap;
}
.HeaderLeft {
background-image: url(images/headerleft.gif);
}
.HeaderRight {
background-image: url(images/headerright.gif);
}
.HeaderButton {
background-image: url(images/headerbg.gif);
}
.HeaderButton img{
width: 21px;
}
.HeaderLeft img{
width: 4px;
}
.HeaderRight img{
width: 9px;
}
.GridHeader table {margin:0;}
.GridHeader td, tr {padding:0;}
/* Grid */
table.scroll {
border-right: 1px solid #FFFFFF;
table-layout: fixed;
margin-bottom:0;
}
table.scroll tbody tr {
background-color: #eceae3;
}
table.scroll tbody tr.alt{
background-color: #e3dfd1;
}
table.scroll tr.over td{
background-color: #D2B48C;
}
table.scroll tr.selected td {
background-color: #c9b9b1;
color: Black;
}
table.scroll tbody tr td {
font-size: 90%;
padding: 2px;
text-align: left;
border-left: 1px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
height : auto;
}
table.scroll thead tr th {
font-size: 90%;
font-weight: normal;
padding: 2px;
border-left: 1px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF;
text-align: left;
overflow: hidden;
white-space: nowrap;
background: url(images/grid-blue-hd.gif) transparent repeat-x;
height : 18px;
}
table.scroll thead tr th div img {
width: 9px;
}
table.scroll th div {
overflow: hidden;
/* white-space: nowrap;*/
word-wrap: break-word;
height : 18px;
}
table.scroll th span {
cursor: e-resize;
/* border-right: 1px solid #D6D2C2; */
width: 5px;
float: right;
position: relative;
display: block;
margin: -1px -1px -1px 0px;
height: 18px;
overflow: hidden;
white-space: nowrap;
}
table.scroll thead {
}
/* End Grid */
/* Pager */
div.scroll {
vertical-align: top;
height: 23px;
text-align: center;
white-space: nowrap;
background-image: url(images/grid-blue-ft.gif);
border-right: 1px solid #FFFFFF;
border-left: 1px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF;
}
div.scroll span {
vertical-align : top;
}
.selbox {
font-size: x-small;
vertical-align : top;
}
input.selbox{
font-size: x-small;
vertical-align : top;
}
.pgbuttons {
margin-top :1px;
}
.nav-table-left {
padding:1px;
float: left;
margin-top:2px;
/* position:absolute;*/
}
.nav-table-right {
padding:1px;
float: right;
margin-top:2px;
}
table.navtable {margin-bottom:0; width: auto;}
table.navtable tbody tr {
background-image: url(images/grid-blue-ft.gif);
}
table.navtable tbody tr td.nav-button {
border: 1px solid #FFFFFF;
white-space: nowrap;
}
table.navtable tbody tr td.nav-hover {
border: 1px solid #c9b9b1;
}
table.tbutton tbody tr td {
border : none;
padding:0px;
}
img.jsHover { /*not used */
border: 1px solid #99CCFF;
}
/* End Pager */
/*multiselect checkbox */
.cbox {
height: 10px;
width: 10px;
/* text-align: center;*/
/*border:1px solid #999;*/
}
/* end multiselect */
/* loading div */
div.loading {
position: absolute;
padding: 3px;
text-align: center;
font-weight: bold;
background: red;
color: white;
display: none;
}
div.loadingui {
display:none;
z-index:6000;
position:absolute;
}
div.loadingui div.msgbox {
position: relative;
z-index:6001;
left: 35%;
top:45%;
background: url(images/loading.gif) no-repeat left;
width: 100px;
border: 2px solid #B2D2FF;
text-align: right;
height: auto;
padding:2px;
margin: 0px;
}
/* end loading div */
/*toolbar */
div.userdata {
margin-top: 0px;
background-color : #e3dfd1;
height : 20px;
overflow: hidden;
}
/* end toolbar */
/*Subgrid text mode*/
.subgrid {
height: 100%;
overflow: auto;
}
.tablediv {
background-color: White;
border-spacing: 1px; /*cellspacing:poor IE support for this*/
border-collapse: separate;
width:100%; /* FF hack poor when scroling subgrid */
}
.celldiv {
float: left;
display: table-cell;
border: 1px dotted #CCCCCC;
overflow: auto;
white-space: normal;
}
.celldivth {
float: left; /*fix for buggy browsers*/
border: 1px solid #CCCCCC;
background-color: #99CCFF;
border-bottom: 1px solid #CBC7B8;
text-align: left;
overflow: auto;
}
.rowdiv {
display: table-row;
background: #F9F9F9 none;
color: #000000;
width: 100%;
overflow:auto;
}
/* End Subgrid */
/* InLine editing */
input.editable[type="text"] {
font-size: x-small;
overflow: hidden;
}
input.editable[type="checkbox"] {
}
textarea.editable {
overflow: hidden;
}
select.editable {
font-size: x-small;
}
/* End Inline Editing */
/*Modal Window */
.modaltext{
text-align : left;
}
.modalwin{
border:1px solid #555555;
background:#F9F9F9;
text-align:left;
margin: 0 auto;
overflow: auto;
}
.modalhead {
background-image: url(images/grid-blue-hd.gif);
height: 20px;
}
.modalcontent {
overflow: auto;
margin-bottom: 9px;
margin-left: 5px;
}
/* end Modal window*/
/* Search window */
input.search {
margin: 2px;
width: 70px;
font-size: 10px;
color: #15428B;
}
select.search {
margin: 2px;
width: 70px;
font-size: 10px;
color: #15428B;
}
.buttonsearch {
width : 50px;
font-size: 10px;
color: #15428B;
}
/*End search */
/* Form edit */
.FormGrid {
margin: 0px;
}
.EditTable {
width: 100%;
}
.FormData { /* tr */
}
#FormError td {
font-size: 90%;
color: #FF0000;
vertical-align: top;
background-color: #f7f7f7;
}
.CaptionTD{ /* td */
font-weight: normal; text-align: left; vertical-align: top;
padding: 1px;
border-top: 1px solid #D4D0C8;
white-space: nowrap;
color: #000000;
}
.DataTD { /* td */
padding: 1px;
border-top: 1px solid #D4D0C8;
vertical-align: top;
}
.navButton{
border-top: 1px solid #D4D0C8;
border-bottom: 1px solid #D4D0C8;
text-align: center;
}
.navButton input{
width:19px;
}
input.EditButton { /* buttons are at footer tr */
font-size: 10px;
color: #15428B;
}
td.EditButton {
text-align: right;
border-top: 1px solid #D4D0C8;
border-bottom: 1px solid #D4D0C8;
}
.FormElement { /* form element - input -text,textarea,checkbox - select */
}
.FormElement {
font-size: 10px;
}
input[type="text"].FormElement{
color: #15428B;
}
input[type="checkbox"].FormElement{
width: 15px;
color: #15428B;
}
input[type="textarea"].FormElement{
color: #15428B;
}
select.FormElement {
font-size: 10px;
color: #15428B;
}
/* End Eorm edit */
/* Delete Dialog */
.DelButton > input { /* buttons are at footer tr */
font-size: 10px;
color: #15428B;
}
.DelButton {
text-align: right;
}
/* End Delete Dialog */
img.jqResize {
position:absolute;
bottom: 0px;
right: 0px;
cursor :se-resize;
}
.dirty-cell {
background: transparent url(images/dirty.gif) no-repeat 0 0;
}
#DelError td {
font-size: 90%;
color: #FF0000;
vertical-align: top;
background-color: #f7f7f7;
}
/* Tree Grid */
.tree-wrap
{
float: left;
position: relative;
height: 18px;
white-space: nowrap;
overflow: hidden;
}
.tree-minus
{
position: absolute;
height: 18px;
width: 16px;
overflow: hidden;
background: url(images/tree_minus.gif) no-repeat;
}
.tree-plus
{
position: absolute;
height: 18px;
width: 16px;
overflow: hidden;
background: url(images/tree_plus.gif) no-repeat;
}
.tree-leaf
{
position: absolute;
height: 18px;
width: 16px;
overflow: hidden;
background: url(images/tree_leaf.gif) no-repeat;
}
.treeclick
{
cursor: pointer;
}
.edit-cell {
background-color: #D2B48C !important;
}
.selected-row, .selected-row TD {
background-color: #c9b9b1;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 832 B

Some files were not shown because too many files have changed in this diff Show More