Files
pmgr/models/double_entry.php
2009-07-19 23:35:25 +00:00

260 lines
8.7 KiB
PHP

<?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;
}
}