From 68cbca5e2862f9521d4609110268be7054965036 Mon Sep 17 00:00:00 2001 From: abijah Date: Wed, 31 Mar 2010 19:49:56 +0000 Subject: [PATCH] Added outstanding charges and outstanding credits to the customer page, and reorded fields in order of presumed importance. Removed items from Unit/Lease which really shouldn't have been there. They were added for convenience, but the redundancy was confusing. Added a couple report links to make it easy to see outstanding charges and collected rents. git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@977 97e9348a-65ac-dc4b-aefc-98561f571b83 --- site/app_controller.php | 9 ++ .../statement_entries_controller.php | 41 +++----- site/models/statement_entry.php | 99 +++++++++++++++---- site/views/customers/receipt.ctp | 8 +- site/views/customers/view.ctp | 86 +++++++++++----- site/views/elements/statement_entries.ctp | 23 ++++- site/views/helpers/grid.php | 6 ++ site/views/leases/view.ctp | 35 +++---- site/views/units/view.ctp | 20 ---- 9 files changed, 206 insertions(+), 121 deletions(-) diff --git a/site/app_controller.php b/site/app_controller.php index d325d7f..2b3412a 100644 --- a/site/app_controller.php +++ b/site/app_controller.php @@ -263,6 +263,15 @@ class AppController extends Controller { 'SITE', $this->op_area); if ($this->admin()) { + $acct = new Account; + $this->addSideMenuLink('Collected Rent', + array('controller' => 'accounts', + 'action' => 'collected', + $acct->rentAccountID()), null, + 'REPORT'); + $this->addSideMenuLink('Unpaid Charges', + array('controller' => 'statement_entries', 'action' => 'unpaid'), null, + 'REPORT'); $this->addSideMenuLink('Lease Up', array('controller' => 'leases', 'action' => 'overview'), null, 'REPORT'); diff --git a/site/controllers/statement_entries_controller.php b/site/controllers/statement_entries_controller.php index f4779e4..4103d64 100644 --- a/site/controllers/statement_entries_controller.php +++ b/site/controllers/statement_entries_controller.php @@ -11,6 +11,7 @@ class StatementEntriesController extends AppController { */ function index() { $this->gridView('All Statement Entries'); } + function unpaid() { $this->gridView('Unpaid Charges', 'unreconciled'); } /************************************************************************** @@ -123,18 +124,6 @@ class StatementEntriesController extends AppController { array(array('ChargeEntry.id' => $statement_entry_id), array('DisbursementEntry.id' => $statement_entry_id))); - if ($params['action'] === 'unreconciled') { - $query = array('conditions' => $conditions); - $set = $this->StatementEntry->reconciledSet('CHARGE', $query, true); - - $entries = array(); - foreach ($set['entries'] AS $entry) - $entries[] = $entry['StatementEntry']['id']; - - $conditions[] = array('StatementEntry.id' => $entries); - $params['userdata']['balance'] = $set['summary']['balance']; - } - return $conditions; } @@ -169,25 +158,19 @@ class StatementEntriesController extends AppController { } function gridDataRecordsExecute(&$params, &$model, $query) { -/* if ($params['action'] === '???') { */ -/* $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1)); */ -/* $tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," . */ -/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */ -/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */ -/* " AS 'applied'", */ -/* "StatementEntry.amount - (" . */ -/* "IF(StatementEntry.type = 'CHARGE'," . */ -/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */ -/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */ -/* ") AS 'balance'", */ -/* ); */ + if ($params['action'] === 'unreconciled') { + $lquery = array('conditions' => $query['conditions']); + $set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true); + + $entries = array(); + foreach ($set['entries'] AS $entry) + $entries[] = $entry['StatementEntry']['id']; + + $query['conditions'] = array('StatementEntry.id' => $entries); + $params['userdata']['balance'] = $set['summary']['balance']; + } -/* //pr(compact('tquery')); */ -/* $total = $model->find('first', $tquery); */ -/* $params['userdata']['total'] = $total[0]['applied']; */ -/* $params['userdata']['balance'] = $total[0]['balance']; */ -/* } */ if ($params['action'] === 'collected') { $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1)); $tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'"); diff --git a/site/models/statement_entry.php b/site/models/statement_entry.php index 9d58f56..c047970 100644 --- a/site/models/statement_entry.php +++ b/site/models/statement_entry.php @@ -294,7 +294,7 @@ class StatementEntry extends AppModel { } return $this->prReturn(array('entries' => $resultset, - 'summary' => $this->stats(null, $query))); + 'summary' => $this->stats(null, $query))); } @@ -338,6 +338,72 @@ class StatementEntry extends AppModel { } + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: outstandingDebits + * - Determines all debit types that have not yet been resolved. + * The name is a bit dumb, but it means any statement entry type + * that a positive customer balance could be used to offset. In + * other words, entries that are still in need of matching + * disbursements. Most notably, this means charges but could + * also mean things like refunds as well. + */ + + function outstandingDebits($query = null, $customer_id = null, + $lease_id = null, $debit_types = null) + { + $this->prEnter(compact('query', 'lease_id', + 'customer_id', 'charge_ids', + 'debit_types')); + $this->queryInit($query); + + if (empty($debit_types)) + $debit_types = $this->debitTypes(); + + if (!empty($customer_id)) + $query['conditions'][] = array('StatementEntry.customer_id' => $customer_id); + + if (!empty($lease_id)) + $query['conditions'][] = array('StatementEntry.lease_id' => $lease_id); + + /* if (isset($charge_ids)) { */ + /* // REVISIT 20100330: */ + /* // Not using $query here, as this code was extracted from its */ + /* // original location in assignCredits, and so I'm keeping the */ + /* // logic consistent. It does seem, however, that we shouldn't */ + /* // be ignoring $query if passed in. I'm sure this won't be */ + /* // looked at until someone _does_ pass $query in (and it break), */ + /* // so hopefully at that time, we can understand what needs to */ + /* // happen in that case (requirements are not clear at present). */ + /* $lquery = array('contain' => false, */ + /* 'conditions' => array('StatementEntry.id' => $charge_ids)); */ + /* } else { */ + /* $lquery = $query; */ + /* // If we're working with a specific lease, then limit charges to it */ + /* if (!empty($lease_id)) */ + /* $lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id); */ + /* } */ + + if (empty($query['order'])) + $query['order'] = 'StatementEntry.effective_date ASC'; + + $debits = array(); + foreach ($debit_types AS $dtype) { + $rset = $this->reconciledSet($dtype, $query, true); + $entries = $rset['entries']; + $debits = array_merge($debits, $entries); + $this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries"); + } + + return $this->prReturn($debits); + } + + function outstandingCharges($query = null, $customer_id = null, $lease_id = null) { + return $this->outstandingDebits($query, $customer_id, $lease_id, array('CHARGE')); + } + + /************************************************************************** ************************************************************************** ************************************************************************** @@ -359,9 +425,6 @@ class StatementEntry extends AppModel { 'customer_id', 'lease_id')); $this->queryInit($query); - if (!empty($customer_id)) - $query['conditions'][] = array('StatementEntry.customer_id' => $customer_id); - if (empty($disbursement_type)) $disbursement_type = 'DISBURSEMENT'; @@ -375,6 +438,9 @@ class StatementEntry extends AppModel { $this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt"); $lquery = $query; + if (!empty($customer_id)) + $lquery['conditions'][] = array('StatementEntry.customer_id' => $customer_id); + $lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS'); // REVISIT : 20090804 // We need to ensure that we're using surplus credits ONLY from either @@ -423,23 +489,16 @@ class StatementEntry extends AppModel { "Receipt Credit Added"); } - // Now find all unpaid charges - if (isset($charge_ids)) { - $lquery = array('contain' => false, - 'conditions' => array('StatementEntry.id' => $charge_ids)); - } else { + // Now find all unpaid charges, using either the specific set + // of charges given, or all outstanding charges based on the + // query, customer and/or lease + if (!empty($charge_ids)) { + $this->INTERNAL_ERROR("PERHAPS IMPLEMENTED - THOUGH NEVER TESTED"); $lquery = $query; - // If we're working with a specific lease, then limit charges to it - if (!empty($lease_id)) - $lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id); - } - $lquery['order'] = 'StatementEntry.effective_date ASC'; - $charges = array(); - foreach ($this->debitTypes() AS $dtype) { - $rset = $this->reconciledSet($dtype, $lquery, true); - $entries = $rset['entries']; - $charges = array_merge($charges, $entries); - $this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries"); + $lquery['conditions'][] = array('StatementEntry.id' => $charge_ids); + $charges = $this->reconciledSet('CHARGE', $query, true); + } else { + $charges = $this->outstandingDebits($query, $customer_id, $lease_id); } // Work through all unpaid charges, applying disbursements as we go diff --git a/site/views/customers/receipt.ctp b/site/views/customers/receipt.ctp index 446aa40..6e92f15 100644 --- a/site/views/customers/receipt.ctp +++ b/site/views/customers/receipt.ctp @@ -130,11 +130,11 @@ function updateCharges(id) { $("#receipt-balance").html("Calculating..."); $("#receipt-charges-caption").html("Please Wait..."); - var custom = new Array(); - custom['customer_id'] = id; + var filter = new Array(); + filter['StatementEntry.customer_id'] = id; var dynamic_post = new Array(); - dynamic_post['custom'] = custom; + dynamic_post['filter'] = filter; $('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post)); $('#charge-entries-jqGrid') @@ -333,7 +333,7 @@ echo $this->element('statement_entries', array 'action' => 'unreconciled', 'exclude' => array('Customer', 'Type', 'Debit', 'Credit'), 'include' => array('Applied', 'Balance'), - 'remap' => array('Applied' => 'Paid'), + 'remap' => array('Received' => 'Paid'), 'limit' => 8, ), )); diff --git a/site/views/customers/view.ctp b/site/views/customers/view.ctp index a5d9456..59089d0 100644 --- a/site/views/customers/view.ctp +++ b/site/views/customers/view.ctp @@ -53,15 +53,55 @@ echo '
' . "\n"; /********************************************************************** - * Contacts + * Unpaid Charges */ -echo $this->element('contacts', array +echo $this->element('statement_entries', array (// Grid configuration 'config' => array - ('caption' => 'Customer Contacts', - 'filter' => array('Customer.id' => $customer['Customer']['id']), - 'include' => array('Relationship'), + ('caption' => 'Outstanding Charges', + 'limit' => 10, + 'action' => 'unreconciled', + 'filter' => array('StatementEntry.customer_id' => $lease['id']), + 'exclude' => array('Customer'), + ))); + + +/********************************************************************** + * Customer Credits + */ + +echo $this->element('statement_entries', array + (// Grid configuration + 'config' => array + ('caption' => 'Oustanding Credits', + 'grid_div_id' => 'surplus', + 'limit' => 10, + 'filter' => array('Customer.id' => $customer['Customer']['id'], + 'StatementEntry.type' => 'SURPLUS'), + 'exclude' => array('Entry', 'Effective', 'Customer', 'Unit', 'Account', 'Debit', 'Credit'), + 'include' => array('Transaction', 'Amount'), + 'remap' => array('Transaction' => 'Receipt'), + ))); + + +/********************************************************************** + * Receipt History + */ + +echo $this->element('ledger_entries', array + (// Grid configuration + 'config' => array + ('caption' => 'Receipts', + 'limit' => 5, + 'filter' => array('Customer.id' => $customer['Customer']['id'], + 'Transaction.type' => 'RECEIPT', + 'Tender.id !=' => null, + //'Account.id !=' => '-AR-' + ), + 'include' => array('Transaction'), + 'exclude' => array('Entry', 'Account', 'Cr/Dr'), + 'remap' => array('Transaction' => 'Receipt'), ))); @@ -73,13 +113,28 @@ echo $this->element('leases', array (// Grid configuration 'config' => array ('caption' => 'Lease History', - 'filter' => array('Customer.id' => $customer['Customer']['id']), + 'limit' => 5, + 'filter' => array('Customer.id' => $customer['Customer']['id']), 'exclude' => array('Customer'), 'sort_column' => 'Move-In', 'sort_order' => 'DESC', ))); +/********************************************************************** + * Contacts + */ + +echo $this->element('contacts', array + (// Grid configuration + 'config' => array + ('caption' => 'Customer Contacts', + 'limit' => 5, + 'filter' => array('Customer.id' => $customer['Customer']['id']), + 'include' => array('Relationship'), + ))); + + /********************************************************************** * Customer Account History */ @@ -90,28 +145,11 @@ echo $this->element('statement_entries', array ('caption' => 'Customer Statement', 'filter' => array('Customer.id' => $customer['Customer']['id'], 'type !=' => 'VOID'), + 'include' => array('Sub-Total'), 'exclude' => array('Customer'), ))); -/********************************************************************** - * Receipt History - */ - -echo $this->element('ledger_entries', array - (// Grid configuration - 'config' => array - ('caption' => 'Receipts', - 'filter' => array('Customer.id' => $customer['Customer']['id'], - 'Transaction.type' => 'RECEIPT', - 'Tender.id !=' => null, - //'Account.id !=' => '-AR-' - ), - 'include' => array('Transaction'), - 'exclude' => array('Entry', 'Account', 'Cr/Dr'), - ))); - - /* End "detail supporting" div */ echo '
' . "\n"; diff --git a/site/views/elements/statement_entries.ctp b/site/views/elements/statement_entries.ctp index 7556ec6..8ebfb9f 100644 --- a/site/views/elements/statement_entries.ctp +++ b/site/views/elements/statement_entries.ctp @@ -21,7 +21,7 @@ $cols['Debit'] = array('index' => 'charge', 'formatter' => $cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency'); $cols['Amount'] = array('index' => "StatementEntry.amount", 'formatter' => 'currency'); -$cols['Applied'] = array('index' => "applied", 'formatter' => 'currency'); +$cols['Received'] = array('index' => "applied", 'formatter' => 'currency'); // 'balance' is already in use as part of charge/disbursement/balance. // 'unapplied' isn't quite the right term, but it's not customer visible. $cols['Balance'] = array('index' => "unapplied", 'formatter' => 'currency'); @@ -32,6 +32,22 @@ if (isset($subtotal_column)) $cols['Sub-Total']['index'] = 'subtotal-' . $cols[$subtotal_column]['index']; +if ((isset($action) && $action == 'unreconciled') || + (isset($config) && isset($config['action']) && $config['action'] == 'unreconciled')) { + if (isset($config) && !isset($config['grid_div_id'])) + $config['grid_div_id'] = 'unpaid'; + $include_columns = array('Entry', 'Date', + 'Effective', 'Customer', 'Unit', + 'Account', 'Amount', 'Received', 'Balance'); +} +else { + $include_columns = + array_diff(array_keys($cols), + array('Transaction', 'Through', 'Lease', + 'Amount', 'Received', 'Balance', 'Sub-Total', + 'Comment')); +} + // Include custom data $grid->customData(compact('statement_entry_id')); @@ -41,8 +57,5 @@ $grid ->sortField('Date', 'DESC') ->defaultFields(array('Entry', 'Date', 'Charge', 'Payment')) ->searchFields(array('Customer', 'Unit')) -->render($this, isset($config) ? $config : null, - array_diff(array_keys($cols), array('Transaction', 'Through', 'Lease', - 'Amount', 'Applied', 'Balance', 'Sub-Total', - 'Comment'))); +->render($this, isset($config) ? $config : null, $include_columns); diff --git a/site/views/helpers/grid.php b/site/views/helpers/grid.php index d9c3bff..f51e0b2 100644 --- a/site/views/helpers/grid.php +++ b/site/views/helpers/grid.php @@ -215,6 +215,12 @@ class GridHelper extends AppHelper { } $this->jqGrid_options['controller'] = $controller; + // Add in any custom variables requested + if (isset($config['custom'])) { + $this->customData($config['custom']); + unset($config['custom']); + } + // Incorporate all other user options if (isset($config)) $this->jqGrid_options = array_merge($this->jqGrid_options, $config); diff --git a/site/views/leases/view.ctp b/site/views/leases/view.ctp index cca4f79..b649a7a 100644 --- a/site/views/leases/view.ctp +++ b/site/views/leases/view.ctp @@ -78,6 +78,21 @@ echo '' . "\n"; echo '
' . "\n"; +/********************************************************************** + * Unpaid Charges + */ + +echo $this->element('statement_entries', array + (// Grid configuration + 'config' => array + ('caption' => 'Outstanding Charges', + 'limit' => 10, + 'action' => 'unreconciled', + 'filter' => array('StatementEntry.lease_id' => $lease['id']), + 'exclude' => array('Customer', 'Unit'), + ))); + + /********************************************************************** * Lease Account History */ @@ -86,30 +101,12 @@ echo $this->element('statement_entries', array (// Grid configuration 'config' => array ('caption' => 'Lease Statement', - 'filter' => array('Lease.id' => $lease['id']), + 'filter' => array('Lease.id' => $lease['id']), 'include' => array('Through'), 'exclude' => array('Customer', 'Lease', 'Unit'), ))); -/********************************************************************** - * Receipt History - */ - -echo $this->element('ledger_entries', array - (// Grid configuration - 'config' => array - ('caption' => 'Customer Receipts', - 'filter' => array('Customer.id' => $customer['id'], - 'Transaction.type' => 'RECEIPT', - 'Tender.id !=' => null, - //'Account.id !=' => '-AR-' - ), - 'include' => array('Transaction'), - 'exclude' => array('Entry', 'Account', 'Cr/Dr'), - ))); - - /* End "detail supporting" div */ echo '
' . "\n"; diff --git a/site/views/units/view.ctp b/site/views/units/view.ctp index 3792bec..3b68f91 100644 --- a/site/views/units/view.ctp +++ b/site/views/units/view.ctp @@ -76,26 +76,6 @@ echo $this->element('leases', array ))); -/********************************************************************** - * Current Customer Lease Account History - */ - -if (isset($current_lease['id'])) { - echo $this->element('statement_entries', array - (// Grid configuration - 'config' => array - ( - 'caption' => - ('Current Lease Statement (' - . $current_lease['Customer']['name'] - . ')'), - 'filter' => array('Lease.id' => $current_lease['id']), - 'include' => array('Through'), - 'exclude' => array('Customer', 'Lease', 'Unit'), - ))); -} - - /* End "detail supporting" div */ echo '' . "\n";