This rework is nowhere near complete, but there are certain things that are falling in place, and worth capturing. I started a branch for just this purpose of being able to check in intermediate work.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@352 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
@@ -1,13 +1,6 @@
|
||||
<?php
|
||||
class Account extends AppModel {
|
||||
|
||||
var $name = 'Account';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
'external_name' => array('notempty')
|
||||
);
|
||||
|
||||
var $hasOne = array(
|
||||
'CurrentLedger' => array(
|
||||
'className' => 'Ledger',
|
||||
@@ -327,25 +320,46 @@ class Account extends AppModel {
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: findLedgerEntries
|
||||
* function: ledgerEntries
|
||||
* - Returns an array of ledger entries that belong to the given
|
||||
* account, either just from the current ledger, or from all ledgers.
|
||||
*/
|
||||
function findLedgerEntries($id, $all = false, $cond = null, $link = null) {
|
||||
function ledgerEntries($id, $all = false, $cond = null, $link = null) {
|
||||
/* pr(array('function' => 'Account::findLedgerEntries', */
|
||||
/* 'args' => compact('id', 'all', 'cond', 'link'), */
|
||||
/* )); */
|
||||
|
||||
$entries = array();
|
||||
foreach ($this->ledgers($id, $all) AS $ledger_id) {
|
||||
$ledger_entries = $this->Ledger->findLedgerEntries
|
||||
($ledger_id, $this->type($id), $cond, $link);
|
||||
$entries = array_merge($entries, $ledger_entries);
|
||||
}
|
||||
/* $this->Entry->find */
|
||||
/* ('all', array */
|
||||
/* ('contain' => array(), */
|
||||
/* 'conditions' => array('Entry.account_id' => $id) */
|
||||
/* )); */
|
||||
|
||||
$stats = $this->stats($id, $all, $cond);
|
||||
$entries = array('Entries' => $entries,
|
||||
'summary' => $stats['Ledger']);
|
||||
$ledgers = $this->ledgers($id, $all);
|
||||
|
||||
/* $this->Ledger->DoubleEntry->find */
|
||||
/* ('all', array */
|
||||
/* ('contain' => array('Ledger'), */
|
||||
/* 'conditions' => array('OR' => */
|
||||
/* array('DoubleEntry.debit_ledger_id' => $ledgers), */
|
||||
/* array('DoubleEntry.credit_ledger_id' => $ledgers)), */
|
||||
/* 'fields' => */
|
||||
/* )); */
|
||||
|
||||
$entries = $this->Ledger->find
|
||||
('all', array
|
||||
('link' =>
|
||||
array('Account',
|
||||
'DoubleEntry' => array
|
||||
('fields' => $this->Ledger->DoubleEntry->debitCreditFields('DoubleEntry', 'Ledger', false)),
|
||||
),
|
||||
|
||||
'conditions' => array('Ledger.id' => $ledgers),
|
||||
));
|
||||
|
||||
/* $stats = $this->stats($id, $all, $cond); */
|
||||
/* $entries = array('Entries' => $entries, */
|
||||
/* 'summary' => $stats['Ledger']); */
|
||||
|
||||
/* pr(array('function' => 'Account::findLedgerEntries', */
|
||||
/* 'args' => compact('id', 'all', 'cond', 'link'), */
|
||||
@@ -379,7 +393,7 @@ class Account extends AppModel {
|
||||
foreach ($rel_ids AS $rel_id)
|
||||
$ledger_ids = array_merge($ledger_ids, $this->ledgers($rel_id));
|
||||
|
||||
array_push($cond, $this->Ledger->LedgerEntry->conditionEntryAsCreditOrDebit($ledger_ids));
|
||||
array_push($cond, $this->Ledger->DoubleEntry->conditionEntryAsCreditOrDebit($ledger_ids));
|
||||
$entries = $this->findLedgerEntries($id, $all, $cond, $link);
|
||||
|
||||
/* pr(array('function' => 'Account::findLedgerEntriesRelatedToAccount', */
|
||||
@@ -413,28 +427,28 @@ class Account extends AppModel {
|
||||
('link' => array
|
||||
('Ledger' => array
|
||||
('fields' => array(),
|
||||
"LedgerEntry" => array
|
||||
('class' => "{$ucfund}LedgerEntry",
|
||||
"DoubleEntry" => array
|
||||
('class' => "{$ucfund}DoubleEntry",
|
||||
'fields' => array('id', 'customer_id', 'lease_id', 'amount'),
|
||||
"ReconciliationLedgerEntry" => array
|
||||
('class' => "{$ucfund}ReconciliationLedgerEntry",
|
||||
"ReconciliationDoubleEntry" => array
|
||||
('class' => "{$ucfund}ReconciliationDoubleEntry",
|
||||
'fields' => array
|
||||
("COALESCE(SUM(Reconciliation.amount),0) AS 'reconciled'",
|
||||
"LedgerEntry.amount - COALESCE(SUM(Reconciliation.amount),0) AS 'balance'",
|
||||
"DoubleEntry.amount - COALESCE(SUM(Reconciliation.amount),0) AS 'balance'",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'group' => ("LedgerEntry.id" .
|
||||
" HAVING LedgerEntry.amount" .
|
||||
'group' => ("DoubleEntry.id" .
|
||||
" HAVING DoubleEntry.amount" .
|
||||
" <> COALESCE(SUM(Reconciliation.amount),0)"),
|
||||
'conditions' => $cond,
|
||||
'fields' => array(),
|
||||
));
|
||||
$balance = 0;
|
||||
foreach ($unreconciled[$fund]['entry'] AS &$entry) {
|
||||
$entry = array_merge(array_diff_key($entry["LedgerEntry"], array(0=>true)),
|
||||
$entry = array_merge(array_diff_key($entry["DoubleEntry"], array(0=>true)),
|
||||
$entry[0]);
|
||||
$balance += $entry['balance'];
|
||||
}
|
||||
@@ -448,7 +462,7 @@ class Account extends AppModel {
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reconcileNewLedgerEntry
|
||||
* function: amountWouldReconcile
|
||||
* - Returns which ledger entries a new credit/debit would
|
||||
* reconcile, and how much.
|
||||
*
|
||||
@@ -459,7 +473,7 @@ class Account extends AppModel {
|
||||
* whatever algorithm is simplest.
|
||||
*/
|
||||
|
||||
function reconcileNewLedgerEntry($id, $fundamental_type, $amount, $cond = null) {
|
||||
function amountWouldReconcile($id, $fundamental_type, $amount, $cond = null) {
|
||||
$ofund = $this->fundamentalOpposite($fundamental_type);
|
||||
$unreconciled = array($ofund => array('entry'=>array(), 'balance'=>0));
|
||||
$applied = 0;
|
||||
@@ -498,7 +512,78 @@ class Account extends AppModel {
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: postLedgerEntry
|
||||
* function: reconcileLedgerEntries
|
||||
* - 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 reconcileLedgerEntries($id, $cond = null) {
|
||||
$unreconciled = $this->findUnreconciledLedgerEntries($id, null, $cond);
|
||||
pr(compact('unreconciled'));
|
||||
|
||||
$entry = array();
|
||||
foreach (array('debit', 'credit') AS $dc)
|
||||
$entry[$dc] = array('balance' => 0);
|
||||
|
||||
while ($entry['debit'] && $entry['credit']) {
|
||||
|
||||
// If/When we've exhausted this/these entries, move the next
|
||||
foreach (array('debit', 'credit') AS $dc) {
|
||||
if ($entry[$dc]['balance'] <= 0) {
|
||||
$entry[$dc] =& current($unreconciled[$dc]['entry']);
|
||||
next($unreconciled[$dc]['entry']);
|
||||
$entry[$dc]['applied'] = 0;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, both entries are valid with a positive balance
|
||||
$apply = min($entry['debit']['balance'], $entry['credit']['balance']);
|
||||
|
||||
|
||||
// REVISIT <AP>: 20090716
|
||||
// NOT YET ENTERING THE RECONCILIATION SO THAT WE CAN TEST
|
||||
// MUST ADD THE RECONCILIATION ENTRY!!!!
|
||||
|
||||
foreach (array('debit', 'credit') AS $dc) {
|
||||
$entry[$dc]['applied'] += $apply;
|
||||
$entry[$dc]['reconciled'] += $apply;
|
||||
$entry[$dc]['balance'] -= $apply;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array('debit', 'credit') AS $dc) {
|
||||
$unreconciled[$dc]['applied'] = 0;
|
||||
//$unreconciled[$dc]['unapplied'] = 0;
|
||||
foreach ($unreconciled[$dc]['entry'] AS $i => $entry) {
|
||||
if (isset($entry[$dc]['applied']))
|
||||
$unreconciled[$dc]['applied'] += $entry[$dc]['applied'];
|
||||
else
|
||||
unset($unreconciled[$dc]['entry'][$i]);
|
||||
|
||||
//$unreconciled[$dc]['unapplied'] += $entry[$dc]['balance'];
|
||||
}
|
||||
$unreconciled[$dc]['balance'] -= $unreconciled[$dc]['applied'];
|
||||
}
|
||||
|
||||
$unreconciled['debit'] ['unapplied'] = $unreconciled['credit']['balance'];
|
||||
$unreconciled['credit']['unapplied'] = $unreconciled['debit'] ['balance'];
|
||||
pr(compact('unreconciled'));
|
||||
|
||||
return $unreconciled;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: postDoubleEntry
|
||||
* -
|
||||
* transaction_data
|
||||
* - transaction_id (optional... if set all else is ignored)
|
||||
@@ -513,7 +598,7 @@ class Account extends AppModel {
|
||||
* - name
|
||||
*/
|
||||
|
||||
function postLedgerEntry($transaction_data,
|
||||
function postDoubleEntry($transaction_data,
|
||||
$monetary_data,
|
||||
$entry_data,
|
||||
$reconcile = null) {
|
||||
@@ -566,7 +651,7 @@ class Account extends AppModel {
|
||||
// No distinguishing features of Cash, just
|
||||
// use the shared monetary source
|
||||
$monetary_data['monetary_source_id'] =
|
||||
$this->Ledger->LedgerEntry->MonetarySource->nameToID('Cash');
|
||||
$this->Ledger->DoubleEntry->MonetarySource->nameToID('Cash');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,7 +719,7 @@ class Account extends AppModel {
|
||||
|
||||
//pr(array('pre-save', compact('entry_data')));
|
||||
// Create it!
|
||||
$new_entry = new LedgerEntry();
|
||||
$new_entry = new DoubleEntry();
|
||||
$new_entry->create();
|
||||
if (!$new_entry->saveAll($entry_data, array('validate'=>false))) {
|
||||
return array('error' => true);
|
||||
@@ -664,9 +749,9 @@ class Account extends AppModel {
|
||||
|
||||
if ($reconcile_set === 'receipt') {
|
||||
$C = new Customer();
|
||||
$reconciled = $C->reconcileNewLedgerEntry($entry_data['customer_id'],
|
||||
$this->fundamentalOpposite($dc_type),
|
||||
$entry_data['amount']);
|
||||
$reconciled = $C->amountWouldReconcile($entry_data['customer_id'],
|
||||
$this->fundamentalOpposite($dc_type),
|
||||
$entry_data['amount']);
|
||||
|
||||
/* pr(array("reconcile receipt", */
|
||||
/* compact('reconciled', 'split_transaction', 'transaction_data'))); */
|
||||
@@ -689,7 +774,7 @@ class Account extends AppModel {
|
||||
|
||||
// Payment must debit the Receipt ledger, and credit the A/R ledger
|
||||
// debit: Receipt credit: A/R
|
||||
$ids = $this->postLedgerEntry
|
||||
$ids = $this->postDoubleEntry
|
||||
($split_transaction,
|
||||
null,
|
||||
array('debit_ledger_id' => $this->currentLedgerID($this->receiptAccountID()),
|
||||
@@ -698,9 +783,9 @@ class Account extends AppModel {
|
||||
'lease_id' => $rec['lease_id'],
|
||||
'customer_id' => $rec['customer_id'],
|
||||
),
|
||||
array('debit' => array(array('LedgerEntry' => array('id' => $new_entry->id,
|
||||
array('debit' => array(array('DoubleEntry' => array('id' => $new_entry->id,
|
||||
'amount' => $rec['applied']))),
|
||||
'credit' => array(array('LedgerEntry' => array('id' => $rec['id'],
|
||||
'credit' => array(array('DoubleEntry' => array('id' => $rec['id'],
|
||||
'amount' => $rec['applied']))))
|
||||
);
|
||||
// Keep using the same split transaction for all reconciled entries
|
||||
@@ -717,19 +802,19 @@ class Account extends AppModel {
|
||||
if (is_array($reconcile_set)) {
|
||||
//pr("reconcile_set is array");
|
||||
foreach ($reconcile_set AS $reconcile_entry) {
|
||||
if (!isset($reconcile_entry['LedgerEntry']['id']))
|
||||
if (!isset($reconcile_entry['DoubleEntry']['id']))
|
||||
continue;
|
||||
|
||||
$amount = $reconcile_entry['LedgerEntry']['amount'];
|
||||
$amount = $reconcile_entry['DoubleEntry']['amount'];
|
||||
if (!$amount)
|
||||
continue;
|
||||
|
||||
if ($dc_type == 'debit') {
|
||||
$debit_ledger_entry_id = $new_entry->id;
|
||||
$credit_ledger_entry_id = $reconcile_entry['LedgerEntry']['id'];
|
||||
$credit_ledger_entry_id = $reconcile_entry['DoubleEntry']['id'];
|
||||
}
|
||||
else {
|
||||
$debit_ledger_entry_id = $reconcile_entry['LedgerEntry']['id'];
|
||||
$debit_ledger_entry_id = $reconcile_entry['DoubleEntry']['id'];
|
||||
$credit_ledger_entry_id = $new_entry->id;
|
||||
}
|
||||
|
||||
@@ -749,9 +834,9 @@ class Account extends AppModel {
|
||||
|
||||
$ret = array
|
||||
('error' => $err,
|
||||
'id' => $new_entry->data['LedgerEntry']['id'],
|
||||
'transaction_id' => $new_entry->data['LedgerEntry']['transaction_id'],
|
||||
'monetary_source_id' => $new_entry->data['LedgerEntry']['monetary_source_id']);
|
||||
'id' => $new_entry->data['DoubleEntry']['id'],
|
||||
'transaction_id' => $new_entry->data['DoubleEntry']['transaction_id'],
|
||||
'monetary_source_id' => $new_entry->data['DoubleEntry']['monetary_source_id']);
|
||||
|
||||
if (isset($split_transaction['transaction_id']))
|
||||
$ret['split_transaction_id'] = $split_transaction['transaction_id'];
|
||||
@@ -783,7 +868,7 @@ class Account extends AppModel {
|
||||
if ($ledger['total'] == 0)
|
||||
continue;
|
||||
|
||||
$ids = $this->postLedgerEntry
|
||||
$ids = $this->postDoubleEntry
|
||||
($transaction,
|
||||
null,
|
||||
array('debit_account_id' => $deposit_account_id,
|
||||
@@ -795,7 +880,7 @@ class Account extends AppModel {
|
||||
//pr(compact('ids'));
|
||||
|
||||
if ($ids['error'])
|
||||
die("closeAndDeposit : postLedgerEntry returned error!");
|
||||
die("closeAndDeposit : postDoubleEntry returned error!");
|
||||
|
||||
$transaction = array_intersect_key($ids, array('transaction_id'=>1));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user