From ffd1b645802adc4e54b97417c73e7b0ad97b6905 Mon Sep 17 00:00:00 2001 From: abijah Date: Wed, 10 Jun 2009 02:41:23 +0000 Subject: [PATCH] Significant changes to work with the new account/ledger structure. Removed much of the auto-generated model association code. Added helper functions into the models to perform model related work, such as model 'stats' (a bad name for a function to return a summary of pertinent financial information from a given model instance). There is a ton of cleanup to do, but first I want to get it all captured. git-svn-id: file:///svn-source/pmgr/branches/ledger_transactions_20090605/site@81 97e9348a-65ac-dc4b-aefc-98561f571b83 --- app_controller.php | 1 - app_model.php | 33 ++ controllers/accounts_controller.php | 133 +++----- controllers/contacts_controller.php | 89 +----- controllers/customers_controller.php | 125 ++++---- controllers/ledgers_controller.php | 90 ++---- controllers/units_controller.php | 77 +---- models/account.php | 440 +++++++++++++++++++++++++-- models/contact.php | 37 +-- models/contact_address.php | 7 - models/contact_email.php | 7 - models/contact_phone.php | 7 - models/customer.php | 220 +++++++++++--- models/lease.php | 177 +++++++++-- models/lease_type.php | 15 +- models/ledger.php | 205 +++++++++---- models/ledger_entry.php | 94 ++++-- models/map.php | 25 +- models/monetary_source.php | 14 +- models/monetary_type.php | 14 +- models/site.php | 29 +- models/site_area.php | 18 +- models/transaction.php | 22 +- models/unit.php | 60 ++-- models/unit_size.php | 22 +- models/unit_type.php | 14 +- views/accounts/view.ctp | 11 +- views/contacts/view.ctp | 4 +- views/elements/accounts.ctp | 23 +- views/elements/contacts.ctp | 2 +- views/elements/customers.ctp | 38 ++- views/elements/leases.ctp | 82 +++++ views/elements/ledger.ctp | 66 ---- views/elements/ledger_entries.ctp | 69 +++++ views/elements/ledgers.ctp | 36 ++- views/helpers/format.php | 5 +- views/ledgers/view.ctp | 6 +- views/transactions/index.ctp | 10 - views/transactions/view.ctp | 2 +- views/units/view.ctp | 16 +- webroot/css/layout.css | 12 +- 41 files changed, 1441 insertions(+), 916 deletions(-) create mode 100644 views/elements/leases.ctp delete mode 100644 views/elements/ledger.ctp create mode 100644 views/elements/ledger_entries.ctp diff --git a/app_controller.php b/app_controller.php index 19af659..c1e74e5 100644 --- a/app_controller.php +++ b/app_controller.php @@ -41,7 +41,6 @@ class AppController extends Controller { return array( array('name' => 'Common', 'header' => true), array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)), - array('name' => 'Tenants', 'url' => array('controller' => 'contacts', 'action' => 'index')), array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')), array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')), array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index')), diff --git a/app_model.php b/app_model.php index 0f1bb9c..97f8611 100644 --- a/app_model.php +++ b/app_model.php @@ -78,6 +78,39 @@ class AppModel extends Model { } //end getEnumValues + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: statMerge + * - Merges summary data from $b into $a + */ + + function statsMerge (&$a, $b) { + if (!isset($b)) + return; + + if (!isset($a)) { + $a = $b; + } + elseif (!is_array($a) && !is_array($b)) { + $a += $b; + } + elseif (is_array($a) && is_array($b)) { + foreach (array_intersect_key($a, $b) AS $k => $v) + { + if (preg_match("/^sp\./", $k)) + $a[$k] .= '; ' . $b[$k]; + else + $this->statsMerge($a[$k], $b[$k]); + } + $a = array_merge($a, array_diff_key($b, $a)); + } + else { + die ("Can't yet merge array and non-array stats"); + } + } + // Overriding pagination, since the stupid count mechanism blows. // This is also a crappy solution, especially if the query returns // a really large number of rows. However, trying to untagle this diff --git a/controllers/accounts_controller.php b/controllers/accounts_controller.php index 1bb9c21..c1080ad 100644 --- a/controllers/accounts_controller.php +++ b/controllers/accounts_controller.php @@ -9,12 +9,13 @@ class AccountsController extends AppController { (// Models 'LedgerEntry' => array('fields' => - array('SUM(IF(LedgerEntry.debit_ledger_id = CurrentLedger.id, LedgerEntry.amount, 0)) AS debits', - 'SUM(IF(LedgerEntry.credit_ledger_id = CurrentLedger.id, LedgerEntry.amount, 0)) AS credits', + array('SUM(IF(LedgerEntry.debit_ledger_id = CurrentLedger.id, LedgerEntry.amount, NULL)) AS debits', + 'SUM(IF(LedgerEntry.credit_ledger_id = CurrentLedger.id, LedgerEntry.amount, NULL)) AS credits', "SUM(IF(Account.type IN ('ASSET', 'EXPENSE'), IF(LedgerEntry.debit_ledger_id = CurrentLedger.id, 1, -1), IF(LedgerEntry.credit_ledger_id = CurrentLedger.id, 1, -1) - )* LedgerEntry.amount) AS balance", + ) * IF(LedgerEntry.amount, LedgerEntry.amount, 0) + ) AS balance", 'COUNT(LedgerEntry.id) AS entries'), 'conditions' => array('OR' => @@ -166,99 +167,51 @@ class AccountsController extends AppController { $this->redirect(array('action'=>'index')); } -/* $this->Account->bindModel(array('hasMany' => array */ -/* ('LedgerEntry' => array */ -/* ('className' => 'LedgerEntry', */ -/* 'foreignKey' => false, */ -/* 'finderQuery' => 'SELECT `LedgerEntry`.* */ -/* FROM pmgr_entries AS `LedgerEntry` */ -/* LEFT JOIN pmgr_transactions AS `Transaction` */ -/* ON `Transaction`.id = `LedgerEntry`.transaction_id */ -/* WHERE LedgerEntry.debit_ledger_id = ({$__cakeID__$}) */ -/* OR LedgerEntry.credit_ledger_id = ({$__cakeID__$}) */ -/* ORDER BY Transaction.stamp', */ -/* )))); */ + // Get details about the account and its ledgers (no ledger entries yet) + $this->Account->Behaviors->attach('Containable'); + $account = $this->Account->find + ('first', + array('contain' => + array(// Models + 'CurrentLedger' => + array('fields' => array('id', 'sequence')), -/* $this->Account->Behaviors->attach('Containable'); */ -/* $this->Account->Contain(array('LedgerEntry' => array */ -/* ( */ -/* // Models */ -/* 'Transaction' => array */ -/* ( */ -/* // Models */ -/* 'Customer', */ -/* )), */ - -/* )); */ -/* } */ -/* $account = $this->Account->read(null, $id); */ + 'Ledger' => + array('order' => array('Ledger.open_stamp' => 'DESC')), + ), + 'conditions' => array(array('Account.id' => $id)), + ) + ); + $this->Account->Behaviors->detach('Containable'); + // Simply debug stuff... testing. + $cond = null; + //$cond = array('Transaction.stamp >' => '2009-05-16'); - $this->Account->recursive = -1; - $account = $this->Account->read(null, $id); + // Get all ledger entries of the CURRENT ledger + //$crap = $this->Account->findSecurityDeposits($id); + //$crap = $this->Account->findAccountRelatedEntries($id, 8); + //pr(array('crap', $crap)); +/* $this->autoRender = false; */ +/* return; */ - $account['Ledger'] = $this->Account->find - ('all', array - ('link' => array - (// Models - 'Ledger' => array - (// Models - 'LedgerEntry' => - array('fields' => - array('SUM(IF(LedgerEntry.debit_ledger_id = Ledger.id, LedgerEntry.amount, 0)) AS debits', - 'SUM(IF(LedgerEntry.credit_ledger_id = Ledger.id, LedgerEntry.amount, 0)) AS credits', - "SUM(IF(Account.type IN ('ASSET', 'EXPENSE'), - IF(LedgerEntry.debit_ledger_id = Ledger.id, 1, -1), - IF(LedgerEntry.credit_ledger_id = Ledger.id, 1, -1) - ) * LedgerEntry.amount) AS balance", - 'COUNT(LedgerEntry.id) AS entries'), - 'conditions' => - array('OR' => - array('LedgerEntry.debit_ledger_id = Ledger.id', - 'LedgerEntry.credit_ledger_id = Ledger.id'), - ), - ), - ), - ), - 'fields' => array(), - 'conditions' => array('Account.id' => $id), - 'order' => 'Ledger.name', - 'group' => 'Ledger.id', - 'limit' => 4, - )); + // Get all ledger entries of the CURRENT ledger + $account['CurrentLedger']['LedgerEntry'] + = $this->Account->findCurrentLedgerEntries($id, $cond); + //pr(array('Account summary', $account)); - - $account['CurrentLedger'] = array_shift($this->Account->Ledger->find - ('first', array - ('link' => array - (// Models - 'Account' => array('fields' => array()), - 'LedgerEntry' => - array('fields' => - array("SUM(IF(LedgerEntry.debit_ledger_id = Ledger.id, LedgerEntry.amount, 0)) AS debits", - "SUM(IF(LedgerEntry.credit_ledger_id = Ledger.id, LedgerEntry.amount, 0)) AS credits", - "SUM(IF(Account.type IN ('ASSET', 'EXPENSE'), - IF(LedgerEntry.debit_ledger_id = Ledger.id, 1, -1), - IF(LedgerEntry.credit_ledger_id = Ledger.id, 1, -1) - ) * LedgerEntry.amount) AS balance", - 'COUNT(LedgerEntry.id) AS entries'), - 'conditions' => - array('OR' => - array("LedgerEntry.debit_ledger_id = Ledger.id", - "LedgerEntry.credit_ledger_id = Ledger.id"), - ), - ), - ), - 'fields' => array(), - 'conditions' => array(array('Ledger.account_id' => $id), - 'NOT' => array('Ledger.closed')), - //'order' => 'Ledger.name', - 'group' => 'Ledger.id', - //'limit' => 4, - ))); - //pr($account); + // Summarize each ledger + foreach($account['Ledger'] AS &$ledger) + $ledger = array_merge($ledger, + $this->Account->Ledger->stats($ledger['id'])); - $balance = $account['CurrentLedger']['balance']; + // Obtain the overall account balance + $account['Account'] = + array_merge($account['Account'], + array('stats' => $this->Account->stats($id))); + $balance = $account['Account']['stats']['Ledger']['balance']; + + // Prepare to render $title = 'Account: ' . $account['Account']['name']; $this->set(compact('account', 'title', 'balance')); } diff --git a/controllers/contacts_controller.php b/controllers/contacts_controller.php index 34f1f19..097b927 100644 --- a/controllers/contacts_controller.php +++ b/controllers/contacts_controller.php @@ -29,94 +29,11 @@ class ContactsController extends AppController { ************************************************************************** ************************************************************************** * action: index - * - Lists all current tenants + * - Lists all contacts */ function index() { - $this->current(); - } - - - /************************************************************************** - ************************************************************************** - ************************************************************************** - * action: past - * - Lists all tenants, past and present - */ - - function tenants() { - $this->paginate = array_merge - ($this->paginate, - array('link' => - array(// Models - 'Lease' => - array('fields' => array(), - 'type' => 'INNER', - ), - ), - 'conditions' => array('ContactsLease.type !=' => 'ALTERNATE') - )); - - $title = 'All Tenants'; - $this->set('title', $title); $this->set('heading', $title); - $this->set('contacts', $this->paginate()); - $this->render('index'); - } - - - /************************************************************************** - ************************************************************************** - ************************************************************************** - * action: current - * - Lists all current tenants - */ - - function current() { - $this->paginate = array_merge - ($this->paginate, - array('link' => - array(// Models - 'Lease' => - array('fields' => array(), - 'type' => 'INNER', - ), - ), - 'conditions' => array('ContactsLease.type !=' => 'ALTERNATE', - 'Lease.close_date IS NULL') - )); - - $title = 'Current Tenants'; - $this->set('title', $title); $this->set('heading', $title); - $this->set('contacts', $this->paginate()); - $this->render('index'); - } - - - /************************************************************************** - ************************************************************************** - ************************************************************************** - * action: past - * - Lists all past tenants - */ - - function past() { - $this->paginate = array_merge - ($this->paginate, - array('link' => - array(// Models - 'Lease' => - array('fields' => array(), - 'type' => 'INNER', - ), - ), - 'conditions' => array('ContactsLease.type !=' => 'ALTERNATE', - 'Lease.close_date IS NOT NULL') - )); - - $title = 'Past Tenants'; - $this->set('title', $title); $this->set('heading', $title); - $this->set('contacts', $this->paginate()); - $this->render('index'); + $this->all(); } @@ -124,7 +41,7 @@ class ContactsController extends AppController { ************************************************************************** ************************************************************************** * action: all - * - Lists all contacts, including non-tenants + * - Lists all contacts */ function all() { diff --git a/controllers/customers_controller.php b/controllers/customers_controller.php index c6db067..b4a47d1 100644 --- a/controllers/customers_controller.php +++ b/controllers/customers_controller.php @@ -2,15 +2,15 @@ class CustomersController extends AppController { var $paginate = array('limit' => 100, - 'group' => 'Customer.id', - 'order' => array('Customer.name' => 'ASC')); + 'group' => 'Customer.id', + 'order' => array('Customer.name' => 'ASC')); var $sidemenu_links = array(array('name' => 'Tenants', 'header' => true), - array('name' => 'Current', 'url' => array('controller' => 'customers', 'action' => 'current')), - array('name' => 'Past', 'url' => array('controller' => 'customers', 'action' => 'past')), - array('name' => 'All', 'url' => array('controller' => 'customers', 'action' => 'all')), - ); + array('name' => 'Current', 'url' => array('controller' => 'customers', 'action' => 'current')), + array('name' => 'Past', 'url' => array('controller' => 'customers', 'action' => 'past')), + array('name' => 'All', 'url' => array('controller' => 'customers', 'action' => 'all')), + ); /************************************************************************** ************************************************************************** @@ -46,14 +46,14 @@ class CustomersController extends AppController { $this->paginate = array_merge ($this->paginate, array('link' => - array(// Models - 'Lease' => - array('fields' => array(), - 'type' => 'INNER', - ), - ), - 'conditions' => array('Lease.close_date IS NULL') - )); + array(// Models + 'Lease' => + array('fields' => array(), + 'type' => 'INNER', + ), + ), + 'conditions' => array('Lease.close_date IS NULL') + )); $title = 'Current Tenants'; $this->set('title', $title); $this->set('heading', $title); @@ -73,14 +73,14 @@ class CustomersController extends AppController { $this->paginate = array_merge ($this->paginate, array('link' => - array(// Models - 'Lease' => - array('fields' => array(), - 'type' => 'INNER', - ), - ), - 'conditions' => array('Lease.close_date IS NOT NULL') - )); + array(// Models + 'Lease' => + array('fields' => array(), + 'type' => 'INNER', + ), + ), + 'conditions' => array('Lease.close_date IS NOT NULL') + )); $title = 'Past Tenants'; $this->set('title', $title); $this->set('heading', $title); @@ -120,58 +120,61 @@ class CustomersController extends AppController { $this->Customer->Behaviors->attach('Containable'); $this->Customer->contain (array(// Models - 'Contact' => - array(// Models - 'ContactPhone', - 'ContactEmail', - 'ContactAddress', - ), - 'Transaction' => - array('order' => array('stamp'), - // Models - 'Entry' => - array(// Models - 'DebitAccount', - 'CreditAccount'), - ), - 'Lease' => - array('order' => 'movein_date', - 'conditions' => array('Lease.lease_date IS NOT NULL'), - // Models + 'Contact' => + array(// Models + 'ContactPhone', + 'ContactEmail', + 'ContactAddress', + ), + 'Account', + 'Lease' => + array(//'order' => 'movein_date', + //'conditions' => array('Lease.lease_date IS NOT NULL'), + // Models + //'Account', 'Unit' => - array('order' => array('sort_order'), - 'fields' => array('id', 'name'), - ), - ), - ) + array('order' => array('sort_order'), + 'fields' => array('id', 'name'), + ), + ), + ) ); $customer = $this->Customer->read(null, $id); + $this->Customer->Behaviors->detach('Containable'); + + foreach ($customer['Lease'] AS &$lease) { + $stats = $this->Customer->Lease->stats($lease['id']); + //pr($stats); + $lease['balance'] = $stats['Account']['Ledger']['balance']; + } + //pr($customer); - $outstanding_deposit = 0; - $outstanding_balance = 0; - foreach($customer['Transaction'] AS $transaction) { - foreach($transaction['Entry'] AS $entry) { - if ($entry['DebitAccount']['name'] === 'A/R') - $outstanding_balance += $entry['amount']; - if ($entry['CreditAccount']['name'] === 'A/R') - $outstanding_balance -= $entry['amount']; + $stats = $this->Customer->stats($id); + $deposits = $this->Customer->findSecurityDeposits($id); - if ($entry['DebitAccount']['name'] === 'Security Deposit') - $outstanding_deposit -= $entry['amount']; - if ($entry['CreditAccount']['name'] === 'Security Deposit') - $outstanding_deposit += $entry['amount']; - } - } + $outstanding_balance = $stats['balance']; + $outstanding_deposit = $deposits['summary']['balance']; + +/* pr(array('Customer Stats', $stats)); */ +/* pr(array('Security Deposits', $deposits)); */ $this->sidemenu_links[] = array('name' => 'Operations', 'header' => true); $this->sidemenu_links[] = array('name' => 'Move-Out', 'url' => array('controller' => 'units', 'action' => 'move-out')); + + $customer['Account'] = array_merge($customer['Account'], $stats['Account']['Ledger']); + //pr($stats); + //unset($stats['Lease'], $stats['Account']); +/* $customer['Account']['debits'] = 10; */ +/* $customer['Account']['credits'] = 20; */ +/* $customer['Account']['balance'] = 55; */ + $title = $customer['Customer']['name']; $this->set(compact('customer', 'title', - 'outstanding_balance', - 'outstanding_deposit')); + 'outstanding_balance', + 'outstanding_deposit')); } } diff --git a/controllers/ledgers_controller.php b/controllers/ledgers_controller.php index e54063c..644f2b4 100644 --- a/controllers/ledgers_controller.php +++ b/controllers/ledgers_controller.php @@ -25,8 +25,6 @@ class LedgersController extends AppController { 'group' => 'Ledger.id', 'order' => array('Ledger.name' => 'ASC')); - var $uses = array('Ledger', 'LedgerEntry'); - var $sidemenu_links = array(array('name' => 'Ledgers', 'header' => true), array('name' => 'Current', 'url' => array('controller' => 'ledgers', 'action' => 'current')), @@ -115,73 +113,37 @@ class LedgersController extends AppController { $this->redirect(array('action'=>'index')); } -/* $this->Ledger->bindModel(array('hasMany' => array */ -/* ('LedgerEntry' => array */ -/* ('className' => 'LedgerEntry', */ -/* 'foreignKey' => false, */ -/* 'finderQuery' => 'SELECT `LedgerEntry`.* */ -/* FROM pmgr_entries AS `LedgerEntry` */ -/* LEFT JOIN pmgr_transactions AS `Transaction` */ -/* ON `Transaction`.id = `LedgerEntry`.transaction_id */ -/* WHERE LedgerEntry.debit_ledger_id = ({$__cakeID__$}) */ -/* OR LedgerEntry.credit_ledger_id = ({$__cakeID__$}) */ -/* ORDER BY Transaction.stamp', */ -/* )))); */ - -/* $this->Ledger->Behaviors->attach('Containable'); */ -/* $this->Ledger->Contain(array('LedgerEntry' => array */ -/* ( */ -/* // Models */ -/* 'Transaction' => array */ -/* ( */ -/* // Models */ -/* 'Customer', */ -/* )), */ - -/* )); */ -/* } */ -/* $ledger = $this->Ledger->read(null, $id); */ - + // Get details about the ledger itself (no entries yet) $this->Ledger->Behaviors->attach('Containable'); - $this->Ledger->Contain(array('Account')); - $ledger = $this->Ledger->read(null, $id); - //pr($ledger); + $ledger = $this->Ledger->find + ('first', + array('contain' => + array(// Models + 'Account', + ), + 'conditions' => array(array('Ledger.id' => $id)), + ) + ); + $this->Ledger->Behaviors->detach('Containable'); - if (in_array($ledger['Account']['type'], array('ASSET', 'EXPENSE'))) - $ledger_type = 'debit'; - else - $ledger_type = 'credit'; + // Get all ledger entries of this ledger + $ledger['LedgerEntry'] = $this->Ledger->findLedgerEntries + ($id, $ledger['Account']['type']); - $ledger['LedgerEntry'] = $this->LedgerEntry->find - ('all', - array('link' => array - (// Models - 'Transaction' => - array(// Models - 'Customer', - )), - 'fields' => - array('id', 'name', 'comment', - "IF(LedgerEntry.debit_ledger_id = $id, LedgerEntry.amount, NULL) AS debit", - "IF(LedgerEntry.credit_ledger_id = $id, LedgerEntry.amount, NULL) AS credit", - "(IF(LedgerEntry.{$ledger_type}_ledger_id = $id, 1, -1) * LedgerEntry.amount) AS balance"), - 'conditions' => array('OR' => - array("LedgerEntry.debit_ledger_id = $id", - "LedgerEntry.credit_ledger_id = $id")), - 'order' => array('Transaction.stamp'), - //'limit' => 15, - //'limit' => 2, - )); - //pr($ledger); +/* $ledger['LedgerEntry'] = $this->Ledger->LedgerEntry->findInLedgerContext */ +/* ($id, +/* $ledger['LedgerEntry'] = $this->Ledger->findLedgerEntries */ +/* ($id); */ + //($id, $ledger['Account']['type']); - $balance = 0; - foreach($ledger['LedgerEntry'] AS &$entry) { - if (isset($entry[0])) - $entry = array_merge($entry[0], array_diff_key($entry, array(0))); - - $balance += $entry['balance']; - } + // Summarize the entries, and obtain the ledger balance + $ledger['Ledger'] = + array_merge($ledger['Ledger'], + array('stats' => $this->Ledger->stats($id))); + $balance = $ledger['Ledger']['stats']['balance']; + + // OK, set our view variables and render! $title = 'Ledger: ' . $ledger['Ledger']['name']; $this->set(compact('ledger', 'title', 'balance')); } diff --git a/controllers/units_controller.php b/controllers/units_controller.php index abe18cf..805a3aa 100644 --- a/controllers/units_controller.php +++ b/controllers/units_controller.php @@ -156,74 +156,27 @@ class UnitsController extends AppController { $this->Unit->contain (array(// Models 'UnitSize', - //'CurrentLease' => - 'Lease' => - array(//'order' => 'movein_date', - //'conditions' => array('Lease.lease_date IS NOT NULL', - //), - // Models - //'Contact' => array('alias' => 'PrimaryContact'), - // 'PrimaryContact', - 'Customer' => array('fields' => array('id', 'name'), - // Models - 'Transaction' => - array('order' => array('stamp'), - // Models - 'LedgerEntry' => array('DebitLedger' => array('Account'), - 'CreditLedger' => array('Account'), - ), - ), - ), -/* array(//'order' => array('sort_order'), */ -/* 'fields' => array('id', 'display_name'), */ -/* ), */ - ) + 'Lease' => array('Customer'), + 'CurrentLease' => array('Customer') ) ); + $unit = $this->Unit->read(null, $id); + $this->Unit->Behaviors->detach('Containable'); - //$unit = $this->Unit->read(null, $id); - //pr($unit); + pr($unit); - $this->Unit->Lease->Customer->Transaction->LedgerEntry->Behaviors->attach('Containable'); - $entries = $this->Unit->Lease->Customer->Transaction->LedgerEntry->find - ('all', - array - ( - 'contain' => - array('Transaction' => - array('Customer' => - array('Lease' => - array('Unit' => - array('conditions' => array('Unit.id' => $id)), - ), - ), - ), - ), - //'conditions' => 'xyz', - 'limit' => 2, - )); - pr($entries); - $this->autoRender = false; - - - $outstanding_deposit = 0; - $outstanding_balance = 0; - foreach($unit['Lease'] AS $lease) { - foreach($lease['Customer']['Transaction'] AS $transaction) { - foreach($transaction['LedgerEntry'] AS $entry) { - if ($entry['DebitLedger']['Account']['name'] === 'A/R') - $outstanding_balance += $entry['amount']; - if ($entry['CreditLedger']['Account']['name'] === 'A/R') - $outstanding_balance -= $entry['amount']; - - if ($entry['DebitLedger']['Account']['name'] === 'Security Deposit') - $outstanding_deposit -= $entry['amount']; - if ($entry['CreditLedger']['Account']['name'] === 'Security Deposit') - $outstanding_deposit += $entry['amount']; - } - } + foreach ($unit['Lease'] AS &$lease) { + $stats = $this->Unit->Lease->stats($lease['id']); + $lease['balance'] = $stats['Account']['Ledger']['balance']; } + $stats = $this->Unit->stats($id); + $deposits = $this->Unit->Lease->findSecurityDeposits($unit['CurrentLease']['id']); + + //pr($stats); + $outstanding_balance = $stats['CurrentLease']['Account']['Ledger']['balance']; + $outstanding_deposit = $deposits['summary']['balance']; + $this->sidemenu_links[] = array('name' => 'Operations', 'header' => true); $this->sidemenu_links[] = diff --git a/models/account.php b/models/account.php index 0079017..1487c3e 100644 --- a/models/account.php +++ b/models/account.php @@ -11,34 +11,428 @@ class Account extends AppModel { var $hasOne = array( 'CurrentLedger' => array( 'className' => 'Ledger', - 'foreignKey' => 'account_id', - 'dependent' => false, - 'conditions' => array(array('CurrentLedger.closed' => 0)), - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' + //'foreignKey' => 'account_id', + 'conditions' => array('NOT' => array('CurrentLedger.closed')) ), ); var $hasMany = array( - 'Ledger' => array( - 'className' => 'Ledger', - 'foreignKey' => 'account_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ), + 'Ledger', ); + var $cache; +/* var $instantiated; */ + + +/* /\************************************************************************** */ +/* ************************************************************************** */ +/* ************************************************************************** */ +/* * function: constructor */ +/* *\/ */ +/* function __constructor($id = null) { */ +/* parent::__contstructor(); */ +/* $this->id = $id; */ +/* $this->instantiated = true; */ +/* } */ + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: securityDepositAccountID + * - Returns the ID of the Security Deposit Account + */ + function securityDepositAccountID() { + $account = $this->find('first', array + ('recursive' => -1, + 'conditions' => array(array('name' => 'Security Deposit')), + )); + return $account['Account']['id']; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function:rentAccountID + * - Returns the ID of the Rent Account + */ + function rentAccountID() { + $account = $this->find('first', array + ('recursive' => -1, + 'conditions' => array(array('name' => 'Rent')), + )); + return $account['Account']['id']; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: type + * - Returns the type of this array of ledger ids from the given account + */ + function type($id) { + if (isset($this->cache[$id]['type'])) { +/* pr(array('function' => 'Account::type', */ +/* 'args' => compact('id'), */ +/* 'cache_hit' => true, */ +/* 'return' => $this->cache[$id]['type'])); */ + return $this->cache[$id]['type']; + } + + $account = $this->find('first', array + ('recursive' => -1, + 'fields' => array('type'), + 'conditions' => array(array('Account.id' => $id)), + )); + + $this->cache[$id]['type'] = $account['Account']['type']; +/* pr(array('function' => 'Account::type', */ +/* 'args' => compact('id'), */ +/* 'return' => $this->cache[$id]['type'])); */ + + return $this->cache[$id]['type']; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: ledgers + * - Returns an array of ledger ids from the given account + */ + function ledgers($id, $all = false) { + $cachekey = $all ? 'all' : 'current'; + if (isset($this->cache[$id]['ledgers'][$cachekey])) { +/* pr(array('function' => 'Account::ledgers', */ +/* 'args' => compact('id', 'all'), */ +/* 'cache_hit' => true, */ +/* 'return' => $this->cache[$id]['ledgers'][$cachekey])); */ + return $this->cache[$id]['ledgers'][$cachekey]; + } + + if ($all) { + $contain = array('Ledger' => array('fields' => array('Ledger.id'))); + } else { + $contain = array('CurrentLedger' => array('fields' => array('CurrentLedger.id'))); + } + + $this->Behaviors->attach('Containable'); + $account = $this->find('first', array + ('contain' => $contain, + 'fields' => array(), + 'conditions' => array(array('Account.id' => $id)), + )); + $this->Behaviors->detach('Containable'); + + if ($all) { + $ledger_ids = array(); + foreach ($account['Ledger'] AS $ledger) + array_push($ledger_ids, $ledger['id']); + } + else { + $ledger_ids = array($account['CurrentLedger']['id']); + } + + $this->cache[$id]['ledgers'][$cachekey] = $ledger_ids; + +/* pr(array('function' => 'Account::ledgers', */ +/* 'args' => compact('id', 'all'), */ +/* 'return' => $this->cache[$id]['ledgers'][$cachekey])); */ + + return $this->cache[$id]['ledgers'][$cachekey]; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findLedgerEntries + * - Returns an array of ledger entries that belong to the given + * account, either just from the current ledger, or from all ledgers. + */ + function findLedgerEntries($id, $all = false, $cond = null, $link = null) { +/* pr(array('function' => 'Account::findLedgerEntries', */ +/* 'args' => compact('id', 'all', 'cond', 'link'), */ +/* )); */ + + $entries = array(); + foreach ($this->ledgers($id, $all) AS $ledger_id) { + $ledger_entries = $this->Ledger->findLedgerEntries($ledger_id, $this->type($id), $cond, $link); + $entries = array_merge($entries, $ledger_entries); + //$entries = array_merge($entries, array_diff_key($ledger_entries, array('summary'=>1))); + //$this->statsMerge($entries['summary'], $ledger_entries['summary']); + } + +/* pr(array('function' => 'Account::findLedgerEntries', */ +/* 'args' => compact('id', 'all', 'cond', 'link'), */ +/* 'return' => compact('entries'), */ +/* )); */ + + $stats = $this->stats($id, $all, $cond); + return array('Entries' => $entries, 'summary' => $stats['Ledger']); + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findLedgerEntriesRelatedToAccount + * - Returns an array of ledger entries that belong to the given + * account, and are related to a specific account, either just from + * the current ledger, or from all ledgers. + */ + function findLedgerEntriesRelatedToAccount($id, $rel_ids, $all = false, $cond = null, $link = null) { +/* pr(array('function' => 'Account::findLedgerEntriesRelatedToAccount', */ +/* 'args' => compact('id', 'rel_ids', 'all', 'cond', 'link'), */ +/* )); */ + if (!isset($cond)) + $cond = array(); + + if (!is_array($rel_ids)) + $rel_ids = array($rel_ids); + + $ledger_ids = array(); + foreach ($rel_ids AS $rel_id) + $ledger_ids = array_merge($ledger_ids, $this->ledgers($rel_id)); + + array_push($cond, $this->Ledger->LedgerEntry->conditionEntryAsCreditOrDebit($ledger_ids)); + $entries = $this->findLedgerEntries($id, $all, $cond, $link); + +/* pr(array('function' => 'Account::findLedgerEntriesRelatedToAccount', */ +/* 'args' => compact('id', 'relid', 'all', 'cond', 'link'), */ +/* 'vars' => compact('ledger_ids'), */ +/* 'return' => compact('entries'), */ +/* )); */ + return $entries; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findCurrentLedgerEntries + * - Returns an array of ledger entries that belong to the current + * ledger of the given account. There is extra work done... see the + * LedgerEntry model. + */ + function findCurrentLedgerEntries($id, $cond = null, $link = null) { + $this->Behaviors->attach('Containable'); + $account = $this->find('first', array + ('contain' => array('CurrentLedger'), + 'fields' => array('Account.type', 'CurrentLedger.id'), + 'conditions' => array(array('Account.id' => $id)), + )); + $this->Behaviors->detach('Containable'); + + $ledger_id = $account['CurrentLedger']['id']; + $account_type = $account['Account']['type']; + + return $this->Ledger->findLedgerEntries($ledger_id, $account_type, $cond, $link); + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findLedgerRelatedEntries + * - Returns an array of ledger entries from this account that are + * related to one of the given ledgers. + */ + function findLedgerRelatedEntries($id, $ledgers, $link = null) { + pr(array_merge(array('function' => 'Account::findLedgerRelatedEntries', + 'checkpoint' => 'begin'), + compact('id', 'ledgers', 'link'))); + $this->Behaviors->attach('Containable'); + $account = $this->find('first', array + ('contain' => array + ('Ledger' => array('fields' => array('Ledger.id')), + ), + 'fields' => array('Account.type'), + 'conditions' => array(array('Account.id' => $id)), + )); + $this->Behaviors->detach('Containable'); + + $cond = array('OR' => + array(array('debit_ledger_id' => $ledgers), + array('credit_ledger_id' => $ledgers))); + + pr(array_merge(array('function' => 'Account::findLedgerRelatedEntries', + 'checkpoint' => 'get-account-ledgers'), + compact('account', 'cond'))); + + $entries = array(); + foreach($account['Ledger'] AS $ledger) { + //pr(array('find', $ledger, $account, $cond, $link)); + $entries = array_merge + ($entries, + $this->Ledger->findLedgerEntries($ledger['id'], + $account['Account']['type'], + $cond, $link)); + } + + foreach($entries AS $entry) + $this->statsMerge($entries['summary'], $entry[0]); + + //$entries['summary'] + + pr(array_merge(array('function' => 'Account::findLedgerRelatedEntries', + 'checkpoint' => 'return'), + compact('entries'))); + return $entries; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findAccountRelatedEntries + * - Returns an array of ledger entries from this account that are + * related to the given account. + */ + function findAccountRelatedEntries($id, $relid, $link = null) { + pr(array_merge(array('function' => 'Account::findAccountRelatedEntries', + 'checkpoint' => 'begin'), + compact('id', 'relid', 'link'))); + $this->Behaviors->attach('Containable'); + $related = $this->find('first', array + ('contain' => array + ('Ledger' => array('fields' => array('Ledger.id')), + ), + 'fields' => array(), + 'conditions' => array(array('Account.id' => $relid)), + )); + $this->Behaviors->detach('Containable'); + + $ledger_ids = array(); + foreach ($related['Ledger'] AS $ledger) + array_push($ledger_ids, $ledger['id']); + + pr(array_merge(array('function' => 'Account::findAccountRelatedEntries', + 'checkpoint' => 'get-related'), + compact('related', 'ledger_ids'))); + + $entries = $this->findLedgerRelatedEntries($id, $ledger_ids, $link); + pr(array_merge(array('function' => 'Account::findAccountRelatedEntries', + 'checkpoint' => 'return'), + compact('entries'))); + return $entries; + //return $this->findLedgerRelatedEntries($id, $ledger_ids, $link); + } + + +/* /\************************************************************************** */ +/* ************************************************************************** */ +/* ************************************************************************** */ +/* * function: findSecurityDeposits */ +/* * - Returns an array of security deposit entries */ +/* *\/ */ +/* function findSecurityDeposits($id, $link = null) { */ +/* pr(array_merge(array('function' => 'Account::findSecurityDeposits', */ +/* 'checkpoint' => 'begin'), */ +/* compact('id', 'link'))); */ +/* $sd_account = $this->find('first', array */ +/* ('recursive' => -1, */ +/* 'conditions' => array(array('name' => 'Security Deposit')), */ +/* )); */ +/* pr(array_merge(array('function' => 'Account::findSecurityDeposits', */ +/* 'checkpoint' => 'get-security-deposit-account'), */ +/* compact('sd_account'))); */ + +/* $deposits = $this->findAccountRelatedEntries($id, $sd_account['Account']['id'], $link); */ +/* pr(array_merge(array('function' => 'Account::findSecurityDeposits', */ +/* 'checkpoint' => 'return'), */ +/* compact('deposits'))); */ +/* return $deposits; */ +/* //return $this->findAccountRelatedEntries($id, $sd_account['Account']['id'], $link); */ +/* } */ + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findSecurityDeposits + * - Returns an array of security deposit entries + */ + function zzfindSecurityDeposits($id, $cond = array(), $link = null) { + $this->Behaviors->attach('Containable'); + $account = $this->find('first', array + ('contain' => array + ('Ledger' => array('fields' => array('Ledger.id')), + ), + 'fields' => array('Account.type'), + 'conditions' => array(array('Account.id' => $id)), + )); + + $sd_account = $this->find('first', array + ('contain' => array + ('Ledger' => array('fields' => array('Ledger.id')), + ), + 'conditions' => array(array('name' => 'Security Deposit')), + )); + $this->Behaviors->detach('Containable'); + + pr(array('sd_account', $sd_account)); + $sd_ledger_ids = array(); + foreach ($sd_account['Ledger'] AS $ledger) + array_push($sd_ledger_ids, $ledger['id']); + + pr(array('sd_ledger_ids', $sd_ledger_ids)); + array_push($cond, + array('OR' => + array(array('debit_ledger_id' => $sd_ledger_ids), + array('credit_ledger_id' => $sd_ledger_ids)))); + + $sd_entries = array(); + foreach($account['Ledger'] AS $ledger) { + pr(array('find', $ledger, $account, $cond, $link)); + $add = $this->Ledger->findLedgerEntries($ledger['id'], + $account['Account']['type'], + $cond, $link); + $sd_entries = array_merge($sd_entries, $add); + } + + pr(array('sd_entries', $sd_entries)); + + //return $this->Ledger->findLedgerEntries($ledger_id, $account_type, $cond, $link); + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: stats + * - Returns summary data from the requested account. + */ + + function stats($id = null, $all = false, $cond = null) { + if (!$id) + return null; + + // All old, closed ledgers MUST balance to 0. + // However, the user may want the ENTIRE running totals. + $this->Behaviors->attach('Containable'); + $account = $this->find('first', + array('contain' => + ($all + ? array('Ledger' => array('fields' => array('id'))) + : array('CurrentLedger' => array('fields' => array('id'))) + ), + 'conditions' => array(array('Account.id' => $id)))); + $this->Behaviors->detach('Containable'); + + if ($all) + $ledgers = $account['Ledger']; + else + $ledgers = array($account['CurrentLedger']); + + foreach ($ledgers AS $ledger) { + $this->statsMerge($stats['Ledger'], $this->Ledger->stats($ledger['id'], $cond)); + } + + return $stats; + } + } ?> \ No newline at end of file diff --git a/models/contact.php b/models/contact.php index 04052c2..d4e18d5 100644 --- a/models/contact.php +++ b/models/contact.php @@ -10,21 +10,7 @@ class Contact extends AppModel { ); var $hasAndBelongsToMany = array( - 'Customer' => array( - 'className' => 'Customer', - 'joinTable' => 'contacts_customers', - 'foreignKey' => 'contact_id', - 'associationForeignKey' => 'customer_id', - 'unique' => true, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' - ), + 'Customer', 'ContactAddress' => array( 'className' => 'ContactAddress', 'joinTable' => 'contacts_methods', @@ -32,13 +18,6 @@ class Contact extends AppModel { 'associationForeignKey' => 'method_id', 'unique' => true, 'conditions' => "method = 'POST'", - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' ), 'ContactPhone' => array( 'className' => 'ContactPhone', @@ -47,13 +26,6 @@ class Contact extends AppModel { 'associationForeignKey' => 'method_id', 'unique' => true, 'conditions' => "method = 'PHONE'", - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' ), 'ContactEmail' => array( 'className' => 'ContactEmail', @@ -62,13 +34,6 @@ class Contact extends AppModel { 'associationForeignKey' => 'method_id', 'unique' => true, 'conditions' => "method = 'EMAIL'", - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' ), ); diff --git a/models/contact_address.php b/models/contact_address.php index 5503268..d064016 100644 --- a/models/contact_address.php +++ b/models/contact_address.php @@ -15,13 +15,6 @@ class ContactAddress extends AppModel { 'associationForeignKey' => 'contact_id', 'unique' => true, 'conditions' => "method = 'POST'", - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' ) ); } diff --git a/models/contact_email.php b/models/contact_email.php index 474e2b2..f2bbf75 100644 --- a/models/contact_email.php +++ b/models/contact_email.php @@ -15,13 +15,6 @@ class ContactEmail extends AppModel { 'associationForeignKey' => 'contact_id', 'unique' => true, 'conditions' => "method = 'EMAIL'", - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' ) ); diff --git a/models/contact_phone.php b/models/contact_phone.php index 8569c89..f53b61d 100644 --- a/models/contact_phone.php +++ b/models/contact_phone.php @@ -17,13 +17,6 @@ class ContactPhone extends AppModel { 'associationForeignKey' => 'contact_id', 'unique' => true, 'conditions' => "method = 'PHONE'", - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' ) ); diff --git a/models/customer.php b/models/customer.php index 652cef3..80c6cb6 100644 --- a/models/customer.php +++ b/models/customer.php @@ -7,52 +7,194 @@ class Customer extends AppModel { 'name' => array('notempty'), ); + var $belongsTo = array( + 'Account', + ); + var $hasMany = array( - 'Lease' => array( + 'CurrentLease' => array( 'className' => 'Lease', - 'foreignKey' => 'customer_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' + 'conditions' => 'CurrentLease.close_date IS NULL', ), - 'Transaction' => array( - 'className' => 'Transaction', - 'foreignKey' => 'customer_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'Lease', + 'Transaction', ); var $hasAndBelongsToMany = array( - 'Contact' => array( - 'className' => 'Contact', - 'joinTable' => 'contacts_customers', - 'foreignKey' => 'customer_id', - 'associationForeignKey' => 'contact_id', - 'unique' => true, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' - ), + 'Contact', ); + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findAccountEntries + * - Returns an array of ledger entries that belong to the current + * ledger of the account for the given customer. There is extra work + * done... see the LedgerEntry model. + */ +/* function findAccountEntries($id, $date = null, $link = null) { */ +/* $result = $this->find('first', array */ +/* ('recursive' => -1, */ +/* 'fields' => array('account_id'), */ +/* 'conditions' => array(array('id' => $id)), */ +/* )); */ + +/* return $this->Account->findCurrentLedgerEntries($result['account_id'], */ +/* $date, $link); */ +/* } */ + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findSecurityDeposits + * - Returns an array of security deposit entries + */ + function zfindSecurityDeposits($id, $link = null) { + pr(array('function' => 'Customer::findSecurityDeposits', + 'args' => compact('id', 'link'), + )); + + $this->Behaviors->attach('Containable'); + $customer = $this->find('first', + array('contain' => + array('Lease' => array + ('fields' => array('Lease.account_id')), + ), + 'fields' => array('Customer.account_id'), + 'conditions' => array(array('Customer.id' => $id)))); + $this->Behaviors->detach('Containable'); + + $account_ids = array($customer['Customer']['account_id']); + foreach ($customer['Lease'] AS $lease) + array_push($account_ids, $lease['account_id']); + + $acct = new Account(); + $entries = $acct->findLedgerEntriesRelatedToAccount + ($acct->securityDepositAccountID(), + $account_ids, + //$acct->rentAccountID(), + //6, + //array_merge(array(1), $account_ids), + true, null, $link); + + // OK, we cheated by finding the entries of the security deposit account, + // and not by finding the security deposit entries of the customer + // account(s). Therefore, we have to invert the credit/debit business. + $entries['summary']['debits'] = $entries['summary']['credit']; + $entries['summary']['credits'] = $entries['summary']['debit']; + unset($entries['summary']['credit']); + unset($entries['summary']['debit']); + + pr(array('function' => 'Customer::findSecurityDeposits', + 'args' => compact('id', 'link'), + 'vars' => compact('customer', 'account_ids'), + 'return' => compact('entries'), + )); + return $entries; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findSecurityDeposits + * - Returns an array of security deposit entries + */ + function findSecurityDeposits($id, $link = null) { +/* pr(array_merge(array('function' => 'Customer::findSecurityDeposits', */ +/* 'checkpoint' => 'begin'), */ +/* compact('id', 'link'))); */ + + $this->Behaviors->attach('Containable'); + $customer = $this->find('first', + array('contain' => + array('Lease' => array('fields' => array('id'))), + 'fields' => array('account_id'), + 'conditions' => array(array('Customer.id' => $id)))); + $this->Behaviors->detach('Containable'); + + $entries = $this->Account->findLedgerEntriesRelatedToAccount + ($customer['Customer']['account_id'], + $this->Account->securityDepositAccountID(), + true, null, $link); + + foreach ($customer['Lease'] AS $lease) { + $ledger_entries = $this->Lease->findSecurityDeposits($lease['id'], $link); + //$this->statsMerge($ledger_entries['summary'], $entries['summary']); + //unset($entries['summary']); + $this->statsMerge($entries['summary'], $ledger_entries['summary']); + $entries['Entries'] = array_merge($entries['Entries'], $ledger_entries['Entries']); + } + +/* pr(array('function' => 'Customer::findSecurityDeposits', */ +/* 'args' => compact('id', 'link'), */ +/* 'vars' => compact('customer'), */ +/* 'return' => compact('entries'))); */ + + return $entries; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: stats + * - Returns summary data from the requested customer. + */ + + function stats($id = null) { + if (!$id) + return null; + + $this->Behaviors->attach('Containable'); + $customer = $this->find('first', + array('contain' => + array('Account' => array('fields' => array('Account.id')), + 'Lease' => array('fields' => array('Lease.id')) + ), +/* array('Account' => array */ +/* ('fields' => array('id'), */ +/* /\* 'CurrentLedger' => array *\/ */ +/* /\* ('fields => *\/ */ +/* /\* 'Lease' => array('fields' => array('id') *\/ */ +/* ), */ +/* ), */ + 'conditions' => array(array('Customer.id' => $id)))); + $this->Behaviors->detach('Containable'); + + $stats['Account'] = $this->Account->stats($customer['Account']['id']); + foreach ($customer['Lease'] AS $lease) { + $this->statsMerge($stats['Lease'], $this->Lease->stats($lease['id'])); + } + +/* foreach($lease['Customer']['Transaction'] AS $transaction) { */ +/* foreach($transaction['LedgerEntry'] AS $entry) { */ +/* if ($entry['DebitLedger']['Account']['name'] === 'A/R') */ +/* $outstanding_balance += $entry['amount']; */ +/* if ($entry['CreditLedger']['Account']['name'] === 'A/R') */ +/* $outstanding_balance -= $entry['amount']; */ + +/* if ($entry['DebitLedger']['Account']['name'] === 'Security Deposit') */ +/* $outstanding_deposit -= $entry['amount']; */ +/* if ($entry['CreditLedger']['Account']['name'] === 'Security Deposit') */ +/* $outstanding_deposit += $entry['amount']; */ +/* } */ +/* } */ +/* } */ +/* if ($entry['DebitLedger']['Account']['name'] === 'Security Deposit') */ +/* $outstanding_deposit -= $entry['amount']; */ +/* if ($entry['CreditLedger']['Account']['name'] === 'Security Deposit') */ +/* $outstanding_deposit += $entry['amount']; */ + + // Merge the stats from both the customer specific account, as + // well as the lease. This will provide current customer standing. + $this->statsMerge($stats, $stats['Account']['Ledger']); + $this->statsMerge($stats, $stats['Lease']['Account']['Ledger']); + + return $stats; + } + } ?> \ No newline at end of file diff --git a/models/lease.php b/models/lease.php index fd349fe..6ce5cc8 100644 --- a/models/lease.php +++ b/models/lease.php @@ -23,36 +23,155 @@ class Lease extends AppModel { ); var $belongsTo = array( - 'LeaseType' => array( - 'className' => 'LeaseType', - 'foreignKey' => 'lease_type_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), - 'Unit' => array( - 'className' => 'Unit', - 'foreignKey' => 'unit_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), - 'LateSchedule' => array( - 'className' => 'LateSchedule', - 'foreignKey' => 'late_schedule_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), - 'Customer' => array( - 'className' => 'Customer', - 'foreignKey' => 'customer_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), + 'LeaseType', + 'Unit', + 'Account', + 'Customer', + 'LateSchedule', ); + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findAccountEntries + * - Returns an array of ledger entries from the account of the given + * lease. + */ + function findAccountEntries($id, $all = false, $cond = null, $link = null) { +/* pr(array('function' => 'Lease::findAccountEntries', */ +/* 'args' => compact('id', 'all', 'cond', 'link'), */ +/* )); */ + + $lease = $this->find('first', array + ('recursive' => -1, + 'fields' => array('account_id'), + 'conditions' => array(array('id' => $id)), + )); + + $entries = $this->Account->findLedgerEntries($lease['Lease']['account_id'], + $all, $cond, $link); +/* pr(array('function' => 'Lease::findAccountEntries', */ +/* 'args' => compact('id', 'all', 'cond', 'link'), */ +/* 'vars' => compact('lease'), */ +/* 'return' => compact('entries'), */ +/* )); */ + return $entries; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findSecurityDeposits + * - Returns an array of security deposit entries + */ + function findSecurityDeposits($id, $link = null) { +/* pr(array('function' => 'Lease::findSecurityDeposits', */ +/* 'args' => compact('id', 'link'), */ +/* )); */ + + $lease = $this->find('first', array + ('recursive' => -1, + 'fields' => array('account_id'), + 'conditions' => array(array('id' => $id)), + )); + +/* $sd_account_id = $this->Account->securityDepositAccountID(); */ +/* $sd_ledger_ids = $this->Account->ledgers($sd_account_id); */ +/* $cond = conditionEntryAsCreditOrDebit($sd_ledger_ids); */ + + $entries = $this->Account->findLedgerEntriesRelatedToAccount + ($lease['Lease']['account_id'], + $this->Account->securityDepositAccountID(), + true, null, $link); + +/* pr(array('function' => 'Lease::findSecurityDeposits', */ +/* 'args' => compact('id', 'link'), */ +/* 'vars' => compact('lease'), */ +/* 'return' => compact('entries'), */ +/* )); */ + return $entries; + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findSecurityDeposits + * - Returns an array of security deposit entries + */ + function findAccountDeposits($id, $link = null) { + pr(array_merge(array('function' => 'Lease::findSecurityDeposits', + 'checkpoint' => 'begin'), + compact('id', 'link'))); + $lease = $this->find('first', array + ('recursive' => -1, + 'fields' => array('account_id'), + 'conditions' => array(array('id' => $id)), + )); + pr(array_merge(array('function' => 'Lease::findSecurityDeposits', + 'checkpoint' => 'get-lease'), + compact('lease'))); + + $deposits = $this->Account->findSecurityDeposits($lease['Lease']['account_id'], $link); + pr(array_merge(array('function' => 'Lease::findSecurityDeposits', + 'checkpoint' => 'return'), + compact('deposits'))); + return $deposits; + //return $this->Account->findSecurityDeposits($lease['Lease']['account_id'], $link); + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findSecurityDeposits + * - Returns an array of security deposit entries + */ + function qqfindSecurityDeposits($id, $link = null) { + pr(array_merge(array('function' => 'Lease::findSecurityDeposits', + 'checkpoint' => 'begin'), + compact('id', 'link'))); + $lease = $this->find('first', array + ('recursive' => -1, + 'fields' => array('account_id'), + 'conditions' => array(array('id' => $id)), + )); + pr(array_merge(array('function' => 'Lease::findSecurityDeposits', + 'checkpoint' => 'get-lease'), + compact('lease'))); + + return $this->Account->findAccountRelatedEntries($id, $relaccount, $link); + $deposits = $this->Account->findSecurityDeposits($lease['Lease']['account_id'], $link); + pr(array_merge(array('function' => 'Lease::findSecurityDeposits', + 'checkpoint' => 'return'), + compact('deposits'))); + return $deposits; + //return $this->Account->findSecurityDeposits($lease['Lease']['account_id'], $link); + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: stats + * - Returns summary data from the requested lease. + */ + + function stats($id = null) { + if (!$id) + return null; + + // Find the associated account. + $lease = $this->find('first', + array('recursive' => -1, + 'conditions' => array(array('Lease.id' => $id)))); + + // Pull the stats from the account. + $stats['Account'] = $this->Account->stats($lease['Lease']['account_id']); + return $stats; + } + } ?> \ No newline at end of file diff --git a/models/lease_type.php b/models/lease_type.php index f4a5208..e606b80 100644 --- a/models/lease_type.php +++ b/models/lease_type.php @@ -7,21 +7,8 @@ class LeaseType extends AppModel { 'name' => array('notempty') ); - //The Associations below have been created with all possible keys, those that are not needed can be removed var $hasMany = array( - 'Lease' => array( - 'className' => 'Lease', - 'foreignKey' => 'lease_type_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'Lease', ); } diff --git a/models/ledger.php b/models/ledger.php index 6808a1f..02c509b 100644 --- a/models/ledger.php +++ b/models/ledger.php @@ -1,65 +1,156 @@ array('numeric'), - 'name' => array('notempty'), - ); + var $name = 'Ledger'; + var $validate = array( + 'id' => array('numeric'), + 'name' => array('notempty'), + ); - var $belongsTo = array( - 'Account' => array( - 'className' => 'Account', - 'foreignKey' => 'account_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), - ); + var $belongsTo = array( + 'Account', + ); - var $hasMany = array( -/* 'LedgerEntry' => array( */ -/* 'className' => 'LedgerEntry', */ -/* 'foreignKey' => false, */ -/* 'dependent' => false, */ -/* 'conditions' => '', */ -/* 'fields' => '', */ -/* 'order' => '', */ -/* 'limit' => '', */ -/* 'offset' => '', */ -/* 'exclusive' => '', */ -/* 'finderQuery' => 'SELECT `Entry`.* FROM pmgr_entries AS `Entry` */ -/* WHERE Entry.debit_ledger_id = ({$__cakeID__$}) */ -/* OR Entry.credit_ledger_id = ({$__cakeID__$})', */ -/* 'counterQuery' => '' */ -/* ), */ - 'DebitLedgerEntry' => array( - 'className' => 'LedgerEntry', - 'foreignKey' => 'debit_ledger_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ), - 'CreditLedgerEntry' => array( - 'className' => 'LedgerEntry', - 'foreignKey' => 'credit_ledger_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ), - ); + var $hasMany = array( + 'LedgerEntry' => array( + 'className' => 'LedgerEntry', + 'foreignKey' => false, + // conditions will be used when JOINing tables + // (such as find with LinkableBehavior) + 'conditions' => array('OR' => + array('LedgerEntry.debit_ledger_id = Ledger.id', + 'LedgerEntry.credit_ledger_id = Ledger.id')), + // finderQuery will be used when tables are put + // together across several querys, not with JOIN. + // (such as find with ContainableBehavior) + 'finderQuery' => 'SELECT `LedgerEntry`.* + FROM pmgr_ledger_entries AS `LedgerEntry` + WHERE LedgerEntry.debit_ledger_id = ({$__cakeID__$}) + OR LedgerEntry.credit_ledger_id = ({$__cakeID__$})', + 'counterQuery' => '' + ), + 'DebitLedgerEntry' => array( + 'className' => 'LedgerEntry', + 'foreignKey' => 'debit_ledger_id', + 'dependent' => false, + ), + 'CreditLedgerEntry' => array( + 'className' => 'LedgerEntry', + 'foreignKey' => 'credit_ledger_id', + 'dependent' => false, + ), + ); + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findLedgerEntries + * - Returns an array of ledger entries that belong to a given + * ledger. There is extra work done... see the LedgerEntry model. + */ + function findLedgerEntries($id, $account_type = null, $cond = null, $link = null) { +/* pr(array('function' => 'Ledger::findLedgerEntries', */ +/* 'args' => compact('id', 'account_type', 'cond', 'link'), */ +/* )); */ + + if (!isset($account_type)) { + $this->Behaviors->attach('Containable'); + $ledger = $this->find('first', array + ('contain' => array + ('Account' => array + ('fields' => array('type'), + ), + ), + 'fields' => array(), + 'conditions' => array(array('Ledger.id' => $id)), + )); + $this->Behaviors->detach('Containable'); + $account_type = $ledger['Account']['type']; + } + + // If the requested entries are limited by date, we must calculate + // a balance forward, or the resulting balance will be thrown off. + + // REVISIT : This obviously is more general than date. + // As such, it will not work (or, only work if the + // condition only manages to exclude the first parts + // of the ledger, nothing in the middle or at the + // end. For now, I'll just create an 'other' entry, + // not necessarily a balance forward. + + $bf = array(); + if (0 && isset($cond)) { + //$date = ''; + $stats = $this->stats($id, array('NOT' => array($cond))); + $bf = array(array(array('debit' => $stats['debits'], + 'credit' => $stats['credits'], + 'balance' => $stats['balance']), + + 'LedgerEntry' => array('id' => null, + //'comment' => "Balance Forward from $date"), + 'comment' => "-- SUMMARY OF EXCLUDED ENTRIES --"), + + 'Transaction' => array('id' => null, + //'stamp' => $date, + 'stamp' => null, + 'comment' => null), + )); + } + + $entries = $this->LedgerEntry->findInLedgerContext($id, $account_type, $cond, $link); +/* pr(array('function' => 'Ledger::findLedgerEntries', */ +/* 'args' => compact('id', 'account_type', 'cond', 'link'), */ +/* 'vars' => compact('ledger'), */ +/* 'return' => compact('entries'), */ +/* )); */ + return $entries; + + // Return entries from the ledger, along with our balance forward. +/* return array_merge($bf, */ +/* $this->LedgerEntry->findInLedgerContext($id, $account_type, $cond, $link)); */ + } + + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: stats + * - Returns summary data from the requested ledger. + */ + function stats($id, $cond = null) { + + $stats = $this->find + ('first', array + ('link' => + array(// Models + 'Account' => array('fields' => array()), + //'LedgerEntry' => array('fields' => array()), + 'LedgerEntry' => + array('fields' => array(), + 'Transaction' => array('fields' => array('stamp')), + ), + ), + 'fields' => + array("SUM(IF(LedgerEntry.debit_ledger_id = Ledger.id, + LedgerEntry.amount, NULL)) AS debits", + "SUM(IF(LedgerEntry.credit_ledger_id = Ledger.id, + LedgerEntry.amount, NULL)) AS credits", + "SUM(IF(Account.type IN ('ASSET', 'EXPENSE'), + IF(LedgerEntry.debit_ledger_id = Ledger.id, 1, -1), + IF(LedgerEntry.credit_ledger_id = Ledger.id, 1, -1) + ) * IF(LedgerEntry.amount, LedgerEntry.amount, 0) + ) AS balance", + "COUNT(LedgerEntry.id) AS entries"), + 'conditions' => array(isset($cond) ? $cond : array(), + array('Ledger.id' => $id)), + 'group' => 'Ledger.id', + )); + + // The fields are all tucked into the [0] index, + // and the rest of the array is useless (empty). + return $stats[0]; + } } ?> \ No newline at end of file diff --git a/models/ledger_entry.php b/models/ledger_entry.php index 4d84e6c..254e411 100644 --- a/models/ledger_entry.php +++ b/models/ledger_entry.php @@ -9,35 +9,89 @@ class LedgerEntry extends AppModel { ); var $belongsTo = array( - 'MonetarySource' => array( - 'className' => 'MonetarySource', - 'foreignKey' => 'monetary_source_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), - 'Transaction' => array( - 'className' => 'Transaction', - 'foreignKey' => 'transaction_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), + 'MonetarySource', + 'Transaction', + 'DebitLedger' => array( 'className' => 'Ledger', 'foreignKey' => 'debit_ledger_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' ), 'CreditLedger' => array( 'className' => 'Ledger', 'foreignKey' => 'credit_ledger_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' ), ); + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: + * - + */ + function conditionEntryAsCreditOrDebit($ledger_ids) { + return array('OR' => + array(array('debit_ledger_id' => $ledger_ids), + array('credit_ledger_id' => $ledger_ids))); + } + + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: findInLedgerContext + * - Returns an array of ledger entries that belong to a given ledger. + * There is extra logic to also figure out whether the ledger_entry + * amount is either a credit, or a debit, depending on how it was + * written into the ledger, as well as whether the amount increases or + * decreases the balance depending on the particular account type of + * the ledger. + */ + function findInLedgerContext($ledger_id, $account_type, $cond = null, $link = null) { + if (!isset($link)) + $link = array('Transaction'); + + if (in_array($account_type, array('ASSET', 'EXPENSE'))) + $ledger_type = 'debit'; + else + $ledger_type = 'credit'; + + $entries = $this->find + ('all', + array('link' => $link, + + 'fields' => + array('id', 'name', 'comment', + "IF(LedgerEntry.debit_ledger_id = $ledger_id," . + " LedgerEntry.amount, NULL) AS debit", + "IF(LedgerEntry.credit_ledger_id = $ledger_id," . + " LedgerEntry.amount, NULL) AS credit", + "(IF(LedgerEntry.{$ledger_type}_ledger_id = $ledger_id, 1, -1)" . + " * LedgerEntry.amount) AS balance"), + + 'conditions' => + array(isset($cond) ? $cond : array(), + 'OR' => + array(array('LedgerEntry.debit_ledger_id' => $ledger_id), + array('LedgerEntry.credit_ledger_id' => $ledger_id))), + + 'order' => + array('Transaction.stamp'), + )); + +/* $entries['summary'] = array('balance' => null, 'debit' => null, 'credit' => null); */ +/* foreach($entries AS $entry) */ +/* $this->statsMerge($entries['summary'], $entry[0]); */ + +/* //if (isset($entries['summary']['debit']) || isset($entries['summary']['credit'])) { */ +/* $entries['summary']['debits'] = $entries['summary']['debit']; */ +/* $entries['summary']['credits'] = $entries['summary']['credit']; */ +/* unset($entries['summary']['debit']); */ +/* unset($entries['summary']['credit']); */ +/* //} */ + + + return $entries; + } } + ?> \ No newline at end of file diff --git a/models/map.php b/models/map.php index c9c2c2e..2e14359 100644 --- a/models/map.php +++ b/models/map.php @@ -11,33 +11,12 @@ class Map extends AppModel { 'depth' => array('numeric') ); - //The Associations below have been created with all possible keys, those that are not needed can be removed var $belongsTo = array( - 'SiteArea' => array( - 'className' => 'SiteArea', - 'foreignKey' => 'site_area_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ) + 'SiteArea', ); var $hasAndBelongsToMany = array( - 'Unit' => array( - 'className' => 'Unit', - 'joinTable' => 'maps_units', - 'foreignKey' => 'map_id', - 'associationForeignKey' => 'unit_id', - 'unique' => true, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'finderQuery' => '', - 'deleteQuery' => '', - 'insertQuery' => '' - ) + 'Unit', ); } diff --git a/models/monetary_source.php b/models/monetary_source.php index a2d5bcc..df530bf 100644 --- a/models/monetary_source.php +++ b/models/monetary_source.php @@ -9,19 +9,7 @@ class MonetarySource extends AppModel { ); var $belongsTo = array( - 'MonetaryType' => array( - 'className' => 'MonetaryType', - 'foreignKey' => 'monetary_type_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'MonetaryType', ); } diff --git a/models/monetary_type.php b/models/monetary_type.php index d79d4fc..22241a4 100644 --- a/models/monetary_type.php +++ b/models/monetary_type.php @@ -9,19 +9,7 @@ class MonetaryType extends AppModel { ); var $hasMany = array( - 'MonetarySource' => array( - 'className' => 'MonetarySource', - 'foreignKey' => 'monetary_type_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'MonetarySource', ); } diff --git a/models/site.php b/models/site.php index d2882df..4825faa 100644 --- a/models/site.php +++ b/models/site.php @@ -7,34 +7,9 @@ class Site extends AppModel { 'name' => array('notempty') ); - //The Associations below have been created with all possible keys, those that are not needed can be removed var $hasMany = array( - 'SiteArea' => array( - 'className' => 'SiteArea', - 'foreignKey' => 'site_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ), - 'SiteOption' => array( - 'className' => 'SiteOption', - 'foreignKey' => 'site_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'SiteArea', + 'SiteOption', ); } diff --git a/models/site_area.php b/models/site_area.php index 1aec59f..2303946 100644 --- a/models/site_area.php +++ b/models/site_area.php @@ -8,26 +8,12 @@ class SiteArea extends AppModel { 'name' => array('notempty') ); - //The Associations below have been created with all possible keys, those that are not needed can be removed var $belongsTo = array( - 'Site' => array( - 'className' => 'Site', - 'foreignKey' => 'site_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ) + 'Site', ); var $hasOne = array( - 'Map' => array( - 'className' => 'Map', - 'foreignKey' => 'site_area_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '' - ) + 'Map', ); } diff --git a/models/transaction.php b/models/transaction.php index d52f06e..08ddf6d 100644 --- a/models/transaction.php +++ b/models/transaction.php @@ -8,29 +8,11 @@ class Transaction extends AppModel { ); var $belongsTo = array( - 'Customer' => array( - 'className' => 'Customer', - 'foreignKey' => 'customer_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), + 'Customer', ); var $hasMany = array( - 'LedgerEntry' => array( - 'className' => 'LedgerEntry', - 'foreignKey' => 'transaction_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'LedgerEntry', ); } diff --git a/models/unit.php b/models/unit.php index d03ddaa..17d9197 100644 --- a/models/unit.php +++ b/models/unit.php @@ -13,27 +13,15 @@ class Unit extends AppModel { ); var $belongsTo = array( - 'UnitSize' => array( - 'className' => 'UnitSize', - 'foreignKey' => 'unit_size_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ), + 'UnitSize', + ); + + var $hasOne = array( 'CurrentLease' => array( 'className' => 'Lease', - 'foreignKey' => 'current_lease_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' + //'foreignKey' => 'unit_id', + 'conditions' => 'CurrentLease.close_date IS NULL', ), -/* 'Map' => array( */ -/* 'className' => 'MapsUnit', */ -/* 'foreignKey' => 'unit_id', */ -/* 'conditions' => '', */ -/* 'fields' => '', */ -/* 'order' => '' */ -/* ) */ ); var $hasMany = array( @@ -41,14 +29,6 @@ class Unit extends AppModel { 'className' => 'Lease', 'foreignKey' => 'unit_id', 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' ) ); @@ -83,4 +63,32 @@ class Unit extends AppModel { return ('Unit.status <= ' . $this->statusValue('UNAVAILABLE')); } + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: stats + * - Returns summary data from the requested customer. + */ + + function stats($id = null) { + if (!$id) + return null; + + $this->Behaviors->attach('Containable'); + $unit = $this->find('first', + array('contain' => array + ('Lease' => array('fields' => array('Lease.id')), + 'CurrentLease' => array('fields' => array('CurrentLease.id'))), + 'conditions' => array(array('Unit.id' => $id)))); + $this->Behaviors->detach('Containable'); + + $stats['CurrentLease'] = $this->Lease->stats($unit['CurrentLease']['id']); + + foreach ($unit['Lease'] AS $lease) { + $this->statsMerge($stats['Lease'], $this->Lease->stats($lease['id'])); + } + + return $stats; + } + } diff --git a/models/unit_size.php b/models/unit_size.php index 29d1a2f..ca06b60 100644 --- a/models/unit_size.php +++ b/models/unit_size.php @@ -14,29 +14,11 @@ class UnitSize extends AppModel { ); var $belongsTo = array( - 'UnitType' => array( - 'className' => 'UnitType', - 'foreignKey' => 'unit_type_id', - 'conditions' => '', - 'fields' => '', - 'order' => '' - ) + 'UnitType', ); var $hasMany = array( - 'Unit' => array( - 'className' => 'Unit', - 'foreignKey' => 'unit_size_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'Unit', ); } diff --git a/models/unit_type.php b/models/unit_type.php index 8488ca0..d2bd90d 100644 --- a/models/unit_type.php +++ b/models/unit_type.php @@ -9,19 +9,7 @@ class UnitType extends AppModel { ); var $hasMany = array( - 'UnitSize' => array( - 'className' => 'UnitSize', - 'foreignKey' => 'unit_type_id', - 'dependent' => false, - 'conditions' => '', - 'fields' => '', - 'order' => '', - 'limit' => '', - 'offset' => '', - 'exclusive' => '', - 'finderQuery' => '', - 'counterQuery' => '' - ) + 'UnitSize', ); } diff --git a/views/accounts/view.ctp b/views/accounts/view.ctp index 2a56256..d25c71d 100644 --- a/views/accounts/view.ctp +++ b/views/accounts/view.ctp @@ -51,13 +51,22 @@ echo $this->element('table', /********************************************************************** - * Ledger + * Ledgers */ echo $this->element('ledgers', array('caption' => $account['Account']['name'] . " Ledgers", 'ledgers' => $account['Ledger'])); + +/********************************************************************** + * Current Ledger + */ + +echo $this->element('ledger_entries', + array('caption' => "Current Ledger: (#{$account['CurrentLedger']['sequence']})", + 'ledger_entries' => $account['CurrentLedger']['LedgerEntry'])); + /* End "detail supporting" DIV */ ?> diff --git a/views/contacts/view.ctp b/views/contacts/view.ctp index ceb91c9..b63f769 100644 --- a/views/contacts/view.ctp +++ b/views/contacts/view.ctp @@ -12,7 +12,9 @@ * Contact Detail Main Section */ -$rows = array(array('Name', $contact['Contact']['display_name']), +$rows = array(array('First Name', $contact['Contact']['first_name']), + array('Middle Name', $contact['Contact']['middle_name']), + array('Last Name', $contact['Contact']['last_name']), array('Company', $contact['Contact']['company_name']), array('SSN', $contact['Contact']['id_federal']), array('ID', ($contact['Contact']['id_local'] diff --git a/views/elements/accounts.ctp b/views/elements/accounts.ctp index 1d312f0..d7db42a 100644 --- a/views/elements/accounts.ctp +++ b/views/elements/accounts.ctp @@ -31,17 +31,16 @@ if (isset($paginator)) { $rows = array(); foreach ($accounts as $account) { - $extra = null; - if (isset($account[0])) { - $extra = $account[0]; - unset($account[0]); - } + //pr($account); + if (isset($account[0])) + $stats = $account[0]; + else + $stats = $account; + + // Move our pointer to the meat if (isset($account['Account'])) $account = $account['Account']; - if (isset($extra)) - $account = array_merge($account, $extra); - $rows[] = array($html->link($account['name'], array('controller' => 'accounts', 'action' => 'view', @@ -49,10 +48,10 @@ foreach ($accounts as $account) { $account['type'], $account['external_name'], $account['external_account'], - $account['entries'], - FormatHelper::currency($account['debits']), - FormatHelper::currency($account['credits']), - FormatHelper::currency($account['balance']), + $stats['entries'], + FormatHelper::currency($stats['debits']), + FormatHelper::currency($stats['credits']), + FormatHelper::currency($stats['balance']), $account['comment'], ); } diff --git a/views/elements/contacts.ctp b/views/elements/contacts.ctp index cdb4c5f..9df365a 100644 --- a/views/elements/contacts.ctp +++ b/views/elements/contacts.ctp @@ -51,7 +51,7 @@ foreach ($contacts as $contact) { $contact['company_name']), (isset($contact['ContactsCustomer']) ? array($contact['ContactsCustomer']['type'], - $contact['ContactsCustomer']['active'], + $contact['ContactsCustomer']['active'] ? 'Yes' : 'No', $contact['ContactsCustomer']['comment']) : array($contact['comment']))); } diff --git a/views/elements/customers.ctp b/views/elements/customers.ctp index 471e203..74d0fbb 100644 --- a/views/elements/customers.ctp +++ b/views/elements/customers.ctp @@ -5,11 +5,12 @@ if (isset($heading)) elseif (!isset($caption)) echo '

'.__('Customers',true).'

'; -$headers = array('ID', 'Name', 'Comment'); +$headers = array_merge(array('Name'), + isset($customers[0]['ContactsCustomer']) + ? array('Relationship') + : array(), + array('Comment')); $column_class = array(); -foreach (array_intersect($headers, array('ID')) AS $k => $v) { - $column_class[$k] = 'id'; -} foreach (array_intersect($headers, array('Comment')) AS $k => $v) { $column_class[$k] = 'comment'; } @@ -18,25 +19,30 @@ if (isset($paginator)) { echo $paginator->counter(array( 'format' => __('Page %page% of %pages%, showing %current% records (%start% - %end%) of %count% total', true))); - $headers = array($paginator->sort('id'), - $paginator->sort('name'), - $paginator->sort('comment')); + $headers = array_merge(array($paginator->sort('name')), + isset($customers[0]['ContactsCustomer']) + ? array($paginator->sort('Relationship', 'type')) + : array(), + array($paginator->sort('comment'))); } $rows = array(); foreach ($customers as $customer) { + $contacts_customer = null; + if (isset($customer['ContactsCustomer'])) + $contacts_customer = $customer['ContactsCustomer']; + if (isset($customer['Customer'])) $customer = $customer['Customer']; - $rows[] = array($html->link($customer['id'], - array('controller' => 'customers', - 'action' => 'view', - $customer['id'])), - $html->link($customer['name'], - array('controller' => 'customers', - 'action' => 'view', - $customer['id'])), - $customer['comment']); + $rows[] = array_merge(array($html->link($customer['name'], + array('controller' => 'customers', + 'action' => 'view', + $customer['id']))), + isset($contacts_customer) + ? array($contacts_customer['type']) + : array(), + array($customer['comment'])); } echo $this->element('table', diff --git a/views/elements/leases.ctp b/views/elements/leases.ctp new file mode 100644 index 0000000..bb4e56a --- /dev/null +++ b/views/elements/leases.ctp @@ -0,0 +1,82 @@ +'.__('Leases',true).''; + +$headers = array_merge(array('Lease'), + isset($leases[0]['Unit']) + ? array('Unit') + : array('Customer'), + array('Signed', 'Move-In', 'Move-Out', 'Balance', 'Comment')); +$column_class = array(); +foreach (array_intersect($headers, array('Lease', 'Unit')) AS $k => $v) { + $column_class[$k] = 'id'; +} +foreach (array_intersect($headers, array('Balance')) AS $k => $v) { + $column_class[$k] = 'currency'; +} + +if (isset($paginator)) { + echo $paginator->counter(array('format' => __('Page %page% of %pages%, showing %current% records (%start% - %end%) of %count% total', true))); + + $headers = array_merge(array($paginator->sort('Lease')), + isset($leases[0]['Unit']) + ? $paginator->sort('Unit', 'Unit.id') + : $paginator->sort('Customer.id'), + array($paginator->sort('Signed', 'lease_date'), + $paginator->sort('Move-In', 'movein_date'), + $paginator->sort('Move-Out', 'moveout_date'), + $paginator->sort('balance'), + $paginator->sort('comment'))); +} + +$rows = array(); +foreach($leases AS $lease) { + $unit = $customer = null; + + if (isset($lease['Unit'])) + $unit = $lease['Unit']; + else + $customer = $lease['Customer']; + + if (isset($lease['Lease'])) + $lease = $lease['Lease']; + + $rows[] = array_merge(array($html->link('#'.$lease['number'], + array('controller' => 'leases', + 'action' => 'view', + $lease['id']))), + isset($unit) + ? array($html->link($unit['name'], + array('controller' => 'units', + 'action' => 'view', + $unit['id']))) + : array($html->link($customer['name'], + array('controller' => 'customers', + 'action' => 'view', + $customer['id']))), + array(FormatHelper::date($lease['lease_date']), + FormatHelper::date($lease['movein_date']), + FormatHelper::date($lease['moveout_date']), + FormatHelper::currency($lease['balance']), + $lease['comment'])); +} + +echo $this->element('table', + array('class' => 'item lease list', + 'caption' => isset($caption) ? $caption : null, + 'headers' => $headers, + 'rows' => $rows, + 'column_class' => $column_class)); + +if (isset($paginator)) { + echo('
' . "\n"); + echo $paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled')); + echo(' | '); + echo $paginator->numbers(); + echo(' | '); + echo $paginator->next(__('next', true).' >>', array(), null, array('class'=>'disabled')); + echo('
' . "\n"); +} diff --git a/views/elements/ledger.ctp b/views/elements/ledger.ctp deleted file mode 100644 index 4128277..0000000 --- a/views/elements/ledger.ctp +++ /dev/null @@ -1,66 +0,0 @@ -'.__('Ledger',true).''; - -$headers = array('Transaction', 'Entry', 'Date', 'Customer', 'Comment', 'Debit', 'Credit', 'Total'); -$column_class = array(); -foreach (array_intersect($headers, array('Transaction', 'Entry')) AS $k => $v) { - $column_class[$k] = array($column_class[$k], 'id'); -} -foreach (array_intersect($headers, array('Debit', 'Credit', 'Total')) AS $k => $v) { - $column_class[$k] = array($column_class[$k], 'currency'); -} -foreach (array_intersect($headers, array('Comment')) AS $k => $v) { - $column_class[$k] = 'slack'; -} - - -$rows = array(); -$running_total = 0; -foreach($entries AS $entry) { - $transaction = $entry['Transaction']; - $customer = $entry['Customer']; - - $credit = $debit = null; - $running_total += $entry['balance']; - - if (isset($entry['debit'])) - $debit = $entry['debit']; - if (isset($entry['credit'])) - $credit = $entry['credit']; - - // Now that we've extracted top level 'entry' data - // move our variable to the meat of 'LedgerEntry' for clarity - $entry = $entry['LedgerEntry']; - - $rows[] = array($html->link('#'.$transaction['id'], - array('controller' => 'transactions', - 'action' => 'view', - $transaction['id'])), - $html->link('#'.$entry['id'], - array('controller' => 'ledger_entries', - 'action' => 'view', - $entry['id'])), - FormatHelper::date($transaction['stamp']), - $html->link($customer['name'], - array('controller' => 'customers', - 'action' => 'view', - $customer['id'])), - FormatHelper::comment(array($transaction['comment'], $entry['comment'])), - FormatHelper::currency($debit), - FormatHelper::currency($credit), - FormatHelper::currency($running_total) - ); -} - -echo $this->element('table', - array('class' => 'item account ledger list', - 'caption' => isset($caption) ? $caption : null, - 'headers' => $headers, - 'rows' => $rows, - 'column_class' => $column_class)); - -?> diff --git a/views/elements/ledger_entries.ctp b/views/elements/ledger_entries.ctp new file mode 100644 index 0000000..3edf18a --- /dev/null +++ b/views/elements/ledger_entries.ctp @@ -0,0 +1,69 @@ +'.__('Ledger Entries',true).''; + +$headers = array('Transaction', 'Entry', 'Date', 'Comment', 'Debit', 'Credit', 'Total'); +$column_class = array(); +foreach (array_intersect($headers, array('Transaction', 'Entry')) AS $k => $v) { + $column_class[$k] = 'id'; +} +foreach (array_intersect($headers, array('Debit', 'Credit', 'Total')) AS $k => $v) { + $column_class[$k] = 'currency'; +} +foreach (array_intersect($headers, array('Comment')) AS $k => $v) { + $column_class[$k] = 'slack'; +} + + +$rows = array(); +$running_total = 0; +foreach($ledger_entries AS $entry) { + $credit = $debit = null; + $running_total += $entry[0]['balance']; + + if (isset($entry[0]['debit'])) + $debit = $entry[0]['debit']; + if (isset($entry[0]['credit'])) + $credit = $entry[0]['credit']; + + // local references to linked tables + $transaction = $entry['Transaction']; + + // Now that we've extracted top level 'LedgerEntry' data + // move our variable to the meat of 'LedgerEntry' for clarity + if (isset($entry['LedgerEntry'])) + $entry = $entry['LedgerEntry']; + + $rows[] = array(isset($transaction['id']) + ? $html->link('#'.$transaction['id'], + array('controller' => 'transactions', + 'action' => 'view', + $transaction['id'])) + : null, + + isset($entry['id']) + ? $html->link('#'.$entry['id'], + array('controller' => 'ledger_entries', + 'action' => 'view', + $entry['id'])) + : null, + + FormatHelper::date($transaction['stamp']), + FormatHelper::comment(array($transaction['comment'], $entry['comment'])), + FormatHelper::currency($debit), + FormatHelper::currency($credit), + FormatHelper::currency($running_total) + ); +} + +echo $this->element('table', + array('class' => 'item ledger-entries list', + 'caption' => isset($caption) ? $caption : null, + 'headers' => $headers, + 'rows' => $rows, + 'column_class' => $column_class)); + +?> diff --git a/views/elements/ledgers.ctp b/views/elements/ledgers.ctp index 4155126..8013036 100644 --- a/views/elements/ledgers.ctp +++ b/views/elements/ledgers.ctp @@ -5,12 +5,15 @@ if (isset($heading)) elseif (!isset($caption)) echo '

'.__('Ledgers',true).'

'; -$headers = array_merge(array('Name'), +$headers = array_merge(array('Sequence'), //array('Name'), (isset($ledgers[0]['Account']) ? array('Account') : array()), - array('Entries', 'Debits', 'Credits', 'Balance', 'Closed', 'Comment')); + array('Entries', 'Debits', 'Credits', 'Balance', 'Close Date', 'Comment')); $column_class = array(); +foreach (array_intersect($headers, array('ID', 'Sequence')) AS $k => $v) { + $column_class[$k] = 'id'; +} foreach (array_intersect($headers, array('Debits', 'Credits', 'Balance')) AS $k => $v) { $column_class[$k] = 'currency'; } @@ -22,7 +25,7 @@ if (isset($paginator)) { echo $paginator->counter(array( 'format' => __('Page %page% of %pages%, showing %current% records (%start% - %end%) of %count% total', true))); - $headers = array_merge(array($paginator->sort('name')), + $headers = array_merge(array($paginator->sort('sequence')), //array($paginator->sort('name')), (isset($ledgers[0]['Account']) ? array($paginator->sort('Account', 'Account.name')) : array()), @@ -30,35 +33,40 @@ if (isset($paginator)) { $paginator->sort('debits'), $paginator->sort('credits'), $paginator->sort('balance'), - $paginator->sort('closed'), + $paginator->sort('Close Date', 'close_stamp'), $paginator->sort('comment'))); } $rows = array(); foreach ($ledgers as $ledger) { + $account = null; + $stats = null; + if (isset($ledger[0])) - $ledger = array_merge($ledger[0], array_diff_key($ledger, array(0=>1))); - if (isset($ledger['Ledger'])) - $ledger = array_merge($ledger['Ledger'], array_diff_key($ledger, array('Ledger'=>1))); + $stats = $ledger[0]; + else + $stats = $ledger; if (isset($ledger['Account'])) $account = $ledger['Account']; + if (isset($ledger['Ledger'])) + $ledger = $ledger['Ledger']; - $rows[] = array_merge(array($html->link($ledger['name'], + $rows[] = array_merge(array($html->link('#'.$ledger['sequence'],//$ledger['name'], array('controller' => 'ledgers', 'action' => 'view', $ledger['id']))), - (isset($ledger['Account']) + (isset($account) ? array($html->link($account['name'], array('controller' => 'accounts', 'action' => 'view', $account['id']))) : array()), - array($ledger['entries'], - FormatHelper::currency($ledger['debits']), - FormatHelper::currency($ledger['credits']), - FormatHelper::currency($ledger['balance']), - $ledger['closed'] ? 'Closed' : 'Open', + array($stats['entries'], + FormatHelper::currency($stats['debits']), + FormatHelper::currency($stats['credits']), + FormatHelper::currency($stats['balance']), + FormatHelper::datetime($ledger['close_stamp']), $ledger['comment'])); } diff --git a/views/helpers/format.php b/views/helpers/format.php index 4b93bab..948a5a8 100644 --- a/views/helpers/format.php +++ b/views/helpers/format.php @@ -13,7 +13,8 @@ class FormatHelper extends AppHelper { function currency($amount) { if (!isset($amount)) - return null; + return '-'; + //return null; return (isset($amount) ? self::$number->currency($amount) @@ -34,7 +35,7 @@ class FormatHelper extends AppHelper { } function datetime($datetime) { - if (!$date) return null; + if (!$datetime) return null; return self::$time->nice($datetime); } diff --git a/views/ledgers/view.ctp b/views/ledgers/view.ctp index 0cddc40..3b46388 100644 --- a/views/ledgers/view.ctp +++ b/views/ledgers/view.ctp @@ -56,11 +56,9 @@ echo $this->element('table', * Ledger */ -echo $this->element('ledger', +echo $this->element('ledger_entries', array('caption' => $ledger['Ledger']['name'], - 'ledger' => array('id' => $ledger['Ledger']['id'], - 'type' => $ledger['Account']['type']), - 'entries' => $ledger['LedgerEntry'])); + 'ledger_entries' => $ledger['LedgerEntry'])); /* End "detail supporting" DIV */ ?> diff --git a/views/transactions/index.ctp b/views/transactions/index.ctp index 16f1c5c..52066c9 100644 --- a/views/transactions/index.ctp +++ b/views/transactions/index.ctp @@ -1,13 +1,3 @@
- - - element('transactions', array('heading' => '

'.$heading.'

')) ?>
diff --git a/views/transactions/view.ctp b/views/transactions/view.ctp index 4771455..30c07b5 100644 --- a/views/transactions/view.ctp +++ b/views/transactions/view.ctp @@ -13,7 +13,7 @@ */ $rows = array(array('ID', $transaction['Transaction']['id']), - array('Timestamp', datefmt($transaction['Transaction']['stamp'])), + array('Timestamp', FormatHelper::datetime($transaction['Transaction']['stamp'])), array('Comment', $transaction['Transaction']['comment'])); echo $this->element('table', diff --git a/views/units/view.ctp b/views/units/view.ctp index e6b79fe..5bbc852 100644 --- a/views/units/view.ctp +++ b/views/units/view.ctp @@ -61,14 +61,14 @@ echo $this->element('leases', /********************************************************************** * Ledger History */ -foreach($unit['Lease'] AS $lease) { - pr($lease); - $caption = 'Lease #'.$lease['number'].' (Tenant: '.$lease['Customer']['name'].')'; - echo $this->element('ledger', - array('caption' => $caption, - 'entries' => $lease['Customer']['Transaction'], - 'ledger' => array('mix'=>1))); -} +/* foreach($unit['Lease'] AS $lease) { */ +/* pr($lease); */ +/* $caption = 'Lease #'.$lease['number'].' (Tenant: '.$lease['Customer']['name'].')'; */ +/* echo $this->element('lease', */ +/* array('caption' => $caption, */ +/* 'entries' => $lease['Customer']['Transaction'], */ +/* 'ledger' => array('mix'=>1))); */ +/* } */ /* End "detail supporting" DIV */ ?> diff --git a/webroot/css/layout.css b/webroot/css/layout.css index 3f7e015..0a4bd8a 100644 --- a/webroot/css/layout.css +++ b/webroot/css/layout.css @@ -110,6 +110,12 @@ table.list td.currency { text-align: right; } /* White spacing exceptions */ td.comment { white-space: normal; } +/* Generic column to assign excess space */ +table.list td.slack { width : 99%; } + +/* Customers */ +table.list.customer td.comment { width : 66%; } + /* Contacts */ table.list.contact td.comment { width : 66%; } @@ -124,16 +130,10 @@ table.list.phone td.comment , table.list.email td.comment , table.list.address td.comment { width: auto; } -/* Leases */ -table.list.lease td.comment { width : 99%; } - /* Ledger Entries */ table.list.ledger td { border-top : 1px dashed #ccc; } table.list.ledger td.date.receipt { padding-left: 1em; } table.list.ledger td.evnrow { background: #f4f4f4; } -table.list.ledger td.comment { width : 99%; } - -/* Account Ledger Entries */ /************************************************************