Another snapshot

git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716/site@356 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
abijah
2009-07-20 23:35:11 +00:00
parent bfbf119aca
commit d5bcd9a496
20 changed files with 696 additions and 759 deletions

View File

@@ -81,6 +81,27 @@ class AppModel extends Model {
} //end getEnumValues } //end getEnumValues
/**************************************************************************
**************************************************************************
**************************************************************************
* function: queryInit
* - Initializes the query fields
*/
function queryInit(&$query, $link = true) {
if (!isset($query))
$query = array();
if (!isset($query['conditions']))
$query['conditions'] = array();
if (!isset($query['group']))
$query['group'] = null;
if (!isset($query['fields']))
$query['fields'] = null;
if ($link && !isset($query['link']))
$query['link'] = array();
if (!$link && !isset($query['contain']))
$query['contain'] = array();
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************

View File

@@ -76,7 +76,7 @@ class AccountsController extends AppController {
function jqGridDataFields(&$params, &$model) { function jqGridDataFields(&$params, &$model) {
return array_merge(array('Account.*'), return array_merge(array('Account.*'),
$this->Account->Ledger->DoubleEntry->debitCreditFields('DoubleEntry', 'CurrentLedger')); $this->Account->Ledger->DoubleEntry->debitCreditFields(true, 'DoubleEntry', 'CurrentLedger'));
} }
function jqGridDataConditions(&$params, &$model) { function jqGridDataConditions(&$params, &$model) {
@@ -245,8 +245,9 @@ class AccountsController extends AppController {
); );
// Get all ledger entries of the CURRENT ledger // Get all ledger entries of the CURRENT ledger
$entries = $this->Account->findLedgerEntries($id); $entries = $this->Account->ledgerEntries($id);
$account['CurrentLedger']['DoubleEntry'] = $entries['Entries']; //pr(compact('entries'));
$account['CurrentLedger']['DoubleEntry'] = $entries;
// Summarize each ledger // Summarize each ledger
foreach($account['Ledger'] AS &$ledger) foreach($account['Ledger'] AS &$ledger)
@@ -270,7 +271,7 @@ class AccountsController extends AppController {
} }
function tst($id) { function tst($id) {
$entries = $this->Account->unreconciledEntries($id); //$entries = $this->Account->($id);
pr($entries); pr($entries);
} }
} }

View File

@@ -63,9 +63,9 @@ class CustomersController extends AppController {
function jqGridDataTables(&$params, &$model) { function jqGridDataTables(&$params, &$model) {
$link = $this->jqGridDataCountTables($params, $model); $link = $this->jqGridDataCountTables($params, $model);
$link['link']['LedgerEntry'] = array('fields' => array()); $link['link']['DoubleEntry'] = array('fields' => array());
$link['link']['LedgerEntry']['Ledger'] = array('fields' => array()); $link['link']['DoubleEntry']['Ledger'] = array('fields' => array());
$link['link']['LedgerEntry']['Ledger']['Account'] = array('fields' => array()); $link['link']['DoubleEntry']['Ledger']['Account'] = array('fields' => array());
// INNER JOIN would be great, as it would ensure we're only looking // INNER JOIN would be great, as it would ensure we're only looking
// at the ledger entries that we truly want. However, this also // at the ledger entries that we truly want. However, this also
// removes from the query any units that do not yet have a ledger // removes from the query any units that do not yet have a ledger
@@ -73,10 +73,10 @@ class CustomersController extends AppController {
// and LEFT JOIN it to the rest. Grouping of JOINs, however, is // and LEFT JOIN it to the rest. Grouping of JOINs, however, is
// implemented with the 'joins' tag, and is not available through // implemented with the 'joins' tag, and is not available through
// the Linkable behavior interface. // the Linkable behavior interface.
//$link['link']['LedgerEntry']['Ledger']['Account']['type'] = 'INNER'; //$link['link']['DoubleEntry']['Ledger']['Account']['type'] = 'INNER';
$link['link']['LedgerEntry']['Ledger']['Account']['conditions'] $link['link']['DoubleEntry']['Ledger']['Account']['conditions']
= array('Account.id' => = array('Account.id' =>
$this->Customer->LedgerEntry->Ledger->Account->accountReceivableAccountID()); $this->Customer->DoubleEntry->Ledger->Account->accountReceivableAccountID());
return $link; return $link;
} }
@@ -85,9 +85,9 @@ class CustomersController extends AppController {
$fields = $db->fields($model, $model->alias); $fields = $db->fields($model, $model->alias);
$fields[] = ('COUNT(DISTINCT CurrentLease.id) AS lease_count'); $fields[] = ('COUNT(DISTINCT CurrentLease.id) AS lease_count');
$fields[] = ("SUM(IF(Account.id IS NULL, 0," . $fields[] = ("SUM(IF(Account.id IS NULL, 0," .
" IF(LedgerEntry.debit_ledger_id = Account.id," . " IF(DoubleEntry.debit_ledger_id = Account.id," .
" 1, -1))" . " 1, -1))" .
" * IF(LedgerEntry.amount IS NULL, 0, LedgerEntry.amount))" . " * IF(DoubleEntry.amount IS NULL, 0, DoubleEntry.amount))" .
" AS 'balance'"); " AS 'balance'");
return $fields; return $fields;
} }
@@ -247,10 +247,18 @@ class CustomersController extends AppController {
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
} }
$customer = $this->Customer->details($id); /* //$result = $this->Customer->securityDeposits($id); */
/* $result = $this->Customer->excessPayments($id); */
/* //$result = $this->Customer->unreconciledCharges($id); */
/* echo('<HR>'); */
/* pr($result); */
/* $this->autoRender = false; */
/* return; */
$customer = $this->Customer->details($id);
//pr($customer);
$outstanding_balance = $customer['stats']['balance']; $outstanding_balance = $customer['stats']['balance'];
$outstanding_deposit = $customer['deposits']['summary']['balance']; $outstanding_deposit = $customer['deposits']['summary']['Payment']['reconciled'];
// Figure out if this customer has any non-closed leases // Figure out if this customer has any non-closed leases
$show_moveout = false; $show_moveout = false;
@@ -429,17 +437,17 @@ class CustomersController extends AppController {
*/ */
function refund() { function refund() {
$entries = $this->Customer->LedgerEntry->find $entries = $this->Customer->DoubleEntry->find
('all', array ('all', array
('contain' => false, ('contain' => false,
'conditions' => array('LedgerEntry.id' => 'conditions' => array('DoubleEntry.id' =>
//array(199,200,201) //array(199,200,201)
61 61
), ),
)); ));
pr(compact('entries')); pr(compact('entries'));
$this->Customer->LedgerEntry->reverse($entries); $this->Customer->DoubleEntry->reverse($entries);
} }
@@ -473,8 +481,8 @@ class CustomersController extends AppController {
if (!count($unreconciled['entries']['entry'])) if (!count($unreconciled['entries']['entry']))
unset($unreconciled['entries']['entry']); unset($unreconciled['entries']['entry']);
pr($unreconciled); //pr($unreconciled);
//$reconciled = $cust->reconcileNewLedgerEntry($cust_id, 'credit', $amount); //$reconciled = $cust->reconcileNewDoubleEntry($cust_id, 'credit', $amount);
$opts = array(); $opts = array();
//$opts['format'] = 'tags'; //$opts['format'] = 'tags';

View File

@@ -35,7 +35,11 @@ class EntriesController extends AppController {
$link = $link =
array(// Models array(// Models
'Account' => 'Account' =>
array('fields' => array('id', 'name'), array('fields' => array('id', 'name', 'type'),
),
'Ledger' =>
array('fields' => array('id', 'sequence'),
), ),
'DoubleEntry' => array 'DoubleEntry' => array
@@ -43,6 +47,20 @@ class EntriesController extends AppController {
array('fields' => array('id', 'stamp'), array('fields' => array('id', 'stamp'),
), ),
'DebitLedger' =>
array('fields' => array('id'),
'Account' => array('alias' => 'DebitAccount',
'fields' => array('id', 'name'),
),
),
'CreditLedger' =>
array('fields' => array('id'),
'Account' => array('alias' => 'CreditAccount',
'fields' => array('id', 'name'),
),
),
'Customer' => 'Customer' =>
array('fields' => array('id', 'name'), array('fields' => array('id', 'name'),
), ),
@@ -56,22 +74,23 @@ class EntriesController extends AppController {
), ),
); );
if ($params['action'] === 'collected' || if (count(array_intersect($params['fields'], array('applied'))) == 1) {
isset($params['custom']['reconcile_id'])) { $link['Payment'] = array('DoubleEntry' =>
$link['Payment'] = array(//'linkalias' => 'MatchingPayment', array('alias' => 'PaymentDoubleEntry',
'Receipt'),
'Account' => array('alias' => 'PaymentAccount'), 'Account' => array('alias' => 'PaymentAccount'),
'Receipt'); );
$link['Charge'] = array(//'linkalias' => 'MatchingCharge', $link['Charge'] = array('DoubleEntry' =>
array('alias' => 'ChargeDoubleEntry',
'Invoice'),
'Account' => array('alias' => 'ChargeAccount'), 'Account' => array('alias' => 'ChargeAccount'),
'Invoice'); );
} }
elseif (isset($params['custom']['customer_id']) || isset($params['custom']['lease_id'])) {
if (isset($params['custom']['ledger_id'])) { $link['Charge'] = array('DoubleEntry' =>
$link['Ledger'] = array('alias' => 'ChargeDoubleEntry',
array('fields' => array('id', 'sequence'), 'Invoice'),
'Account' => 'Account' => array('alias' => 'ChargeAccount'),
array('fields' => array('id', 'name'),
),
); );
} }
@@ -81,20 +100,40 @@ class EntriesController extends AppController {
function jqGridDataFields(&$params, &$model) { function jqGridDataFields(&$params, &$model) {
$fields = parent::jqGridDataFields($params, $model); $fields = parent::jqGridDataFields($params, $model);
if (!isset($fields))
$fields = array('Entry.*');
/* if (isset($params['custom']['reconcile_id'])) { */
/* $fields[] = array("IF(Entry.type = 'CHARGE',", */
/* " COALESCE(AppliedCharge.amount,0),", */
/* " COALESCE(AppliedPayment.amount,0))", */
/* " AS 'applied'"); */
/* $fields[] = array("Entry.amount - (", */
/* "IF(Entry.type = 'CHARGE',", */
/* " COALESCE(AppliedCharge.amount,0),", */
/* " COALESCE(AppliedPayment.amount,0))", */
/* ") AS 'balance'"); */
/* } */
if (isset($params['custom']['customer_id']) || isset($params['custom']['lease_id'])) {
$fields[] = "IF(Entry.type = 'CHARGE', DoubleEntry.amount, NULL) AS debit";
$fields[] = "IF(Entry.type = 'PAYMENT', DoubleEntry.amount, NULL) AS credit";
$fields[] = "IF(Entry.type = 'CHARGE', 1, -1) * DoubleEntry.amount AS balance";
}
else {
if (count(array_intersect($params['fields'], array('applied'))) == 1) if (count(array_intersect($params['fields'], array('applied'))) == 1)
$fields[] = ('SUM(COALESCE(AppliedPayment.amount,0)' . $fields[] = ('SUM(COALESCE(AppliedPayment.amount,0)' .
' + COALESCE(AppliedCharge.amount,0)) AS applied'); ' + COALESCE(AppliedCharge.amount,0)) AS applied');
if (isset($params['custom']['reconcile_id'])) { if (count(array_intersect($params['fields'], array('debit', 'credit'))) >= 1) {
$fields[] = array("IF(Entry.type = 'CHARGE',", $fields = array_merge($fields,
" COALESCE(AppliedCharge.amount,0),", $this->Entry->DoubleEntry->debitCreditFields());
" COALESCE(AppliedPayment.amount,0))", /* $fields = array_merge($fields, */
" AS 'applied'"); /* $this->Entry->Account->debitCreditFields()); */
$fields[] = array("Entry.amount - (", /* $fields[] = "IF(Entry.crdr = 'CREDIT', DoubleEntry.amount, NULL) AS credit"; */
"IF(Entry.type = 'CHARGE',", /* $fields[] = "IF(Entry.crdr = 'DEBIT', DoubleEntry.amount, NULL) AS debit"; */
" COALESCE(AppliedCharge.amount,0),", /* $fields[] = "IF(Account.type IN Entry.crdr = 'DEBIT', DoubleEntry.amount, NULL) AS debit"; */
" COALESCE(AppliedPayment.amount,0))", }
") AS 'balance'");
} }
if ($params['action'] === 'collected') if ($params['action'] === 'collected')
@@ -145,13 +184,37 @@ class EntriesController extends AppController {
} }
if (isset($params['custom']['customer_id'])) { if (isset($params['custom']['customer_id'])) {
$customer_id = $params['custom']['customer_id'];
$conditions[] = $conditions[] =
array('Customer.id' => $params['custom']['customer_id']); array('OR' =>
array(array(array('Entry.type' => 'CHARGE'),
array('DoubleEntry.customer_id' => $customer_id)),
array(array('Entry.type' => 'PAYMENT'),
array('ChargeDoubleEntry.customer_id' => $customer_id)),
),
);
} }
if (isset($params['custom']['lease_id'])) { if (isset($params['custom']['lease_id'])) {
$lease_id = $params['custom']['lease_id'];
$conditions[] = $conditions[] =
array('Lease.id' => $params['custom']['lease_id']); array('OR' =>
array(array(array('Entry.type' => 'CHARGE'),
array('DoubleEntry.lease_id' => $lease_id)),
array(array('Entry.type' => 'PAYMENT'),
array('ChargeDoubleEntry.lease_id' => $lease_id)),
),
);
/* array('OR' => */
/* array('AND' => */
/* array(array('Entry.type' => 'CHARGE'), */
/* array('DoubleEntry.lease_id' => $lease_id)) */
/* ), */
/* array('AND' => */
/* array(array('Entry.type' => 'PAYMENT'), */
/* array('ChargeDoubleEntry.lease_id' => $lease_id)), */
/* ), */
/* ); */
} }
if (isset($params['custom']['transaction_id'])) { if (isset($params['custom']['transaction_id'])) {

View File

@@ -57,9 +57,9 @@ class LeasesController extends AppController {
function jqGridDataTables(&$params, &$model) { function jqGridDataTables(&$params, &$model) {
$link = $this->jqGridDataCountTables($params, $model); $link = $this->jqGridDataCountTables($params, $model);
$link['link']['LedgerEntry'] = array('fields' => array()); $link['link']['DoubleEntry'] = array('fields' => array());
$link['link']['LedgerEntry']['Ledger'] = array('fields' => array()); $link['link']['DoubleEntry']['Ledger'] = array('fields' => array());
$link['link']['LedgerEntry']['Ledger']['Account'] = array('fields' => array()); $link['link']['DoubleEntry']['Ledger']['Account'] = array('fields' => array());
// INNER JOIN would be great, as it would ensure we're only looking // INNER JOIN would be great, as it would ensure we're only looking
// at the ledger entries that we truly want. However, this also // at the ledger entries that we truly want. However, this also
// removes from the query any leases that do not yet have a ledger // removes from the query any leases that do not yet have a ledger
@@ -67,10 +67,10 @@ class LeasesController extends AppController {
// and LEFT JOIN it to the rest. Grouping of JOINs, however, is // and LEFT JOIN it to the rest. Grouping of JOINs, however, is
// implemented with the 'joins' tag, and is not available through // implemented with the 'joins' tag, and is not available through
// the Linkable behavior interface. // the Linkable behavior interface.
//$link['link']['LedgerEntry']['Ledger']['Account']['type'] = 'INNER'; //$link['link']['DoubleEntry']['Ledger']['Account']['type'] = 'INNER';
$link['link']['LedgerEntry']['Ledger']['Account']['conditions'] $link['link']['DoubleEntry']['Ledger']['Account']['conditions']
= array('Account.id' => = array('Account.id' =>
$this->Lease->LedgerEntry->Ledger->Account->accountReceivableAccountID()); $this->Lease->DoubleEntry->Ledger->Account->accountReceivableAccountID());
return $link; return $link;
} }
@@ -78,9 +78,9 @@ class LeasesController extends AppController {
$db = &$model->getDataSource(); $db = &$model->getDataSource();
$fields = $db->fields($model, $model->alias); $fields = $db->fields($model, $model->alias);
$fields[] = ("SUM(IF(Account.id IS NULL, 0," . $fields[] = ("SUM(IF(Account.id IS NULL, 0," .
" IF(LedgerEntry.debit_ledger_id = Account.id," . " IF(DoubleEntry.debit_ledger_id = Account.id," .
" 1, -1))" . " 1, -1))" .
" * IF(LedgerEntry.amount IS NULL, 0, LedgerEntry.amount))" . " * IF(DoubleEntry.amount IS NULL, 0, DoubleEntry.amount))" .
" AS 'balance'"); " AS 'balance'");
return $fields; return $fields;
} }
@@ -252,10 +252,10 @@ class LeasesController extends AppController {
$receipt_transaction = array_intersect_key($this->data, $receipt_transaction = array_intersect_key($this->data,
array('Transaction'=>1, array('Transaction'=>1,
'transaction_id'=>1)); 'transaction_id'=>1));
foreach ($data['LedgerEntry'] AS $entry) { foreach ($data['DoubleEntry'] AS $entry) {
// Create the receipt entry, and reconcile the credit side // Create the receipt entry, and reconcile the credit side
// of the double-entry (which should be A/R) as a payment. // of the double-entry (which should be A/R) as a payment.
$ids = $this->LedgerEntry->Ledger->Account->postLedgerEntry $ids = $this->DoubleEntry->Ledger->Account->postDoubleEntry
($receipt_transaction, ($receipt_transaction,
array_intersect_key($entry, array('MonetarySource'=>1)) array_intersect_key($entry, array('MonetarySource'=>1))
+ array_intersect_key($entry, array('account_id'=>1)), + array_intersect_key($entry, array('account_id'=>1)),
@@ -269,6 +269,14 @@ class LeasesController extends AppController {
if ($ids['error']) if ($ids['error'])
$ret = false; $ret = false;
$db = &$model->getDataSource();
$fields = $db->fields($model, $model->alias);
$fields[] = ("SUM(IF(Account.id IS NULL, 0," .
" IF(LedgerEntry.debit_ledger_id = Account.id," .
" 1, -1))" .
" * IF(LedgerEntry.amount IS NULL, 0, LedgerEntry.amount))" .
" AS 'balance'");
return $fields;
$receipt_transaction = array_intersect_key($ids, $receipt_transaction = array_intersect_key($ids,
array('transaction_id'=>1, array('transaction_id'=>1,
'split_transaction_id'=>1)); 'split_transaction_id'=>1));
@@ -315,7 +323,7 @@ class LeasesController extends AppController {
array('stats' => $this->Lease->stats($id))); array('stats' => $this->Lease->stats($id)));
// Determine the lease security deposit // Determine the lease security deposit
$deposit = $this->Lease->findSecurityDeposits($lease['Lease']['id']); $deposit = $this->Lease->securityDeposits($lease['Lease']['id']);
$this->set(compact('deposit')); $this->set(compact('deposit'));
$this->set('customer', $lease['Customer']); $this->set('customer', $lease['Customer']);
$this->set('unit', $lease['Unit']); $this->set('unit', $lease['Unit']);
@@ -371,7 +379,7 @@ class LeasesController extends AppController {
array('stats' => $this->Lease->stats($id))); array('stats' => $this->Lease->stats($id)));
// Determine the lease security deposit // Determine the lease security deposit
$deposit = $this->Lease->findSecurityDeposits($lease['Lease']['id']); $deposit = $this->Lease->securityDeposits($lease['Lease']['id']);
if ($deposit['summary']['balance'] > 0) if ($deposit['summary']['balance'] > 0)
die("Still have un-utilized security deposit"); die("Still have un-utilized security deposit");
@@ -406,7 +414,7 @@ class LeasesController extends AppController {
/* $outstanding_balance = $stats['balance']; */ /* $outstanding_balance = $stats['balance']; */
/* // Determine the lease security deposit */ /* // Determine the lease security deposit */
/* $deposits = $this->Lease->findSecurityDeposits($id); */ /* $deposits = $this->Lease->securityDeposits($id); */
/* $outstanding_deposit = $deposits['summary']['balance']; */ /* $outstanding_deposit = $deposits['summary']['balance']; */
@@ -515,8 +523,8 @@ class LeasesController extends AppController {
$outstanding_balance = $lease['Lease']['stats']['balance']; $outstanding_balance = $lease['Lease']['stats']['balance'];
// Determine the lease security deposit // Determine the lease security deposit
$deposits = $this->Lease->findSecurityDeposits($lease['Lease']['id']); $deposits = $this->Lease->securityDeposits($lease['Lease']['id']);
$outstanding_deposit = $deposits['summary']['balance']; $outstanding_deposit = $deposits['summary']['Payment']['reconciled'];
// Set up dynamic menu items // Set up dynamic menu items
if (!isset($lease['Lease']['close_date'])) { if (!isset($lease['Lease']['close_date'])) {

View File

@@ -67,7 +67,7 @@ class LedgersController extends AppController {
function jqGridDataFields(&$params, &$model) { function jqGridDataFields(&$params, &$model) {
return array_merge(array('Ledger.*', return array_merge(array('Ledger.*',
'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence'), 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence'),
$this->Ledger->DoubleEntry->debitCreditFields()); $this->Ledger->DoubleEntry->debitCreditFields(true));
} }
function jqGridDataConditions(&$params, &$model) { function jqGridDataConditions(&$params, &$model) {

View File

@@ -97,6 +97,41 @@ class Account extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: debitCreditFields
* - Returns the fields necessary to determine whether the queried
* entries are a debit, or a credit, and also the effect each have
* on the overall balance of the account.
*/
function debitCreditFields($id, $sum = false,
$entry_name = 'Entry', $double_name = 'DoubleEntry') {
$ftype = strtoupper($this->fundamentalType($id));
$fields = array
(
($sum ? 'SUM(' : '') .
"IF({$entry_name}.crdr = 'DEBIT', {$double_name}.amount, NULL)" .
($sum ? ')' : '') . ' AS debit' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') .
"IF({$entry_name}.crdr = 'CREDIT', {$double_name}.amount, NULL)" .
($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') .
"IF({$entry_name}.crdr = '$ftype', 1, -1) * {$double_name}.amount" .
// IF({$double_name}.amount, {$double_name}.amount, 0)" .
($sum ? ')' : '') . ' AS balance',
);
if ($sum)
$fields[] = "COUNT({$entry_name}.id) AS entries";
return $fields;
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -346,7 +381,7 @@ class Account extends AppModel {
$link['Account'] = array('fields' => array()); $link['Account'] = array('fields' => array());
$cond[] = array('Account.id' => $id); $cond[] = array('Account.id' => $id);
$set = $this->Ledger->Entry->reconciledSet($set, $cond, $link, true); $set = $this->Ledger->Entry->reconciledSet($set, $cond, $link, true);
pr(compact('set')); //pr(compact('set'));
return $set; return $set;
} }
@@ -416,7 +451,7 @@ class Account extends AppModel {
function reconcileLedgerEntries($id, $cond = null) { function reconcileLedgerEntries($id, $cond = null) {
$unreconciled = $this->findUnreconciledLedgerEntries($id, null, $cond); $unreconciled = $this->findUnreconciledLedgerEntries($id, null, $cond);
pr(compact('unreconciled')); //pr(compact('unreconciled'));
$entry = array(); $entry = array();
foreach (array('debit', 'credit') AS $dc) foreach (array('debit', 'credit') AS $dc)
@@ -465,7 +500,7 @@ class Account extends AppModel {
$unreconciled['debit'] ['unapplied'] = $unreconciled['credit']['balance']; $unreconciled['debit'] ['unapplied'] = $unreconciled['credit']['balance'];
$unreconciled['credit']['unapplied'] = $unreconciled['debit'] ['balance']; $unreconciled['credit']['unapplied'] = $unreconciled['debit'] ['balance'];
pr(compact('unreconciled')); //pr(compact('unreconciled'));
return $unreconciled; return $unreconciled;
} }
@@ -787,37 +822,47 @@ class Account extends AppModel {
* - Returns summary data from the requested account. * - Returns summary data from the requested account.
*/ */
function stats($id = null, $all = false, $cond = null) { function stats($id = null, $all = false, $query = null) {
if (!$id) if (!$id)
return null; return null;
// All old, closed ledgers MUST balance to 0. $this->queryInit($query);
// However, the user may want the ENTIRE running totals,
// (not just the balance), so we may have to query all
// ledgers, as dictated by the $all parameter.
$account = $this->find('first', /* if ($all) { */
array('contain' => /* if (!isset($query['link']['Ledger'])) */
($all /* $query['link']['Ledger'] = array(); */
? array('Ledger' => array /* if (!isset($query['link']['Ledger']['fields'])) */
('fields' => array('id'))) /* $query['link']['Ledger']['fields'] = array(); */
: array('CurrentLedger' => array /* $query['link']['Ledger']['fields'][] = 'id'; */
('fields' => array('id'))) /* } */
), /* else { */
'conditions' => array /* if (!isset($query['link']['CurrentLedger'])) */
(array('Account.id' => $id)) /* $query['link']['CurrentLedger'] = array(); */
)); /* if (!isset($query['link']['CurrentLedger']['fields'])) */
/* $query['link']['CurrentLedger']['fields'] = array(); */
/* $query['link']['CurrentLedger']['fields'][] = 'id'; */
/* } */
$stats = array(); /* $query['conditions'][] = array('Account.id' => $id); */
if ($all) {
foreach ($account['Ledger'] AS $ledger) /* $account = $this->find('first', $query); */
$query['link'] = array('Account' => $query['link']);
foreach ($this->ledgers($id, $all) AS $ledger)
$this->statsMerge($stats['Ledger'], $this->statsMerge($stats['Ledger'],
$this->Ledger->stats($ledger['id'], $cond)); $this->Ledger->stats($ledger, $query));
}
else { /* $stats = array(); */
$stats['Ledger'] = /* if ($all) { */
$this->Ledger->stats($account['CurrentLedger']['id'], $cond); /* foreach ($account['Ledger'] AS $ledger) */
} /* $this->statsMerge($stats['Ledger'], */
/* $this->Ledger->stats($ledger['id'], $query)); */
/* } */
/* else { */
/* $stats['Ledger'] = */
/* $this->Ledger->stats($account['CurrentLedger']['id'], $query); */
/* } */
return $stats; return $stats;
} }

View File

@@ -73,26 +73,27 @@ class Customer extends AppModel {
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
* function: findSecurityDeposits * function: securityDeposits
* - Returns an array of security deposit entries * - Returns an array of security deposit entries
*/ */
function findSecurityDeposits($id, $link = null) { function securityDeposits($id, $query = null) {
/* pr(array('function' => 'Customer::findSecurityDeposits', */ $this->queryInit($query);
/* 'args' => compact('id', 'link'), */
/* )); */
$A = new Account(); $A = new Account();
$entries = $A->ledgerEntries
($A->securityDepositAccountID(),
true, array('DoubleEntry.customer_id' => $id), $link);
/* pr(array('function' => 'Customer::findSecurityDeposits', */ if (!isset($query['link']['DoubleEntry']))
/* 'args' => compact('id', 'link'), */ $query['link']['DoubleEntry'] = array();
/* 'vars' => compact('customer'), */ if (!isset($query['link']['DoubleEntry']['Customer']))
/* 'return' => compact('entries'), */ $query['link']['DoubleEntry']['Customer'] = array();
/* )); */ if (!isset($query['link']['DoubleEntry']['Customer']['fields']))
$query['link']['DoubleEntry']['Customer']['fields'] = array();
return $entries; $query['conditions'][] = array('Customer.id' => $id);
$query['conditions'][] = array('Entry.account_id' => $A->securityDepositAccountID());
$set = $this->DoubleEntry->Entry->reconciledSet('CHARGE', $query);
//pr(compact('set'));
return $set;
} }
@@ -103,20 +104,45 @@ class Customer extends AppModel {
* - Returns charges have not yet been fully paid * - Returns charges have not yet been fully paid
*/ */
function unreconciledCharges($id, $cond = null, $link = null) { function unreconciledCharges($id, $query = null) {
if (!isset($cond)) $this->queryInit($query);
$cond = array();
if (!isset($link)) if (!isset($query['link']['DoubleEntry']))
$link = array(); $query['link']['DoubleEntry'] = array();
if (!isset($link['DoubleEntry'])) if (!isset($query['link']['DoubleEntry']['Customer']))
$link['DoubleEntry'] = array(); $query['link']['DoubleEntry']['Customer'] = array();
if (!isset($link['DoubleEntry']['Customer'])) if (!isset($query['link']['DoubleEntry']['Customer']['fields']))
$link['DoubleEntry']['Customer'] = array(); $query['link']['DoubleEntry']['Customer']['fields'] = array();
if (!isset($link['DoubleEntry']['Customer']['fields']))
$link['DoubleEntry']['Customer']['fields'] = array(); $query['conditions'][] = array('Customer.id' => $id);
$cond[] = array('Customer.id' => $id);
$set = $this->DoubleEntry->Entry->reconciledSet('CHARGE', $cond, $link, true); $set = $this->DoubleEntry->Entry->reconciledSet('CHARGE', $query, true);
pr(compact('set')); //pr(compact('set'));
return $set;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: excessPayments
* - Returns payments which have not yet been fully utilized
*/
function excessPayments($id, $query = null) {
$this->queryInit($query);
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
if (!isset($query['link']['DoubleEntry']['Customer']))
$query['link']['DoubleEntry']['Customer'] = array();
if (!isset($query['link']['DoubleEntry']['Customer']['fields']))
$query['link']['DoubleEntry']['Customer']['fields'] = array();
$query['conditions'][] = array('Customer.id' => $id);
$set = $this->DoubleEntry->Entry->reconciledSet('PAYMENT', $query, true);
//pr(compact('set'));
return $set; return $set;
} }
@@ -125,8 +151,7 @@ class Customer extends AppModel {
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
* function: paymentWouldReconcile * function: paymentWouldReconcile
* - Returns which ledger entries a new credit/debit would * - Returns which charges a new payment would reconcile
* reconcile, and how much.
* *
* - REVISIT <AP> 20090617 * - REVISIT <AP> 20090617
* This should be subject to different algorithms, such * This should be subject to different algorithms, such
@@ -135,16 +160,17 @@ class Customer extends AppModel {
* whatever algorithm is simplest. * whatever algorithm is simplest.
*/ */
function paymentWouldReconcile($id, $amount, $cond = null, $link = null) { function paymentWouldReconcile($id, $amount, $query = null) {
$unreconciled = array($ofund => array('entry'=>array(), 'balance'=>0)); $unreconciled = array($ofund => array('entry'=>array(), 'balance'=>0));
$applied = 0; $applied = 0;
if ($amount <= 0) if ($amount <= 0)
return; return;
$unreconciled = $this->unreconciledEntries($id, 'CHARGE', $cond, $link); $unreconciled = array();
$unreconciled['entries'] = $this->unreconciledCharges($id, $query);
foreach ($unreconciled AS $i => &$item) { foreach ($unreconciled['entries'] AS $i => &$item) {
$entry =& $item['DoubleEntry']; $entry =& $item['DoubleEntry'];
// Determine if amount is sufficient to cover the entry // Determine if amount is sufficient to cover the entry
if ($amount > $entry['balance']) if ($amount > $entry['balance'])
@@ -170,51 +196,6 @@ class Customer extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: findUnreconciledLedgerEntries
* - Returns ledger entries that are not yet reconciled
* (such as charges not paid).
*/
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null) {
$A = new Account();
$unreconciled = $A->findUnreconciledLedgerEntries
($A->accountReceivableAccountID(),
$fundamental_type,
array('DoubleEntry.customer_id' => $id));
return $unreconciled;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: amountWouldReconcile
* - Returns which ledger entries a new credit/debit would
* reconcile, and how much.
*
* - REVISIT <AP> 20090617
* This should be subject to different algorithms, such
* as apply to oldest charges first, newest first, to fees
* before rent, etc. Until we get there, I'll hardcode
* whatever algorithm is simplest.
*/
function amountWouldReconcile($id, $fundamental_type, $amount) {
$A = new Account();
$reconciled = $A->amountWouldReconcile
($A->accountReceivableAccountID(),
$fundamental_type,
$amount,
array('DoubleEntry.customer_id' => $id));
return $reconciled;
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -273,7 +254,7 @@ class Customer extends AppModel {
$customer['stats'] = $this->stats($id); $customer['stats'] = $this->stats($id);
// Figure out the total security deposit for the current lease. // Figure out the total security deposit for the current lease.
$customer['deposits'] = $this->findSecurityDeposits($id); $customer['deposits'] = $this->securityDeposits($id);
return $customer; return $customer;
} }

View File

@@ -29,10 +29,12 @@ class DoubleEntry extends AppModel {
'Invoice' => array( 'Invoice' => array(
'className' => 'Transaction', 'className' => 'Transaction',
'conditions' => array('Invoice.type' => 'INVOICE'), 'conditions' => array('Invoice.type' => 'INVOICE'),
'foreignKey' => 'transaction_id',
), ),
'Receipt' => array( 'Receipt' => array(
'className' => 'Transaction', 'className' => 'Transaction',
'conditions' => array('Invoice.type' => 'RECEIPT'), 'conditions' => array('Invoice.type' => 'RECEIPT'),
'foreignKey' => 'transaction_id',
), ),
@@ -81,7 +83,7 @@ class DoubleEntry extends AppModel {
} }
function debitCreditFields($double_name = 'DoubleEntry', $ledger_name = 'Ledger', $sum = true) { function debitCreditFields($sum = false, $double_name = 'DoubleEntry', $ledger_name = 'Ledger', $account_name = 'Account') {
$fields = array $fields = array
( (
($sum ? 'SUM(' : '') . ($sum ? 'SUM(' : '') .
@@ -95,7 +97,7 @@ class DoubleEntry extends AppModel {
($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''), ($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') . ($sum ? 'SUM(' : '') .
"IF(Account.type IN ('ASSET', 'EXPENSE'), "IF({$account_name}.type IN ('ASSET', 'EXPENSE'),
IF({$double_name}.debit_ledger_id = {$ledger_name}.id, 1, -1), IF({$double_name}.debit_ledger_id = {$ledger_name}.id, 1, -1),
IF({$double_name}.credit_ledger_id = {$ledger_name}.id, 1, -1) IF({$double_name}.credit_ledger_id = {$ledger_name}.id, 1, -1)
) * IF({$double_name}.amount, {$double_name}.amount, 0)" . ) * IF({$double_name}.amount, {$double_name}.amount, 0)" .

View File

@@ -8,15 +8,6 @@ class Entry extends AppModel {
var $hasAndBelongsToMany = array( var $hasAndBelongsToMany = array(
// The Payments that match THIS Charge (if it is one)
'Payment' => array(
'className' => 'Entry',
'joinTable' => 'charges_payments',
'linkalias' => 'AppliedPayment',
'foreignKey' => 'charge_entry_id',
'associationForeignKey' => 'payment_entry_id',
),
// The Charges that match THIS Payment (if it is one) // The Charges that match THIS Payment (if it is one)
'Charge' => array( 'Charge' => array(
'className' => 'Entry', 'className' => 'Entry',
@@ -26,23 +17,41 @@ class Entry extends AppModel {
'associationForeignKey' => 'charge_entry_id', 'associationForeignKey' => 'charge_entry_id',
), ),
// The Debits of this same account matching THIS Credit (if it is one) // The Payments that match THIS Charge (if it is one)
'Debit' => array( 'Payment' => array(
'className' => 'Entry', 'className' => 'Entry',
'joinTable' => 'reconciliations', 'joinTable' => 'charges_payments',
'linkalias' => 'AppliedDebit', 'linkalias' => 'AppliedPayment',
'foreignKey' => 'credit_entry_id', 'foreignKey' => 'charge_entry_id',
'associationForeignKey' => 'debit_entry_id', 'associationForeignKey' => 'payment_entry_id',
), ),
// The Credits of this same account matching THIS Debit (if it is one) /* // The Deposits that match THIS Payment (if it is one) */
'Credit' => array( /* 'Deposit' => array( */
'className' => 'Entry', /* 'className' => 'Entry', */
'joinTable' => 'reconciliations', /* 'joinTable' => 'deposits_payments', */
'linkalias' => 'AppliedCredit', /* 'linkalias' => 'AppliedDeposit', */
'foreignKey' => 'debit_entry_id', /* 'foreignKey' => 'payment_entry_id', */
'associationForeignKey' => 'credit_entry_id', /* 'associationForeignKey' => 'deposit_entry_id', */
), /* ), */
/* // The Debits of this same account matching THIS Credit (if it is one) */
/* 'Debit' => array( */
/* 'className' => 'Entry', */
/* 'joinTable' => 'reconciliations', */
/* 'linkalias' => 'AppliedDebit', */
/* 'foreignKey' => 'credit_entry_id', */
/* 'associationForeignKey' => 'debit_entry_id', */
/* ), */
/* // The Credits of this same account matching THIS Debit (if it is one) */
/* 'Credit' => array( */
/* 'className' => 'Entry', */
/* 'joinTable' => 'reconciliations', */
/* 'linkalias' => 'AppliedCredit', */
/* 'foreignKey' => 'debit_entry_id', */
/* 'associationForeignKey' => 'credit_entry_id', */
/* ), */
/* // The Entries of this same account matching THIS Entry */ /* // The Entries of this same account matching THIS Entry */
/* 'REntry' => array( */ /* 'REntry' => array( */
@@ -61,6 +70,38 @@ class Entry extends AppModel {
); );
/**************************************************************************
**************************************************************************
**************************************************************************
* function: chargePaymentFields
*/
function chargePaymentFields($sum = false, $entry_name = 'Entry', $double_name = 'DoubleEntry') {
$fields = array
(
($sum ? 'SUM(' : '') .
"IF({$entry_name}.type = 'CHARGE'," .
" {$double_name}.amount, NULL)" .
($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') .
"IF({$entry_name}.type = 'PAYMENT'," .
" {$double_name}.amount, NULL)" .
($sum ? ')' : '') . ' AS payment' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') .
"IF({$entry_name}.type = 'CHARGE', 1, -1)" .
" * IF({$double_name}.amount, {$double_name}.amount, 0)" .
($sum ? ')' : '') . ' AS balance',
);
if ($sum)
$fields[] = "COUNT({$entry_name}.id) AS entries";
return $fields;
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -134,40 +175,6 @@ class Entry extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* 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 (!isset($cond))
$cond = array();
$fields = $this->ledgerContextFields($ledger_id, $account_type);
$cond[] = $this->ledgerContextConditions($ledger_id, $account_type);
$order = array('Transaction.stamp');
$entries = $this->find
('all',
array('link' => $link,
'fields' => $fields,
'conditions' => $cond,
'order' => $order,
));
return $entries;
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -282,94 +289,6 @@ OPTION 2
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reconcileConditions
* - Returns entries which reconcile, or match, the set of entries
* requested through the $cond argument.
*/
function reconcilingQuery($double_name = 'DoubleEntry', $sum = false) {
$applied = array();
foreach (array('Payment', 'Charge') AS $pc) {
$applied[$pc] = "COALESCE(Applied{$pc}.amount,0)";
if ($sum)
$applied[$pc] = "SUM({$applied[$pc]})";
}
return array
('fields' => array("IF(Entry.type = 'CHARGE'," .
" {$applied['Payment']}, {$applied['Charge']}) AS 'applied'",
"{$double_name}.amount - IF(Entry.type = 'CHARGE'," .
" {$applied['Payment']}, {$applied['Charge']}) AS 'balance'",
),
'conditions' => array(),
);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: matchingEntries
* - Returns entries which reconcile, or match, the set of entries
* requested through the $cond argument.
*/
function matchingEntries($cond, $group, $strip_rec = false, $strip_unrec = false) {
$rquery = $this->reconcilingQuery('DoubleEntry', $group);
$fields = array_merge(array('Entry.*'), $rquery['fields']);
$cond = array_merge($cond, $rquery['conditions']);
$reconciled = $this->find
('all', array
('link' => array('DoubleEntry', 'Account',
'Charge' => array('fields' => array('Charge.*', 'AppliedCharge.*')),
'Payment' => array('fields' => array('Payment.*', 'AppliedPayment.*')),
),
'fields' => $fields,
'group' => $group,
'conditions' => $cond,
));
foreach ($reconciled AS $i => &$entry) {
$entry['Entry'] += $entry[0];
unset($entry[0]);
// Since HAVING isn't a builtin feature of CakePHP,
// we'll have to post-process to get the desired entries
if ($entry['Entry']['balance'] == 0) {
if ($strip_rec)
unset($reconciled[$i]);
}
else {
if ($strip_unrec)
unset($reconciled[$i]);
}
}
//pr(compact('reconciled'));
return $reconciled;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reconciledEntries
* - Returns the list of entries that have been reconciled (if $rec),
* or not fully reconciled (if $rec is false), along with the amount
* that has already been applied towards the entry as well as the
* remaining balance.
*/
function reconciledEntries1($id, $rec = true, $cond = null) {
$cond[] = array('Entry.id' => $id);
//return $this->matchingEntries($cond, array('Entry.id'), !$rec, $rec);
return $this->matchingEntries($cond, array('Entry.id'), false, false);
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -377,46 +296,36 @@ OPTION 2
* - Returns the set of entries satisfying the given conditions, * - Returns the set of entries satisfying the given conditions,
* along with any entries that they reconcile * along with any entries that they reconcile
*/ */
function reconciledSetQuery($set, $query) {
function reconciledSet($set, $cond = null, $link = null, $unrec = false) { $this->queryInit($query);
if (!isset($cond))
$cond = array();
if (!isset($link))
$link = array();
if ($set == 'CHARGE' || $set == 'PAYMENT') if ($set == 'CHARGE' || $set == 'PAYMENT')
$cond[] = array('Entry.type' => $set); $query['conditions'][] = array('Entry.type' => $set);
elseif ($set == 'DEBIT' || $set == 'CREDIT') elseif ($set == 'DEBIT' || $set == 'CREDIT')
$cond[] = array('Entry.crdr' => $set); $query['conditions'][] = array('Entry.crdr' => $set);
else else
die("INVALID RECONCILE SET"); die("INVALID RECONCILE SET");
$link['DoubleEntry'] += array(); if (!isset($query['link']['DoubleEntry']))
/* if ($set == 'CHARGE') */ $query['link']['DoubleEntry'] = array();
/* $link['Payment'] = array('fields' => array("SUM(ChargesPayment.amount) AS applied")); */
/* if ($set == 'PAYMENT') */
/* $link['Charge'] = array('fields' => array("SUM(ChargesPayment.amount) AS applied")); */
/* if ($set == 'DEBIT') */
/* $link['Credit'] = array('fields' => array("SUM(Reconciliation.amount) AS applied")); */
/* if ($set == 'CREDIT') */
/* $link['Debit'] = array('fields' => array("SUM(Reconciliation.amount) AS applied")); */
if ($set == 'CHARGE') if ($set == 'CHARGE')
$link['Payment'] = array('fields' => array("SUM(AppliedPayment.amount) AS applied")); $query['link']['Payment'] = array('fields' => array("SUM(AppliedPayment.amount) AS reconciled"));
if ($set == 'PAYMENT') if ($set == 'PAYMENT')
$link['Charge'] = array('fields' => array("SUM(AppliedCharge.amount) AS applied")); $query['link']['Charge'] = array('fields' => array("SUM(AppliedCharge.amount) AS reconciled"));
if ($set == 'DEBIT') /* if ($set == 'DEBIT') */
$link['Credit'] = array('fields' => array("SUM(AppliedCredit.amount) AS applied")); /* $query['link']['Credit'] = array('fields' => array("SUM(AppliedCredit.amount) AS reconciled")); */
if ($set == 'CREDIT') /* if ($set == 'CREDIT') */
$link['Debit'] = array('fields' => array("SUM(AppliedDebit.amount) AS applied")); /* $query['link']['Debit'] = array('fields' => array("SUM(AppliedDebit.amount) AS reconciled")); */
$result = $this->find $query['group'] = 'Entry.id';
('all', array return $query;
( }
'link' => $link,
'conditions' => $cond, function reconciledSet($set, $query = null, $unrec = false) {
'group' => 'Entry.id', $lquery = $this->reconciledSetQuery($set, $query);
)); $result = $this->find('all', $lquery);
pr(array('reconciledSet', compact('set', 'cond', 'link', 'result')));
//pr(array('reconciledSet', compact('set', 'lquery', 'result')));
$resultset = array(); $resultset = array();
foreach ($result AS $i => $entry) { foreach ($result AS $i => $entry) {
@@ -424,7 +333,7 @@ OPTION 2
unset($entry[0]); unset($entry[0]);
$entry['DoubleEntry']['balance'] = $entry['DoubleEntry']['balance'] =
$entry['DoubleEntry']['amount'] - $entry['DoubleEntry']['applied']; $entry['DoubleEntry']['amount'] - $entry['DoubleEntry']['reconciled'];
// Since HAVING isn't a builtin feature of CakePHP, // Since HAVING isn't a builtin feature of CakePHP,
// we'll have to post-process to get the desired entries // we'll have to post-process to get the desired entries
@@ -438,9 +347,10 @@ OPTION 2
} }
} }
//$result['stats'] = $this->stats(null, $cond); //$resultset['stats'] = $this->stats(null, $query);
pr($this->stats(null, $cond, $link)); //pr($this->stats(null, $query));
return $resultset; return array('entries' => $resultset,
'summary' => $this->stats(null, $query, $set));
} }
@@ -451,93 +361,36 @@ OPTION 2
* - Returns a list of entries that reconcile against the given entry. * - Returns a list of entries that reconcile against the given entry.
* (such as payments towards a charge). * (such as payments towards a charge).
*/ */
function reconciledEntriesQuery($id, $query = null) {
function reconciledEntries($id, $cond = null, $link = null) { $this->queryInit($query, false);
if (!isset($cond))
$cond = array();
if (!isset($link))
$link = array();
$cond[] = array('Entry.id' => $id);
$entry = $this->find('first', array('conditions' => array('Entry.id' => $id), $entry = $this->find('first', array('conditions' => array('Entry.id' => $id),
'recursive' => -1)); 'recursive' => -1));
$entry = $entry['Entry']; $entry = $entry['Entry'];
$contain = array(); $query['conditions'][] = array('Entry.id' => $id);
if ($entry['type'] == 'CHARGE') if ($entry['type'] == 'CHARGE')
$contain['Payment'] = array('fields' => array('Payment.*', 'ChargesPayment.amount')); $query['contain']['Payment'] = array('fields' => array('Payment.*', 'ChargesPayment.amount'));
if ($entry['type'] == 'PAYMENT') if ($entry['type'] == 'PAYMENT')
$contain['Charge'] = array('fields' => array('Charge.*', 'ChargesPayment.amount')); $query['contain']['Charge'] = array('fields' => array('Charge.*', 'ChargesPayment.amount'));
if ($entry['crdr'] == 'DEBIT') /* if ($entry['crdr'] == 'DEBIT') */
$contain['Credit'] = array('fields' => array('Credit.*', 'Reconciliation.amount')); /* $query['contain']['Credit'] = array('fields' => array('Credit.*', 'Reconciliation.amount')); */
if ($entry['crdr'] == 'CREDIT') /* if ($entry['crdr'] == 'CREDIT') */
$contain['Debit'] = array('fields' => array('Debit.*', 'Reconciliation.amount')); /* $query['contain']['Debit'] = array('fields' => array('Debit.*', 'Reconciliation.amount')); */
return $query;
}
function reconciledEntries($id, $query = null) {
$lquery = $this->reconciledEntriesQuery($id, $query);
//pr(array('reconciledEntries', compact('entry', 'contain'))); //pr(array('reconciledEntries', compact('entry', 'contain')));
$result = array(); $result = $this->find('first', $lquery);
$result['entries'] = $this->find unset($result['Entry']);
('first', array
(
'contain' => $contain,
/* 'zcontain' => array(//'DoubleEntry' => array('fields' => array('amount')), */ return array('entries' => $result,
/* 'REntry' => array('fields' => array('Reconciliation.amount'), */ 'summary' => $this->stats($id, $query));
/* 'DoubleEntry'), */
/* ), */
/* 'zlink' => array(//'DoubleEntry' => array('fields' => array('amount')), */
/* 'REntry' => array('fields' => array('REntry.*', 'Reconciliation.amount'), */
/* 'DoubleEntry'), */
/* ), */
/* 'zlink' => array(//'DoubleEntry' => array('fields' => array('amount')), */
/* 'Debit' => array('fields' => array('AppliedDebit.amount'), */
/* 'DoubleEntry' => array('alias' => 'DebitDoubleEntry')), */
/* 'Credit' => array('fields' => array('AppliedCredit.amount'), */
/* 'DoubleEntry' => array('alias' => 'CreditDoubleEntry')), */
/* ), */
'fields' => array('id'),
'conditions' => $cond,
));
unset($result['entries']['Entry']);
$result['stats'] = $this->stats($id);
return $result;
/* $balance = $this->find */
/* ('first', array */
/* ('link' => array */
/* ( */
/* "Charge" => array */
/* ('fields' => array("SUM(COALESCE(ChargesPayment.amount,0)) AS 'reconciling_charges'")), */
/* "Payment" => array */
/* ('fields' => array("SUM(COALESCE(ChargesPayment.amount,0)) AS 'reconciling_payments'")), */
/* ), */
/* 'fields' => array('Entry.amount'), */
/* 'group' => array('Entry.id'); */
/* 'conditions' => $cond, */
/* )); */
/* pr(compact('balance')); */
// pull up, since there should only be one
//$reconciling = $reconciling[0];
// Add the calculated fields to Entry
/* $reconciling['applied'] = 0; */
/* $reconciling['balance'] = $reconciling[0]['Entry']['amount']; */
/* foreach ($reconciling AS $i => $entry) { */
/* $reconciling['applied'] += $entry[0]['applied']; */
/* unset($reconciling[$i]['Entry']); */
/* } */
/* $reconciling['balance'] -= $reconciling['applied']; */
/* pr(compact('reconciling')); */
/* return $reconciling; */
} }
@@ -547,44 +400,48 @@ OPTION 2
* function: stats * function: stats
* - Returns summary data from the requested ledger entry * - Returns summary data from the requested ledger entry
*/ */
function stats($id = null, $cond = null, $link = null) { function stats($id = null, $query = null, $set = null) {
if (!isset($cond)) $this->queryInit($query);
$cond = array(); unset($query['group']);
if (!isset($link))
$link = array(); if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
/* if (!isset($query['link']['DoubleEntry']['fields'])) */
/* $query['link']['DoubleEntry']['fields'] = array(); */
if (isset($id)) if (isset($id))
$cond[] = array('Entry.id' => $id); $query['conditions'][] = array('Entry.id' => $id);
/* $entry = $this->find('first', array('contain' => array('DoubleEntry.amount'), */ if (isset($set))
/* 'fields' => array('Entry.type', 'Entry.crdr'), */ $set = strtoupper($set);
/* 'conditions' => array('Entry.id' => $id))); */
/* pr(compact('entry')); */ //pr(array('stats()', compact('id', 'query', 'set')));
/* $entry['Entry'] += $entry['DoubleEntry']; */
/* $entry = $entry['Entry']; */ $rtypes = array('charge', 'payment',
// 'debit', 'credit',
);
$stats = array(); $stats = array();
foreach(array('charge', 'payment', 'debit', 'credit') AS $rtype) { foreach($rtypes AS $rtype) {
$Rtype = ucfirst($rtype); $Rtype = ucfirst($rtype);
$rlink = $link; if (($rtype == 'charge' && (!isset($set) || $set == 'PAYMENT')) ||
$rlink[$Rtype] = array('fields' => array("SUM(Applied{$Rtype}.amount) AS applied")); ($rtype == 'payment' && (!isset($set) || $set == 'CHARGE'))
/* ($rtype == 'debit' && (!isset($set) || $set == 'CREDIT')) || */
/* ($rtype == 'credit' && (!isset($set) || $set == 'DEBIT')) */
) {
pr(array('stats()', compact('id', 'cond', 'link', 'rlink'))); $rquery = $query;
$rquery['link'][$Rtype] =
array('fields' => array("SUM(COALESCE(Applied{$Rtype}.amount,0)) AS reconciled"));
if (1 || ($rtype == 'charge' && $entry['type'] == 'PAYMENT') || $rquery['fields'] = array();
($rtype == 'payment' && $entry['type'] == 'CHARGE') || //$rquery['fields'][] = "SUM(DoubleEntry.amount) AS total";
($rtype == 'debit' && $entry['crdr'] == 'CREDIT') || $rquery['fields'][] = "SUM(DoubleEntry.amount) - SUM(COALESCE(Applied{$Rtype}.amount,0)) AS balance";
($rtype == 'credit' && $entry['crdr'] == 'DEBIT')) { $rquery['conditions'][] = array("Applied{$Rtype}.id !=" => null);
$result = $this->find
('first', array $result = $this->find('first', $rquery);
('link' => $rlink, //pr(compact('Rtype', 'rquery', 'result'));
'fields' => array("SUM(DoubleEntry.amount) AS total",
"SUM(DoubleEntry.amount) - SUM(Applied{$Rtype}.amount) AS unapplied"),
'conditions' => $cond,
//'group' => 'Entry.id',
));
pr(compact('Rtype', 'result'));
$sumfld = $Rtype; $sumfld = $Rtype;
$stats[$sumfld] = $result[0]; $stats[$sumfld] = $result[0];
@@ -593,68 +450,6 @@ OPTION 2
} }
} }
return $stats;
/* $result = $this->find */
/* ('first', array */
/* ('link' => array('DoubleEntry' => array('fields' => array('amount')), */
/* 'Credit' => array('fields' => array()), */
/* 'Debit' => array('fields' => array())), */
/* 'fields' => array('Entry.crdr', */
/* "SUM(AppliedDebit.amount) AS 'applied_debits'", */
/* "SUM(AppliedCredit.amount) AS 'applied_credits'"), */
/* 'conditions' => $cond, */
/* 'group' => 'Entry.id', */
/* )); */
//pr(compact('result'));
$stats = array();
if ($result['Entry']['crdr'] == 'DEBIT') {
if ($result[0]['applied_debits'])
die('INCONSISTENT DATABASE ENTRIES');
$stats['applied'] = $result[0]['applied_credits'];
}
elseif ($result['Entry']['crdr'] == 'CREDIT') {
if ($result[0]['applied_credits'])
die('INCONSISTENT DATABASE ENTRIES');
$stats['applied'] = $result[0]['applied_debits'];
}
if (!isset($stats['applied']))
$stats['applied'] = 0;
$stats['unapplied'] = $result['DoubleEntry']['amount'] - $stats['applied'];
/* $reconciled = $this->find */
/* ('all', array */
/* ('link' => array */
/* ( */
/* "Charge" => array */
/* ('fields' => array */
/* ('id', */
/* "COALESCE(SUM(ChargesPayment.amount),0) AS 'reconciled'", */
/* "Entry.amount - COALESCE(SUM(ChargesPayment.amount),0) AS 'balance'", */
/* ), */
/* ), */
/* "Payment" => array */
/* ('fields' => array */
/* ('id', */
/* "COALESCE(SUM(ChargesPayment.amount),0) AS 'reconciled'", */
/* "Entry.amount - COALESCE(SUM(ChargesPayment.amount),0) AS 'balance'", */
/* ), */
/* ), */
/* ), */
/* 'conditions' => array(isset($cond) ? $cond : array(), */
/* array('Entry.id' => $id)), */
/* 'group' => 'Entry.id', */
/* )); */
return $stats; return $stats;
} }

View File

@@ -16,66 +16,27 @@ class Lease extends AppModel {
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
* function: accountId * function: securityDeposits
* - Returns the accountId of the given lease
*/
function accountId($id) {
$A = new Account();
return $A->invoiceAccountID();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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'), */
/* )); */
if (!isset($cond))
$cond = array();
$cond[] = array('DoubleEntry.lease_id' => $id);
$A = new Account();
$entries = $A->findLedgerEntries($this->accountId($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 * - Returns an array of security deposit entries
*/ */
function findSecurityDeposits($id, $link = null) { function securityDeposits($id, $query = null) {
/* pr(array('function' => 'Lease::findSecurityDeposits', */ $this->queryInit($query);
/* 'args' => compact('id', 'link'), */
/* )); */
$A = new Account(); $this->id = $id;
$entries = $A->findLedgerEntries $this->recursive = -1;
($A->securityDepositAccountID(), $this->read();
true, array('DoubleEntry.lease_id' => $id), $link);
/* pr(array('function' => 'Lease::findSecurityDeposits', */ if (!isset($query['link']['DoubleEntry']))
/* 'args' => compact('id', 'link'), */ $query['link']['DoubleEntry'] = array();
/* 'vars' => compact('lease'), */ if (!isset($query['link']['DoubleEntry']['Lease']))
/* 'return' => compact('entries'), */ $query['link']['DoubleEntry']['Lease'] = array();
/* )); */ if (!isset($query['link']['DoubleEntry']['Lease']['fields']))
return $entries; $query['link']['DoubleEntry']['Lease']['fields'] = array();
$query['conditions'][] = array('Lease.id' => $id);
return $this->Customer->securityDeposits
($this->data['Lease']['customer_id'], $query);
} }
@@ -91,38 +52,40 @@ class Lease extends AppModel {
*/ */
function rentLastCharges($id) { function rentLastCharges($id) {
$A = new Account(); $rent_account_id = $this->DoubleEntry->Entry->Account->rentAccountID();
$entries = $this->find $entries = $this->find
('all', ('all',
array('link' => array('link' =>
array(// Models array(// Models
'DoubleEntry' => array 'DoubleEntry' =>
('Ledger' => array array('Entry'// =>
('fields' => array(), //array('fields'),
'Account' => array ),
('fields' => array(),
'Ledger' => array 'DEx' =>
('alias' => 'Lx', array('class' => 'DoubleEntry',
'fields' => array(),
'DoubleEntry' => array
('alias' => 'LEx',
'fields' => array(),
'conditions' => array 'conditions' => array
('LEx.effective_date = DATE_ADD(DoubleEntry.through_date, INTERVAL 1 day)', ('DEx.effective_date = DATE_ADD(Entry.through_date, INTERVAL 1 day)',
'LEx.lease_id = DoubleEntry.lease_id', 'DEx.lease_id = DoubleEntry.lease_id',
)
),
), ),
'Ex' =>
array('class' => 'Entry',
'type' => 'INNER',
'conditions' => array
('Ex.account_id = Entry.account_id',
'Ex.type = Entry.type',
'Ex.crdr = Entry.crdr'),
), ),
), ),
), ),
),
//'fields' => array('id', 'amount', 'effective_date', 'through_date'), //'fields' => array('id', 'amount', 'effective_date', 'through_date'),
'fields' => array(), 'fields' => array(),
'conditions' => array(array('Lease.id' => $id), 'conditions' => array(array('Lease.id' => $id),
array('Account.id' => $A->rentAccountID()), array('Entry.type' => 'CHARGE'),
array('LEx.id' => null), array('Entry.account_id' => $rent_account_id),
array('DEx.id' => null),
), ),
) )
); );
@@ -174,62 +137,76 @@ class Lease extends AppModel {
*/ */
function rentPaidThrough($id) { function rentPaidThrough($id) {
$rent_account_id = $this->DoubleEntry->Entry->Account->rentAccountID();
// Income / Receipt / Money $rent = $this->DoubleEntry->Entry->reconciledSet
// debit: A/R credit: Income <-- this entry ('CHARGE',
// debit: Receipt credit: A/R <-- ReceiptDoubleEntry, below array('fields' =>
// debit: Money credit: Receipt <-- MoneyDoubleEntry, below array('DATE_SUB(DoubleEntry.effective_date, INTERVAL 1 DAY) AS paid_through',
),
'conditions' =>
array(array('DoubleEntry.lease_id' => $id),
array('Entry.account_id' => $rent_account_id)),
$query = array 'order' => array('DoubleEntry.effective_date'),
('link' => array
(
'CreditLedger' =>
array('fields' => array(),
'Account' =>
array('fields' => array(),
),
), ),
true);
// We're searching for the Receipt<->A/R entries, /* $query = array */
// which are debits on the A/R account. Find the /* ('link' => */
// reconciling entries to that A/R debit. /* array(// Models */
'DebitReconciliationDoubleEntry' => /* 'DoubleEntry' => */
array('alias' => 'ReceiptDoubleEntry', /* array('Entry' => */
'fields' => array(), /* array(), */
/* 'fields' => array('SUM(COALESCE(MoneyDoubleEntryR.amount,0)) AS paid'), */
/* ), */
/* ), */
// Finally, the Money (Cash/Check/etc) Entry is the one /* // Finally, the Money (Cash/Check/etc) Entry is the one */
// which reconciles our ReceiptDoubleEntry debit /* // which reconciles our ReceiptDoubleEntry debit */
'DebitReconciliationDoubleEntry' => /* 'DebitReconciliationDoubleEntry' => */
array('alias' => 'MoneyDoubleEntry', /* array('alias' => 'MoneyDoubleEntry', */
'linkalias' => 'MoneyDoubleEntryR', /* 'linkalias' => 'MoneyDoubleEntryR', */
'fields' => array('SUM(COALESCE(MoneyDoubleEntryR.amount,0)) AS paid'), /* ), */
), /* ), */
), /* ), */
),
'fields' => array('DoubleEntry.amount', /* 'fields' => array('DoubleEntry.amount', */
'DATE_SUB(DoubleEntry.effective_date, INTERVAL 1 DAY) AS paid_through', /* 'DATE_SUB(DoubleEntry.effective_date, INTERVAL 1 DAY) AS paid_through', */
), /* ), */
'group' => 'DoubleEntry.id HAVING paid <> DoubleEntry.amount', /* 'group' => 'DoubleEntry.id HAVING paid <> DoubleEntry.amount', */
'conditions' => array(array('DoubleEntry.lease_id' => $id), /* 'conditions' => array(array('DoubleEntry.lease_id' => $id), */
array('Account.id' => $this->DoubleEntry->Ledger->Account->rentAccountID()), /* array('Account.id' => $this->DoubleEntry->Ledger->Account->rentAccountID()), */
), /* ), */
'order' => array('DoubleEntry.effective_date', /* 'order' => array('DoubleEntry.effective_date', */
), /* ), */
); /* ); */
$rent = $this->DoubleEntry->find('first', $query); /* $rent = $this->DoubleEntry->find('first', $query); */
//pr($rent);
if ($rent['entries'])
return $rent['entries'][0]['DoubleEntry']['paid_through'];
$rent = $this->DoubleEntry->Entry->reconciledSet
('CHARGE',
array('conditions' =>
array(array('DoubleEntry.lease_id' => $id),
array('Entry.account_id' => $rent_account_id)),
'order' => array('Entry.through_date DESC'),
),
false);
if ($rent) if ($rent)
return $rent[0]['paid_through']; return $rent[0]['Entry']['through_date'];
$query['fields'] = 'DoubleEntry.through_date'; /* $query['fields'] = 'Entry.through_date'; */
$query['order'] = 'DoubleEntry.through_date DESC'; /* $query['order'] = 'Entry.through_date DESC'; */
$query['group'] = 'DoubleEntry.id'; /* $query['group'] = 'DoubleEntry.id'; */
$rent = $this->DoubleEntry->find('first', $query); /* $rent = $this->DoubleEntry->find('first', $query); */
if ($rent) /* if ($rent) */
return $rent['DoubleEntry']['through_date']; /* return $rent['DoubleEntry']['through_date']; */
return null; return null;
} }
@@ -432,16 +409,60 @@ class Lease extends AppModel {
* - Returns summary data from the requested lease. * - Returns summary data from the requested lease.
*/ */
function stats($id = null) { function stats($id = null, $query = null) {
if (!$id) if (!$id)
return null; return null;
$A = new Account(); $this->queryInit($query);
$stats = $A->stats($A->accountReceivableAccountID(), true,
array('DoubleEntry.lease_id' => $id)); //$query['link'] = array('Lease' => $query['link']);
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
if (!isset($query['link']['Charge']))
$query['link']['Charge'] = array();
if (!isset($query['link']['Charge']['DoubleEntry']))
$query['link']['Charge']['DoubleEntry'] = array();
if (!isset($query['link']['Charge']['DoubleEntry']['Invoice']))
$query['link']['Charge']['DoubleEntry']['Invoice'] = array();
if (!isset($query['link']['Charge']['Account']))
$query['link']['Charge']['Account'] = array();
/* $query['link']['DoubleEntry']['fields'] = array(); */
/* $query['link']['Charge']['fields'] = array(); */
/* $query['link']['Charge']['Account']['fields'] = array(); */
/* $query['link']['Charge']['DoubleEntry']['fields'] = array(); */
/* $query['link']['Charge']['DoubleEntry']['Invoice']['fields'] = array(); */
$query['link']['Charge']['Account']['alias'] = 'ChargeAccount';
$query['link']['Charge']['DoubleEntry']['alias'] = 'ChargeDoubleEntry';
if (!isset($query['fields']))
$query['fields'] = array();
$query['fields'] = array_merge($query['fields'],
$this->DoubleEntry->Entry->chargePaymentFields(false));
$query['conditions'][] = array('OR' =>
array(array(array('Entry.type' => 'CHARGE'),
array('DoubleEntry.lease_id' => $id)),
array(array('Entry.type' => 'PAYMENT'),
array('ChargeDoubleEntry.lease_id' => $id)),
),
);
$query['group'] = null;
$stats = $this->DoubleEntry->Entry->find('all', $query);
pr(compact('query', 'stats'));
// The fields are all tucked into the [0] index,
// and the rest of the array is useless (empty).
$stats = $stats[0];
// Make sure we have a non-null balance
if (!isset($stats['balance']))
$stats['balance'] = 0;
// Pull to the top level and return
$stats = $stats['Ledger'];
return $stats; return $stats;
} }

View File

@@ -41,10 +41,11 @@ class Ledger extends AppModel {
function accountID($id) { function accountID($id) {
$this->cacheQueries = true; $this->cacheQueries = true;
$item = $this->find('first', array $item = $this->find('first', array
('contain' => 'Account.id', ('link' => array('Account'),
'conditions' => array('Ledger.id' => $id), 'conditions' => array('Ledger.id' => $id),
)); ));
$this->cacheQueries = false; $this->cacheQueries = false;
//pr(compact('id', 'item'));
return $item['Account']['id']; return $item['Account']['id'];
} }
@@ -120,29 +121,18 @@ class Ledger extends AppModel {
} }
function debitCreditFields($id, $sum = false, $entry_name = 'Entry', $double_name = 'DoubleEntry') { /**************************************************************************
$ftype = strtoupper($this->Account->fundamentalType($this->accountID($id))); **************************************************************************
**************************************************************************
$fields = array * function: debitCreditFields
( * - Returns the fields necessary to determine whether the queried
($sum ? 'SUM(' : '') . * entries are a debit, or a credit, and also the effect each have
"IF({$entry_name}.crdr = 'DEBIT', {$double_name}.amount, NULL)" . * on the overall balance of the ledger.
($sum ? ')' : '') . ' AS debit' . ($sum ? 's' : ''), */
function debitCreditFields($id, $sum = false,
($sum ? 'SUM(' : '') . $entry_name = 'Entry', $double_name = 'DoubleEntry') {
"IF({$entry_name}.crdr = 'CREDIT', {$double_name}.amount, NULL)" . return $this->Account->debitCreditFields
($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''), ($this->accountID($id), $sum, $entry_name, $double_name);
($sum ? 'SUM(' : '') .
"IF({$entry_name}.crdr = '$ftype', 1, -1) * {$double_name}.amount" .
// IF({$double_name}.amount, {$double_name}.amount, 0)" .
($sum ? ')' : '') . ' AS balance',
);
if ($sum)
$fields[] = "COUNT({$entry_name}.id) AS entries";
return $fields;
} }
/************************************************************************** /**************************************************************************
@@ -171,7 +161,7 @@ class Ledger extends AppModel {
'conditions' => array('Entry.ledger_id' => $ids), 'conditions' => array('Entry.ledger_id' => $ids),
)); ));
pr(compact('entries')); //pr(compact('entries'));
return $entries; return $entries;
} }
@@ -182,27 +172,43 @@ class Ledger extends AppModel {
* function: stats * function: stats
* - Returns summary data from the requested ledger. * - Returns summary data from the requested ledger.
*/ */
function stats($id, $cond = null) { function stats($id, $query = null) {
if (!isset($cond)) if (!$id)
$cond = array(); return null;
$cond[] = array('Ledger.id' => $id);
$stats = $this->find $this->queryInit($query);
('first', array
('link' => if (!isset($query['link']['Account']))
array(// Models $query['link']['Account'] = array();
'Account' => array('fields' => array()), if (!isset($query['link']['Account']['fields']))
'Entry' => array $query['link']['Account']['fields'] = array();
('DoubleEntry' => if (!isset($query['link']['Entry']))
array('fields' => array(), $query['link']['Entry'] = array();
'Transaction' => array('fields' => array('stamp')), if (!isset($query['link']['Entry']['DoubleEntry']))
), $query['link']['Entry']['DoubleEntry'] = array();
), if (!isset($query['link']['Entry']['DoubleEntry']['fields']))
), $query['link']['Entry']['DoubleEntry']['fields'] = array();
'fields' => $this->debitCreditFields($id, true), if (!isset($query['link']['Entry']['DoubleEntry']['Transaction']))
'conditions' => $cond, $query['link']['Entry']['DoubleEntry']['Transaction'] = array();
'group' => 'Ledger.id', if (!isset($query['link']['Entry']['DoubleEntry']['Transaction']['fields']))
)); $query['link']['Entry']['DoubleEntry']['Transaction']['fields'] = array();
$query['link']['Entry']['DoubleEntry']['Transaction']['fields'][] = 'stamp';
if (!isset($query['fields']))
$query['fields'] = array();
$query['fields'] = array_merge($query['fields'],
$this->debitCreditFields($id, true));
$query['conditions'][] = array('Ledger.id' => $id);
$query['group'][] = 'Ledger.id';
$stats = $this->find('first', $query);
unset($query['group']);
$query['fields'] = $this->debitCreditFields($id, false);
$stats = $this->find('all', $query);
pr(compact('query', 'stats'));
// The fields are all tucked into the [0] index, // The fields are all tucked into the [0] index,
// and the rest of the array is useless (empty). // and the rest of the array is useless (empty).

View File

@@ -66,11 +66,10 @@ echo $this->element('ledgers', array
* Current Ledger * Current Ledger
*/ */
echo $this->element('ledger_entries', array echo $this->element('entries', array
(// Element configuration (// Element configuration
'ledger_id' => $account['CurrentLedger']['id'], 'ledger_id' => $account['CurrentLedger']['id'],
'account_type' => $account['Account']['type'], 'account_type' => $account['Account']['type'],
'group_by_tx' => true,
// Grid configuration // Grid configuration
'config' => array 'config' => array

View File

@@ -62,7 +62,9 @@ echo $this->element('contacts', array
*/ */
echo $this->element('leases', array echo $this->element('leases', array
('config' => array ('no_customer' => true,
'config' => array
('caption' => 'Lease History', ('caption' => 'Lease History',
'rows' => $customer['Lease'], 'rows' => $customer['Lease'],
))); )));
@@ -72,10 +74,10 @@ echo $this->element('leases', array
* Customer Account History * Customer Account History
*/ */
echo $this->element('ledger_entries', array echo $this->element('entries', array
(// Element configuration (// Element configuration
'customer_id' => $customer['Customer']['id'], 'customer_id' => $customer['Customer']['id'],
'ar_account' => true, 'entry_type' => array('CHARGE', 'PAYMENT'),
// Grid configuration // Grid configuration
'config' => array 'config' => array

View File

@@ -63,7 +63,7 @@ if ($group_by_tx)
if (!isset($collected_account_id)) if (!isset($collected_account_id))
$grid->invalidFields('Last Payment'); $grid->invalidFields('Last Payment');
if (isset($account_ftype) || isset($ledger_id) || isset($account_id) || isset($ar_account)) if (isset($account_ftype) || isset($ledger_id) || isset($account_id) || isset($ar_account) || isset($customer_id))
$grid->invalidFields(array('Debit Account', 'Credit Account')); $grid->invalidFields(array('Debit Account', 'Credit Account'));
else else
$grid->invalidFields('Account'); $grid->invalidFields('Account');
@@ -71,7 +71,7 @@ else
if (isset($no_account) || $group_by_tx || isset($collected_account_id)) if (isset($no_account) || $group_by_tx || isset($collected_account_id))
$grid->invalidFields(array('Account', 'Debit Account', 'Credit Account')); $grid->invalidFields(array('Account', 'Debit Account', 'Credit Account'));
if (isset($ledger_id) || isset($account_id) || isset($ar_account)) { if (isset($ledger_id) || isset($account_id) || isset($ar_account) || isset($customer_id)) {
$grid->invalidFields('Amount'); $grid->invalidFields('Amount');
$cols['Sub-Total']['index'] = 'subtotal-balance'; $cols['Sub-Total']['index'] = 'subtotal-balance';
} else { } else {

View File

@@ -9,6 +9,8 @@ $cols['Date'] = array('index' => 'Transaction.stamp', 'formatter' =>
$cols['Effective'] = array('index' => 'DoubleEntry.effective_date', 'formatter' => 'date'); $cols['Effective'] = array('index' => 'DoubleEntry.effective_date', 'formatter' => 'date');
$cols['Through'] = array('index' => 'Entry.through_date', 'formatter' => 'date'); $cols['Through'] = array('index' => 'Entry.through_date', 'formatter' => 'date');
$cols['Debit Account'] = array('index' => 'DebitAccount.name', 'formatter' => 'name');
$cols['Credit Account'] = array('index' => 'CreditAccount.name', 'formatter' => 'name');
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name'); $cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name');
$cols['Cr/Dr'] = array('index' => 'Entry.crdr', 'formatter' => 'name'); $cols['Cr/Dr'] = array('index' => 'Entry.crdr', 'formatter' => 'name');
@@ -19,6 +21,8 @@ $cols['Unit'] = array('index' => 'Unit.name', 'formatter' =>
$cols['Source'] = array('index' => 'Entry.name', 'formatter' => 'name'); $cols['Source'] = array('index' => 'Entry.name', 'formatter' => 'name');
$cols['Comment'] = array('index' => 'Entry.comment', 'formatter' => 'comment', 'width'=>150); $cols['Comment'] = array('index' => 'Entry.comment', 'formatter' => 'comment', 'width'=>150);
$cols['Debit'] = array('index' => 'debit', 'formatter' => 'currency');
$cols['Credit'] = array('index' => 'credit', 'formatter' => 'currency');
$cols['Amount'] = array('index' => 'DoubleEntry.amount', 'formatter' => 'currency'); $cols['Amount'] = array('index' => 'DoubleEntry.amount', 'formatter' => 'currency');
$cols['Last Payment'] = array('index' => 'last_paid', 'formatter' => 'date'); $cols['Last Payment'] = array('index' => 'last_paid', 'formatter' => 'date');
@@ -26,49 +30,24 @@ $cols['Applied'] = array('index' => "applied", 'formatter' =>
$cols['Sub-Total'] = array('index' => 'subtotal-DoubleEntry.amount', 'formatter' => 'currency', 'sortable' => false); $cols['Sub-Total'] = array('index' => 'subtotal-DoubleEntry.amount', 'formatter' => 'currency', 'sortable' => false);
// Since group_by_tx is a boolean, let's just get it
// defined, regardless of whether the caller did so.
// group_by_tx will cause all entry fields to be
// invalidated, and will leave only the transaction
// fields. Yes... the caller should just use the
// transactions element instead, in theory. However,
// it hasn't yet been implemented to the level of
// this element, and additionally, the transactions
// element will not allow for customer information
// (rightly so, since it's a ledger_entry field).
// However, at the current implementation, all ledger
// entries of a transaction are for the same customer.
// So... we allow it for now.
if (!isset($group_by_tx))
$group_by_tx = false;
// REVISIT <AP>: 20090715
// If we really want to group by transaction, we need
// a transaction listing, not a ledger_entry listing.
// switch controllers... don't overload this one.
$group_by_tx = false;
if (isset($transaction_id) || isset($reconcile_id)) if (isset($transaction_id) || isset($reconcile_id))
$grid->invalidFields('Transaction'); $grid->invalidFields('Transaction');
if ($group_by_tx)
$grid->invalidFields('Entry');
if ($group_by_tx)
$grid->invalidFields(array('Effective', 'Through'));
if (!isset($collected_account_id)) if (!isset($collected_account_id))
$grid->invalidFields('Last Payment'); $grid->invalidFields('Last Payment');
if (isset($account_ftype) || isset($ledger_id) || isset($account_id) || isset($ar_account)) if (isset($account_ftype) || isset($ar_account) || isset($customer_id) || isset($lease_id))
$grid->invalidFields(array('Debit Account', 'Credit Account')); $grid->invalidFields(array('Debit Account', 'Credit Account'));
else else
$grid->invalidFields('Account'); $grid->invalidFields(array('Account', 'Cr/Dr'));
if (isset($no_account) || $group_by_tx || isset($collected_account_id)) if (isset($customer_id) || isset($lease_id))
$grid->invalidFields(array('Account', 'Debit Account', 'Credit Account')); $grid->invalidFields(array('Cr/Dr'));
if (isset($ledger_id) || isset($account_id) || isset($ar_account)) { if (isset($no_account) || isset($ledger_id) || isset($account_id) || isset($collected_account_id))
$grid->invalidFields(array('Account', 'Cr/Dr', 'Debit Account', 'Credit Account'));
if (isset($ledger_id) || isset($account_id) || isset($ar_account) || isset($customer_id) || isset($lease_id)) {
$grid->invalidFields('Amount'); $grid->invalidFields('Amount');
$cols['Sub-Total']['index'] = 'subtotal-balance'; $cols['Sub-Total']['index'] = 'subtotal-balance';
} else { } else {
@@ -76,12 +55,10 @@ if (isset($ledger_id) || isset($account_id) || isset($ar_account)) {
$cols['Sub-Total']['index'] = 'subtotal-DoubleEntry.amount'; $cols['Sub-Total']['index'] = 'subtotal-DoubleEntry.amount';
} }
// group_by_tx SHOULD wipe out Customer, but the reality
// is that it works good at the present, so we'll leave it.
if (isset($lease_id) || isset($customer_id)) if (isset($lease_id) || isset($customer_id))
$grid->invalidFields(array('Customer')); $grid->invalidFields(array('Customer'));
if (isset($lease_id) || $group_by_tx) if (isset($lease_id))
$grid->invalidFields(array('Lease', 'Unit')); $grid->invalidFields(array('Lease', 'Unit'));
if (!isset($reconcile_id) && !isset($collected_account_id)) if (!isset($reconcile_id) && !isset($collected_account_id))
@@ -127,17 +104,18 @@ if (isset($searchfields))
$grid->searchFields(array('Customer', 'Unit')); $grid->searchFields(array('Customer', 'Unit'));
// Include custom data // Include custom data
$grid->customData(compact('ledger_id', 'account_id', 'ar_account', $grid->customData(compact('ledger_id', 'account_id', 'ar_account', 'entry_type',
'account_type', 'account_ftype', 'monetary_source_id', 'account_type', 'account_ftype', 'monetary_source_id',
'customer_id', 'lease_id', 'transaction_id', 'group_by_tx')); 'customer_id', 'lease_id', 'transaction_id'));
// Render the grid // Render the grid
$grid $grid
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array('Transaction', 'Entry', 'Date', 'Effective', 'Last Payment', array('Transaction', 'Entry', 'Date', 'Effective', 'Last Payment',
'Account', 'Cr/Dr', 'Debit Account', 'Credit Account', 'Account', 'Cr/Dr',
'Customer', 'Unit', 'Customer', 'Unit',
'Comment', 'Comment',
'Amount', 'Debit', 'Credit', 'Amount',
'Applied', 'Sub-Total') 'Applied', 'Sub-Total')
); );

View File

@@ -18,6 +18,9 @@ $cols['Comment'] = array('index' => 'Lease.comment', 'formatter' => 'com
if (isset($searchfields)) if (isset($searchfields))
$grid->searchFields(array('Customer', 'Unit')); $grid->searchFields(array('Customer', 'Unit'));
if (isset($no_customer))
$grid->invalidFields('Customer');
// Render the grid // Render the grid
$grid $grid
->columns($cols) ->columns($cols)

View File

@@ -52,6 +52,7 @@ $rows[] = array('Transaction', $html->link('#'.$transaction['id'],
$rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp'])); $rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp']));
$rows[] = array('Effective', FormatHelper::date($double['effective_date'])); $rows[] = array('Effective', FormatHelper::date($double['effective_date']));
$rows[] = array('Through', FormatHelper::date($entry['through_date'])); $rows[] = array('Through', FormatHelper::date($entry['through_date']));
$rows[] = array('Amount', FormatHelper::currency($double['amount']));
$rows[] = array('Account', $html->link($account['name'], $rows[] = array('Account', $html->link($account['name'],
array('controller' => 'accounts', array('controller' => 'accounts',
'action' => 'view', 'action' => 'view',
@@ -94,25 +95,24 @@ echo $this->element('table',
echo '<div class="infobox">' . "\n"; echo '<div class="infobox">' . "\n";
$applied_caption = "Transfers applied"; //pr($reconciled);
$remaining_caption = "Unapplied amount"; foreach ($reconciled['summary'] AS $Rtype => $stats) {
foreach ($reconciled['stats'] AS $Rtype => $stats) {
$rtype = strtolower($Rtype); $rtype = strtolower($Rtype);
$applied_caption = "Transfers applied"; $applied_caption = "Applied";
$remaining_caption = "Unapplied amount"; $remaining_caption = "Balance";
/* $applied_caption = $Rtype . 's Applied'; */ /* $applied_caption = $Rtype . 's Applied'; */
/* $remaining_caption = 'Remaining for ' . $Rtype . 's'; */ /* $remaining_caption = 'Remaining for ' . $Rtype . 's'; */
$rows = array(); $rows = array();
$rows[] = array($applied_caption, $rows[] = array($applied_caption,
'<SPAN id="'.$rtype.'-applied">' . '<SPAN id="'.$rtype.'-applied">' .
FormatHelper::currency($stats['applied']) . FormatHelper::currency($stats['reconciled']) .
'</SPAN>'); '</SPAN>');
$rows[] = array($remaining_caption, $rows[] = array($remaining_caption,
'<SPAN id="'.$rtype.'-unapplied">' . '<SPAN id="'.$rtype.'-unapplied">' .
FormatHelper::currency($stats['unapplied']) . FormatHelper::currency($stats['balance']) .
'</SPAN>'); '</SPAN>');
echo $this->element('table', echo $this->element('table',
@@ -148,6 +148,10 @@ foreach ($reconciled['entries'] AS $Rtype => $entries) {
echo $this->element('entries', array echo $this->element('entries', array
(// Element configuration (// Element configuration
'entry_ids' => $entries, 'entry_ids' => $entries,
/* 'action' => 'reconcile', */
/* 'entry_id' => $entry['id'], */
/* 'reconcile_types' => array($rtype), */
// 'reconcile_id' => $entry['id'],
// Grid configuration // Grid configuration
'config' => array 'config' => array

View File

@@ -79,10 +79,11 @@ echo '<div CLASS="detail supporting">' . "\n";
* Lease Account History * Lease Account History
*/ */
echo $this->element('ledger_entries', array echo $this->element('entries', array
(// Element configuration (// Element configuration
'lease_id' => $lease['id'], 'lease_id' => $lease['id'],
'ar_account' => true, //'charge_payment' => true,
//'entry_type' => array('CHARGE', 'PAYMENT'),
// Grid configuration // Grid configuration
'config' => array 'config' => array

View File

@@ -63,11 +63,10 @@ echo '<div CLASS="detail supporting">' . "\n";
* Ledger Entries * Ledger Entries
*/ */
echo $this->element('ledger_entries', array echo $this->element('entries', array
(// Element configuration (// Element configuration
'ledger_id' => $ledger['id'], 'ledger_id' => $ledger['id'],
'account_type' => $account['type'], 'account_type' => $account['type'],
'group_by_tx' => true,
// Grid configuration // Grid configuration
'config' => array 'config' => array