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:
259
site/models/double_entry.php
Normal file
259
site/models/double_entry.php
Normal file
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
class DoubleEntry extends AppModel {
|
||||
|
||||
var $name = 'DoubleEntry';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'transaction_id' => array('numeric'),
|
||||
'amount' => array('money')
|
||||
);
|
||||
|
||||
var $hasOne = array(
|
||||
'DebitEntry' => array(
|
||||
'className' => 'Entry',
|
||||
'conditions' => array('DebitEntry.crdr' => 'DEBIT'),
|
||||
),
|
||||
'CreditEntry' => array(
|
||||
'className' => 'Entry',
|
||||
'conditions' => array('CreditEntry.crdr' => 'CREDIT'),
|
||||
),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Entry',
|
||||
);
|
||||
|
||||
|
||||
var $belongsTo = array(
|
||||
'Transaction',
|
||||
'Invoice' => array(
|
||||
'className' => 'Transaction',
|
||||
'conditions' => array('Invoice.type' => 'INVOICE'),
|
||||
),
|
||||
'Receipt' => array(
|
||||
'className' => 'Transaction',
|
||||
'conditions' => array('Invoice.type' => 'RECEIPT'),
|
||||
),
|
||||
|
||||
|
||||
'Customer',
|
||||
'Lease',
|
||||
|
||||
'DebitLedger' => array(
|
||||
'className' => 'Ledger',
|
||||
'foreignKey' => 'debit_ledger_id',
|
||||
),
|
||||
'CreditLedger' => array(
|
||||
'className' => 'Ledger',
|
||||
'foreignKey' => 'credit_ledger_id',
|
||||
),
|
||||
|
||||
'Ledger' => array(
|
||||
'foreignKey' => false,
|
||||
// conditions will be used when JOINing tables
|
||||
// (such as find with LinkableBehavior)
|
||||
'conditions' => array('OR' =>
|
||||
array('%{MODEL_ALIAS}.debit_ledger_id = Ledger.id',
|
||||
'%{MODEL_ALIAS}.credit_ledger_id = Ledger.id')),
|
||||
|
||||
// finderQuery will be used when tables are put
|
||||
// together across several querys, not with JOIN.
|
||||
// (such as find with ContainableBehavior)
|
||||
'finderQuery' => 'NOT-IMPLEMENTED',
|
||||
|
||||
'counterQuery' => ''
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: conditionEntryAsCreditOrDebit
|
||||
* - returns the condition necessary to match a set of
|
||||
* Ledgers to all related LedgerEntries
|
||||
*/
|
||||
function conditionEntryAsCreditOrDebit($ledger_ids) {
|
||||
return array('OR' =>
|
||||
array(array('debit_ledger_id' => $ledger_ids),
|
||||
array('credit_ledger_id' => $ledger_ids)));
|
||||
}
|
||||
|
||||
|
||||
function debitCreditFields($double_name = 'DoubleEntry', $ledger_name = 'Ledger', $sum = true) {
|
||||
$fields = array
|
||||
(
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$double_name}.debit_ledger_id = {$ledger_name}.id,
|
||||
{$double_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS debit' . ($sum ? 's' : ''),
|
||||
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$double_name}.credit_ledger_id = {$ledger_name}.id,
|
||||
{$double_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''),
|
||||
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF(Account.type IN ('ASSET', 'EXPENSE'),
|
||||
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}.amount, {$double_name}.amount, 0)" .
|
||||
($sum ? ')' : '') . ' AS balance',
|
||||
);
|
||||
|
||||
if ($sum)
|
||||
$fields[] = "COUNT({$double_name}.id) AS entries";
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: ledgerContext query helpers
|
||||
* - Returns parameters necessary to generate a query which
|
||||
* puts ledger entries into the context of a ledger. Since
|
||||
* debit/credit depends on the account type, it is required
|
||||
* as an argument for each function to avoid having to
|
||||
* query the ledger/account to find it out.
|
||||
*/
|
||||
function ledgerContextFields($ledger_id = null, $account_type = null) {
|
||||
$fields = array('id', 'effective_date',
|
||||
'lease_id', 'customer_id', 'comment', 'amount');
|
||||
|
||||
if (isset($ledger_id)) {
|
||||
$fields[] = ("IF(DoubleEntry.debit_ledger_id = $ledger_id," .
|
||||
" DoubleEntry.amount, NULL) AS debit");
|
||||
$fields[] = ("IF(DoubleEntry.credit_ledger_id = $ledger_id," .
|
||||
" DoubleEntry.amount, NULL) AS credit");
|
||||
|
||||
if (isset($account_type)) {
|
||||
if (in_array($account_type, array('ASSET', 'EXPENSE')))
|
||||
$ledger_type = 'debit';
|
||||
else
|
||||
$ledger_type = 'credit';
|
||||
|
||||
$fields[] = ("(IF(DoubleEntry.{$ledger_type}_ledger_id = $ledger_id," .
|
||||
" 1, -1) * DoubleEntry.amount) AS balance");
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function ledgerContextFields2($ledger_id = null, $account_id = null, $account_type = null) {
|
||||
$fields = array('id', 'effective_date', 'comment', 'amount');
|
||||
|
||||
if (isset($ledger_id)) {
|
||||
$fields[] = ("IF(DoubleEntry.debit_ledger_id = $ledger_id," .
|
||||
" SUM(DoubleEntry.amount), NULL) AS debit");
|
||||
$fields[] = ("IF(DoubleEntry.credit_ledger_id = $ledger_id," .
|
||||
" SUM(DoubleEntry.amount), NULL) AS credit");
|
||||
|
||||
if (isset($account_id) || isset($account_type)) {
|
||||
$Account = new Account();
|
||||
$account_ftype = $Account->fundamentalType($account_id ? $account_id : $account_type);
|
||||
$fields[] = ("(IF(DoubleEntry.{$account_ftype}_ledger_id = $ledger_id," .
|
||||
" 1, -1) * SUM(DoubleEntry.amount)) AS balance");
|
||||
}
|
||||
}
|
||||
elseif (isset($account_id)) {
|
||||
$fields[] = ("IF(DebitLedger.account_id = $account_id," .
|
||||
" SUM(DoubleEntry.amount), NULL) AS debit");
|
||||
$fields[] = ("IF(CreditLedger.account_id = $account_id," .
|
||||
" SUM(DoubleEntry.amount), NULL) AS credit");
|
||||
|
||||
$Account = new Account();
|
||||
$account_ftype = ucfirst($Account->fundamentalType($account_id));
|
||||
$fields[] = ("(IF({$account_ftype}Ledger.account_id = $account_id," .
|
||||
" 1, -1) * SUM(DoubleEntry.amount)) AS balance");
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
function ledgerContextConditions($ledger_id, $account_type) {
|
||||
if (isset($ledger_id)) {
|
||||
return array
|
||||
('OR' =>
|
||||
array(array('DoubleEntry.debit_ledger_id' => $ledger_id),
|
||||
array('DoubleEntry.credit_ledger_id' => $ledger_id)),
|
||||
);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: findInLedgerContext
|
||||
* - Returns an array of ledger entries that belong to a given ledger.
|
||||
* There is extra logic to also figure out whether the double_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;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns summary data from the requested double entry
|
||||
*/
|
||||
function stats($id) {
|
||||
|
||||
/* $query = array */
|
||||
/* ( */
|
||||
/* 'fields' => array("SUM(Reconciliation.amount) AS 'reconciled'"), */
|
||||
|
||||
/* 'conditions' => array(isset($cond) ? $cond : array(), */
|
||||
/* array('DoubleEntry.id' => $id)), */
|
||||
|
||||
/* 'group' => 'DoubleEntry.id', */
|
||||
/* ); */
|
||||
|
||||
/* // Get the applied amounts on the debit side */
|
||||
/* $query['link'] = */
|
||||
/* array('DebitReconciliationDoubleEntry' => array('alias' => 'DRLE', 'DRLETransaction' => array('class' => 'Transaction'))); */
|
||||
/* $tmpstats = $this->find('first', $query); */
|
||||
/* $stats['debit_amount_reconciled'] = $tmpstats[0]['reconciled']; */
|
||||
|
||||
/* // Get the applied amounts on the credit side */
|
||||
/* $query['link'] = */
|
||||
/* array('CreditReconciliationDoubleEntry' => array('alias' => 'CRLE', 'CRLETransaction' => array('class' => 'Transaction'))); */
|
||||
/* $tmpstats = $this->find('first', $query); */
|
||||
/* $stats['credit_amount_reconciled'] = $tmpstats[0]['reconciled']; */
|
||||
|
||||
$stats['debit']['amount_reconciled'] = 0;
|
||||
$stats['credit']['amount_reconciled'] = 0;
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user