Making progress. Much still to do, but there are hints of functionality finally returning so I'm snapshotting.

git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@360 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
abijah
2009-07-21 10:23:52 +00:00
parent fd856323a5
commit 93ebc450fe
26 changed files with 1164 additions and 985 deletions

View File

@@ -16,6 +16,7 @@ class Account extends AppModel {
var $hasMany = array(
'Ledger',
'LedgerEntry',
);
@@ -105,30 +106,10 @@ class Account extends AppModel {
* 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;
function debitCreditFields($sum = false, $entry_name = 'Entry', $account_name = 'Account') {
return $this->LedgerEntry->debitCreditFields
($sum, $entry_name, $account_name);
}
@@ -410,7 +391,7 @@ class Account extends AppModel {
$unreconciled = $this->unreconciledEntries($id, 'CHARGE', $cond, $link);
foreach ($unreconciled AS $i => &$item) {
$entry =& $item['DoubleEntry'];
$entry =& $item['LedgerEntry'];
// Determine if amount is sufficient to cover the entry
if ($amount > $entry['balance'])
$apply = $entry['balance'];
@@ -509,7 +490,7 @@ class Account extends AppModel {
/**************************************************************************
**************************************************************************
**************************************************************************
* function: postDoubleEntry
* function: postLedgerEntry
* -
* transaction_data
* - transaction_id (optional... if set all else is ignored)
@@ -524,7 +505,7 @@ class Account extends AppModel {
* - name
*/
function postDoubleEntry($transaction_data,
function postLedgerEntry($transaction_data,
$monetary_data,
$entry_data,
$reconcile = null) {
@@ -577,7 +558,7 @@ class Account extends AppModel {
// No distinguishing features of Cash, just
// use the shared monetary source
$monetary_data['monetary_source_id'] =
$this->Ledger->DoubleEntry->MonetarySource->nameToID('Cash');
$this->Ledger->LedgerEntry->MonetarySource->nameToID('Cash');
}
}
@@ -645,7 +626,7 @@ class Account extends AppModel {
//pr(array('pre-save', compact('entry_data')));
// Create it!
$new_entry = new DoubleEntry();
$new_entry = new LedgerEntry();
$new_entry->create();
if (!$new_entry->saveAll($entry_data, array('validate'=>false))) {
return array('error' => true);
@@ -700,7 +681,7 @@ class Account extends AppModel {
// Payment must debit the Receipt ledger, and credit the A/R ledger
// debit: Receipt credit: A/R
$ids = $this->postDoubleEntry
$ids = $this->postLedgerEntry
($split_transaction,
null,
array('debit_ledger_id' => $this->currentLedgerID($this->receiptAccountID()),
@@ -709,9 +690,9 @@ class Account extends AppModel {
'lease_id' => $rec['lease_id'],
'customer_id' => $rec['customer_id'],
),
array('debit' => array(array('DoubleEntry' => array('id' => $new_entry->id,
array('debit' => array(array('LedgerEntry' => array('id' => $new_entry->id,
'amount' => $rec['applied']))),
'credit' => array(array('DoubleEntry' => array('id' => $rec['id'],
'credit' => array(array('LedgerEntry' => array('id' => $rec['id'],
'amount' => $rec['applied']))))
);
// Keep using the same split transaction for all reconciled entries
@@ -728,19 +709,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['DoubleEntry']['id']))
if (!isset($reconcile_entry['LedgerEntry']['id']))
continue;
$amount = $reconcile_entry['DoubleEntry']['amount'];
$amount = $reconcile_entry['LedgerEntry']['amount'];
if (!$amount)
continue;
if ($dc_type == 'debit') {
$debit_ledger_entry_id = $new_entry->id;
$credit_ledger_entry_id = $reconcile_entry['DoubleEntry']['id'];
$credit_ledger_entry_id = $reconcile_entry['LedgerEntry']['id'];
}
else {
$debit_ledger_entry_id = $reconcile_entry['DoubleEntry']['id'];
$debit_ledger_entry_id = $reconcile_entry['LedgerEntry']['id'];
$credit_ledger_entry_id = $new_entry->id;
}
@@ -760,9 +741,9 @@ class Account extends AppModel {
$ret = array
('error' => $err,
'id' => $new_entry->data['DoubleEntry']['id'],
'transaction_id' => $new_entry->data['DoubleEntry']['transaction_id'],
'monetary_source_id' => $new_entry->data['DoubleEntry']['monetary_source_id']);
'id' => $new_entry->data['LedgerEntry']['id'],
'transaction_id' => $new_entry->data['LedgerEntry']['transaction_id'],
'monetary_source_id' => $new_entry->data['LedgerEntry']['monetary_source_id']);
if (isset($split_transaction['transaction_id']))
$ret['split_transaction_id'] = $split_transaction['transaction_id'];
@@ -794,7 +775,7 @@ class Account extends AppModel {
if ($ledger['total'] == 0)
continue;
$ids = $this->postDoubleEntry
$ids = $this->postLedgerEntry
($transaction,
null,
array('debit_account_id' => $deposit_account_id,
@@ -806,7 +787,7 @@ class Account extends AppModel {
//pr(compact('ids'));
if ($ids['error'])
die("closeAndDeposit : postDoubleEntry returned error!");
die("closeAndDeposit : postLedgerEntry returned error!");
$transaction = array_intersect_key($ids, array('transaction_id'=>1));

View File

@@ -1,261 +1,13 @@
<?php
class DoubleEntry extends AppModel {
var $name = 'DoubleEntry';
var $validate = array(
'id' => array('numeric'),
'transaction_id' => array('numeric'),
'amount' => array('money')
);
var $hasOne = array(
var $belongsTo = array(
'DebitEntry' => array(
'className' => 'Entry',
'conditions' => array('DebitEntry.crdr' => 'DEBIT'),
'className' => 'LedgerEntry',
),
'CreditEntry' => array(
'className' => 'Entry',
'conditions' => array('CreditEntry.crdr' => 'CREDIT'),
'className' => 'LedgerEntry',
),
);
var $hasMany = array(
'Entry',
);
var $belongsTo = array(
'Transaction',
'Invoice' => array(
'className' => 'Transaction',
'conditions' => array('Invoice.type' => 'INVOICE'),
'foreignKey' => 'transaction_id',
),
'Receipt' => array(
'className' => 'Transaction',
'conditions' => array('Invoice.type' => 'RECEIPT'),
'foreignKey' => 'transaction_id',
),
'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($sum = false, $double_name = 'DoubleEntry', $ledger_name = 'Ledger', $account_name = 'Account') {
$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_name}.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;
}
}

View File

@@ -9,7 +9,7 @@ class Lease extends AppModel {
);
var $hasMany = array(
'DoubleEntry',
'StatementEntry',
);
@@ -22,21 +22,19 @@ class Lease extends AppModel {
function securityDeposits($id, $query = null) {
$this->queryInit($query);
$this->id = $id;
$this->recursive = -1;
$this->read();
$A = new Account();
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
if (!isset($query['link']['DoubleEntry']['Lease']))
$query['link']['DoubleEntry']['Lease'] = array();
if (!isset($query['link']['DoubleEntry']['Lease']['fields']))
$query['link']['DoubleEntry']['Lease']['fields'] = array();
if (!isset($query['link']['Lease']))
$query['link']['Lease'] = array();
if (!isset($query['link']['Lease']['fields']))
$query['link']['Lease']['fields'] = array();
$query['conditions'][] = array('Lease.id' => $id);
$query['conditions'][] = array('StatementEntry.account_id' => $A->securityDepositAccountID());
return $this->Customer->securityDeposits
($this->data['Lease']['customer_id'], $query);
$set = $this->StatementEntry->reconciledSet('CHARGE', $query);
//pr(compact('set'));
return $set;
}
@@ -52,40 +50,28 @@ class Lease extends AppModel {
*/
function rentLastCharges($id) {
$rent_account_id = $this->DoubleEntry->Entry->Account->rentAccountID();
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
$entries = $this->find
('all',
array('link' =>
array(// Models
'DoubleEntry' =>
array('Entry'// =>
//array('fields'),
),
'StatementEntry' => array(),
'DEx' =>
array('class' => 'DoubleEntry',
'SEx' =>
array('class' => 'StatementEntry',
'conditions' => array
('DEx.effective_date = DATE_ADD(Entry.through_date, INTERVAL 1 day)',
'DEx.lease_id = DoubleEntry.lease_id',
('SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
'SEx.lease_id = StatementEntry.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(),
'conditions' => array(array('Lease.id' => $id),
array('Entry.type' => 'CHARGE'),
array('Entry.account_id' => $rent_account_id),
array('DEx.id' => null),
array('StatementEntry.type' => 'CHARGE'),
array('StatementEntry.account_id' => $rent_account_id),
array('SEx.id' => null),
),
)
);
@@ -125,7 +111,7 @@ class Lease extends AppModel {
return false;
if (count($entries) != 1)
return null;
return $entries[0]['DoubleEntry']['through_date'];
return $entries[0]['StatementEntry']['through_date'];
}
@@ -137,76 +123,77 @@ class Lease extends AppModel {
*/
function rentPaidThrough($id) {
$rent_account_id = $this->DoubleEntry->Entry->Account->rentAccountID();
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
$rent = $this->DoubleEntry->Entry->reconciledSet
$rent = $this->StatementEntry->reconciledSet
('CHARGE',
array('fields' =>
array('DATE_SUB(DoubleEntry.effective_date, INTERVAL 1 DAY) AS paid_through',
array('StatementEntry.*',
'DATE_SUB(StatementEntry.effective_date, INTERVAL 1 DAY) AS paid_through',
),
'conditions' =>
array(array('DoubleEntry.lease_id' => $id),
array('Entry.account_id' => $rent_account_id)),
array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id)),
'order' => array('DoubleEntry.effective_date'),
'order' => array('StatementEntry.effective_date'),
),
true);
/* $query = array */
/* ('link' => */
/* array(// Models */
/* 'DoubleEntry' => */
/* 'StatementEntry' => */
/* array('Entry' => */
/* array(), */
/* 'fields' => array('SUM(COALESCE(MoneyDoubleEntryR.amount,0)) AS paid'), */
/* 'fields' => array('SUM(COALESCE(MoneyStatementEntryR.amount,0)) AS paid'), */
/* ), */
/* ), */
/* // Finally, the Money (Cash/Check/etc) Entry is the one */
/* // which reconciles our ReceiptDoubleEntry debit */
/* 'DebitReconciliationDoubleEntry' => */
/* array('alias' => 'MoneyDoubleEntry', */
/* 'linkalias' => 'MoneyDoubleEntryR', */
/* // which reconciles our ReceiptStatementEntry debit */
/* 'DebitReconciliationStatementEntry' => */
/* array('alias' => 'MoneyStatementEntry', */
/* 'linkalias' => 'MoneyStatementEntryR', */
/* ), */
/* ), */
/* ), */
/* 'fields' => array('DoubleEntry.amount', */
/* 'DATE_SUB(DoubleEntry.effective_date, INTERVAL 1 DAY) AS paid_through', */
/* 'fields' => array('StatementEntry.amount', */
/* 'DATE_SUB(StatementEntry.effective_date, INTERVAL 1 DAY) AS paid_through', */
/* ), */
/* 'group' => 'DoubleEntry.id HAVING paid <> DoubleEntry.amount', */
/* 'group' => 'StatementEntry.id HAVING paid <> StatementEntry.amount', */
/* 'conditions' => array(array('DoubleEntry.lease_id' => $id), */
/* array('Account.id' => $this->DoubleEntry->Ledger->Account->rentAccountID()), */
/* 'conditions' => array(array('StatementEntry.lease_id' => $id), */
/* array('Account.id' => $this->StatementEntry->Ledger->Account->rentAccountID()), */
/* ), */
/* 'order' => array('DoubleEntry.effective_date', */
/* 'order' => array('StatementEntry.effective_date', */
/* ), */
/* ); */
/* $rent = $this->DoubleEntry->find('first', $query); */
/* $rent = $this->StatementEntry->find('first', $query); */
//pr($rent);
if ($rent['entries'])
return $rent['entries'][0]['DoubleEntry']['paid_through'];
return $rent['entries'][0]['StatementEntry']['paid_through'];
$rent = $this->DoubleEntry->Entry->reconciledSet
$rent = $this->StatementEntry->reconciledSet
('CHARGE',
array('conditions' =>
array(array('DoubleEntry.lease_id' => $id),
array('Entry.account_id' => $rent_account_id)),
array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id)),
'order' => array('Entry.through_date DESC'),
),
false);
if ($rent)
return $rent[0]['Entry']['through_date'];
return $rent[0]['StatementEntry']['through_date'];
/* $query['fields'] = 'Entry.through_date'; */
/* $query['order'] = 'Entry.through_date DESC'; */
/* $query['group'] = 'DoubleEntry.id'; */
/* $rent = $this->DoubleEntry->find('first', $query); */
/* $query['group'] = 'StatementEntry.id'; */
/* $rent = $this->StatementEntry->find('first', $query); */
/* if ($rent) */
/* return $rent['DoubleEntry']['through_date']; */
/* return $rent['StatementEntry']['through_date']; */
return null;
}
@@ -416,43 +403,28 @@ class Lease extends AppModel {
$this->queryInit($query);
//$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();
/* if (!isset($query['link']['StatementEntry'])) */
/* $query['link']['StatementEntry'] = array(); */
/* if (!isset($query['link']['StatementEntry']['ChargeEntry'])) */
/* $query['link']['StatementEntry']['ChargeEntry'] = 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';
/* $query['link']['StatementEntry']['fields'] = array(); */
/* $query['link']['ChargeEntry']['fields'] = array(); */
/* $query['link']['ChargeEntry']['Account']['fields'] = array(); */
/* $query['link']['ChargeEntry']['StatementEntry']['fields'] = array(); */
/* $query['link']['ChargeEntry']['StatementEntry']['Invoice']['fields'] = array(); */
if (!isset($query['fields']))
$query['fields'] = array();
$query['fields'] = array_merge($query['fields'],
$this->DoubleEntry->Entry->chargePaymentFields(false));
$this->StatementEntry->chargePaymentFields(true));
$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['conditions'][] = array('StatementEntry.lease_id' => $id);
$query['group'] = null;
$stats = $this->DoubleEntry->Entry->find('all', $query);
$stats = $this->StatementEntry->find('first', $query);
pr(compact('query', 'stats'));
// The fields are all tucked into the [0] index,

View File

@@ -8,27 +8,8 @@ class Ledger extends AppModel {
);
var $hasMany = array(
'Entry',
'DoubleEntry' => array(
'foreignKey' => false,
// conditions will be used when JOINing tables
// (such as find with LinkableBehavior)
'conditions' => array('OR' =>
array('DoubleEntry.debit_ledger_id = %{MODEL_ALIAS}.id',
'DoubleEntry.credit_ledger_id = %{MODEL_ALIAS}.id')),
// finderQuery will be used when tables are put
// together across several querys, not with JOIN.
// (such as find with ContainableBehavior)
'finderQuery' => 'SELECT `DoubleEntry`.*
FROM pmgr_double_entries AS `DoubleEntry`
WHERE DoubleEntry.debit_ledger_id = ({$__cakeID__$})
OR DoubleEntry.credit_ledger_id = ({$__cakeID__$})',
'counterQuery' => ''
),
'Transaction',
'LedgerEntry',
);
@@ -111,7 +92,7 @@ class Ledger extends AppModel {
'comment' => "Ledger Balance Forward",
);
$carry_entry = new DoubleEntry();
$carry_entry = new LedgerEntry();
$carry_entry->create();
if (!$carry_entry->save($carry_entry_data, false)) {
return null;
@@ -129,10 +110,9 @@ class Ledger extends AppModel {
* entries are a debit, or a credit, and also the effect each have
* on the overall balance of the ledger.
*/
function debitCreditFields($id, $sum = false,
$entry_name = 'Entry', $double_name = 'DoubleEntry') {
return $this->Account->debitCreditFields
($this->accountID($id), $sum, $entry_name, $double_name);
function debitCreditFields($sum = false, $entry_name = 'Entry', $account_name = 'Account') {
return $this->LedgerEntry->debitCreditFields
($sum, $entry_name, $account_name);
}
/**************************************************************************
@@ -142,23 +122,16 @@ class Ledger extends AppModel {
* - Returns an array of ledger entries that belong to a given
* ledger. There is extra work done to establish debit/credit
*/
function ledgerEntries($ids, $cond = null, $link = null) {
function ledgerEntries($ids, $query = null) {
if (empty($ids))
return null;
/* $id = (is_array($ids) ? $ids[0] : $ids); */
/* $ftype = strtoupper($this->Account->fundamentalType($this->accountID($id))); */
$entries = $this->Entry->find
$entries = $this->LedgerEntry->find
('all', array
('contain' => array('DoubleEntry' => array('fields' => array('amount'))),
'fields' => array_merge(array("Entry.*"),
$this->debitCreditFields(is_array($ids) ? $ids[0] : $ids)),
/* "IF(Entry.crdr = 'CREDIT', DoubleEntry.amount, NULL) AS credit", */
/* "IF(Entry.crdr = 'DEBIT', DoubleEntry.amount, NULL) AS debit", */
/* "IF(Entry.crdr = '$ftype', 1, -1) * DoubleEntry.amount AS balance", */
'conditions' => array('Entry.ledger_id' => $ids),
('contain' => array('Ledger' => array('Account')),
'fields' => array_merge(array("LedgerEntry.*"),
$this->LedgerEntry->debitCreditFields()),
'conditions' => array('LedgerEntry.ledger_id' => $ids),
));
//pr(compact('entries'));
@@ -178,37 +151,37 @@ class Ledger extends AppModel {
$this->queryInit($query);
if (!isset($query['link']['Account']))
$query['link']['Account'] = array();
if (!isset($query['link']['Account']['fields']))
$query['link']['Account']['fields'] = array();
if (!isset($query['link']['Entry']))
$query['link']['Entry'] = array();
if (!isset($query['link']['Entry']['DoubleEntry']))
$query['link']['Entry']['DoubleEntry'] = array();
if (!isset($query['link']['Entry']['DoubleEntry']['fields']))
$query['link']['Entry']['DoubleEntry']['fields'] = array();
if (!isset($query['link']['Entry']['DoubleEntry']['Transaction']))
$query['link']['Entry']['DoubleEntry']['Transaction'] = array();
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['link']['Ledger']))
$query['link']['Ledger'] = array();
if (!isset($query['link']['Ledger']['fields']))
$query['link']['Ledger']['fields'] = array();
if (!isset($query['link']['Ledger']['Account']))
$query['link']['Ledger']['Account'] = array();
if (!isset($query['link']['Ledger']['Account']['fields']))
$query['link']['Ledger']['Account']['fields'] = array();
/* if (!isset($query['link']['Transaction'])) */
/* $query['link']['Transaction'] = array(); */
/* if (!isset($query['link']['Transaction']['fields'])) */
/* $query['link']['Transaction']['fields'] = array(); */
/* $query['link']['Transaction']['fields'][] = 'stamp'; */
if (!isset($query['fields']))
$query['fields'] = array();
$query['fields'] = array_merge($query['fields'],
$this->debitCreditFields($id, true));
$this->debitCreditFields(true));
$query['conditions'][] = array('Ledger.id' => $id);
$query['group'][] = 'Ledger.id';
$query['conditions'][] = array('LedgerEntry.ledger_id' => $id);
$query['group'][] = 'LedgerEntry.ledger_id';
$stats = $this->find('first', $query);
$stats = $this->LedgerEntry->find('first', $query);
pr(compact('stats'));
unset($query['group']);
$query['fields'] = $this->debitCreditFields($id, false);
$stats = $this->find('all', $query);
pr(compact('query', 'stats'));
/* 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,
// and the rest of the array is useless (empty).

View File

@@ -0,0 +1,320 @@
<?php
class LedgerEntry extends AppModel {
var $belongsTo = array(
'Transaction',
'Account',
'Ledger',
);
var $hasOne = array(
'Payment',
);
var $hasMany = array(
);
var $hasAndBelongsToMany = array(
// The Debit half of the double entry matching THIS Credit (if it is one)
'DebitEntry' => array(
'className' => 'LedgerEntry',
'joinTable' => 'double_entries',
'linkalias' => 'DDE',
'foreignKey' => 'credit_entry_id',
'associationForeignKey' => 'debit_entry_id',
),
// The Credit half of the double entry matching THIS Debit (if it is one)
'CreditEntry' => array(
'className' => 'LedgerEntry',
'joinTable' => 'double_entries',
'linkalias' => 'CDE',
'foreignKey' => 'debit_entry_id',
'associationForeignKey' => 'credit_entry_id',
),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* 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/ledger.
*/
function debitCreditFields($sum = false, $entry_name = 'Entry', $account_name = 'Account') {
$fields = array
(
($sum ? 'SUM(' : '') .
"IF({$entry_name}.type = 'DEBIT'," .
" {$entry_name}.amount, NULL)" .
($sum ? ')' : '') . ' AS debit' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') .
"IF({$entry_name}.type = 'CREDIT'," .
" {$entry_name}.amount, NULL)" .
($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') .
"IF(${account_name}.type IN ('ASSET', 'EXPENSE')," .
" IF({$entry_name}.type = 'DEBIT', 1, -1)," .
" IF({$entry_name}.type = 'CREDIT', 1, -1))" .
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
($sum ? ')' : '') . ' AS balance',
);
if ($sum)
$fields[] = "COUNT({$entry_name}.id) AS entries";
return $fields;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addCharge
* - Adds a new charge
*/
function addCharge($data, $transaction, $customer_id, $lease_id = null) {
// Create some models for convenience
$A = new Account();
// Assume this will succeed
$ret = true;
// Establish the key charge parameters
$charge = array_intersect_key($data, array('stamp'=>1, 'amount'=>1, 'account_id'=>1));
$charge['customer_id'] = $customer_id;
$charge['lease_id'] = $lease_id;
$charge['type'] = 'CHARGE';
$ids = $this->Entry->Ledger->Account->postLedgerEntry
($transaction,
$charge,
array('debit_ledger_id' => $A->currentLedgerID($data['account_id']),
'credit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID())
) + $data
);
if ($ids['error'])
$ret = false;
return $ids['charge_id'];
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addPayment
* - Adds a new payment
*/
function addPayment($data, $transaction, $customer_id, $lease_id = null) {
// Create some models for convenience
$A = new Account();
// Assume this will succeed
$ret = true;
// Establish the key payment parameters
$payment = array_intersect_key($data, array('stamp'=>1, 'name'=>1, 'monetary_type'=>1,
'data1'=>1, 'data2'=>1, 'data3'=>1, 'data4'=>1,
'amount'=>1, 'account_id'=>1));
$payment['customer_id'] = $customer_id;
$payment['type'] = 'PAYMENT';
$ids = $this->Entry->Ledger->Account->postLedgerEntry
($transaction,
$payment,
array('debit_ledger_id' => $A->currentLedgerID($data['account_id']),
'credit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID())
) + $data
);
if ($ids['error'])
$ret = false;
return $ids['payment_id'];
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reverse
* - Reverses the charges
*
* SAMPLE MOVE IN w/ PRE PAYMENT
* DEPOSIT RENT A/R RECEIPT CHECK PETTY BANK
* ------- ------- ------- ------- ------- ------- -------
* |25 | 25| | | | |
* | |20 20| | | | |
* | |20 20| | | | |
* | |20 20| | | | |
* | | |25 25| | | |
* | | |20 20| | | |
* | | |20 20| | | |
* | | |20 20| | | |
* | | | |85 85| | |
* | | | | |85 | 85|
* MOVE OUT and REFUND FINAL MONTH
* DEPOSIT RENT C/P RECEIPT CHECK PETTY BANK
* ------- ------- ------- ------- ------- ------- -------
* 25| | |25 | | | | t20 e20a
* | 20| |20 | | | | t20 e20b
* -ONE REFUND CHECK-
* | | 25| |25 | | | t30 e30a
* | | 20| |20 | | | t30 e30b
* | | | 45| | | |45 t40 e40
* -OR MULTIPLE-
* | | 15| |15 | | | t50a e50a
* | | | 15| | |15 | t60a e60a
* | | 30| |30 | | | t50b e50b
* | | | 30| | | |30 t60b e60b
* | | | | | | |
OPTION 1
* |-25 | -25| | | | |
* | |-20 -20| | | | |
* | | |-25 -25| | | |
* | | |-20 -20| | | |
OPTION 2
* |-25 | | -25| | | |
* | |-20 | -20| | | |
* | | | |-15 | -15| |
* | | | |-30 | | -30|
* | | | | | | |
*
*/
function reverse($ledger_entries, $stamp = null) {
pr(array('Entry::reverse',
compact('ledger_entries', 'stamp')));
// If the user only wants to reverse one ID, we'll allow it
if (!is_array($ledger_entries))
$ledger_entries = $this->find
('all', array
('contain' => false,
'conditions' => array('Entry.id' => $ledger_entries)));
$A = new Account();
$ar_account_id = $A->accountReceivableAccountID();
$receipt_account_id = $A->receiptAccountID();
$transaction_id = null;
foreach ($ledger_entries AS $entry) {
$entry = $entry['Entry'];
$amount = -1*$entry['amount'];
if (isset($entry['credit_account_id']))
$refund_account_id = $entry['credit_account_id'];
elseif (isset($entry['CreditLedger']['Account']['id']))
$refund_account_id = $entry['CreditLedger']['Account']['id'];
elseif (isset($entry['credit_ledger_id']))
$refund_account_id = $this->Ledger->accountID($entry['credit_ledger_id']);
else
return null;
// post new refund in the income account
$ids = $A->postEntry
(array('transaction_id' => $transaction_id),
null,
array('debit_ledger_id' => $A->currentLedgerID($ar_account_id),
'credit_ledger_id' => $A->currentLedgerID($refund_account_id),
'effective_date' => $entry['effective_date'],
'through_date' => $entry['through_date'],
'amount' => $amount,
'lease_id' => $entry['lease_id'],
'customer_id' => $entry['customer_id'],
'comment' => "Refund; Entry #{$entry['id']}",
),
array('debit' => array
(array('Entry' =>
array('id' => $entry['id'],
'amount' => $amount))),
)
);
if ($ids['error'])
return null;
$transaction_id = $ids['transaction_id'];
pr(array('checkpoint' => 'Posted Refund Ledger Entry',
compact('ids', 'amount', 'refund_account_id', 'ar_account_id')));
}
return true;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: stats
* - Returns summary data from the requested ledger entry
*/
function stats($id = null, $query = null, $set = null) {
$this->queryInit($query);
unset($query['group']);
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
/* if (!isset($query['link']['DoubleEntry']['fields'])) */
/* $query['link']['DoubleEntry']['fields'] = array(); */
if (isset($id))
$query['conditions'][] = array('Entry.id' => $id);
if (isset($set))
$set = strtoupper($set);
//pr(array('stats()', compact('id', 'query', 'set')));
$rtypes = array('charge', 'payment',
// 'debit', 'credit',
);
$stats = array();
foreach($rtypes AS $rtype) {
$Rtype = ucfirst($rtype);
if (($rtype == 'charge' && (!isset($set) || $set == 'PAYMENT')) ||
($rtype == 'payment' && (!isset($set) || $set == 'CHARGE'))
/* ($rtype == 'debit' && (!isset($set) || $set == 'CREDIT')) || */
/* ($rtype == 'credit' && (!isset($set) || $set == 'DEBIT')) */
) {
$rquery = $query;
$rquery['link'][$Rtype] =
array('fields' => array("SUM(COALESCE(Applied{$Rtype}.amount,0)) AS reconciled"));
$rquery['fields'] = array();
//$rquery['fields'][] = "SUM(DoubleEntry.amount) AS total";
$rquery['fields'][] = "SUM(DoubleEntry.amount) - SUM(COALESCE(Applied{$Rtype}.amount,0)) AS balance";
$rquery['conditions'][] = array("Applied{$Rtype}.id !=" => null);
$result = $this->find('first', $rquery);
//pr(compact('Rtype', 'rquery', 'result'));
$sumfld = $Rtype;
$stats[$sumfld] = $result[0];
/* if (!isset($stats[$sumfld]['applied'])) */
/* $stats[$sumfld]['applied'] = 0; */
}
}
return $stats;
}
}

View File

@@ -2,16 +2,13 @@
class Payment extends AppModel {
var $belongsTo = array(
'Customer',
'Lease',
);
var $hasMany = array(
'DoubleEntry',
);
var $hasAndBelongsToMany = array(
'DoubleEntry',
'LedgerEntry',
'DepositTransaction' => array(
'className' => 'Transaction',
),
'NsfTransaction' => array(
'className' => 'Transaction',
),
);
@@ -36,7 +33,7 @@ class Payment extends AppModel {
// Create the payment entry, and reconcile the credit side
// of the double-entry (which should be A/R) as a payment.
$ids = $this->DoubleEntry->Ledger->Account->postDoubleEntry
$ids = $this->LedgerEntry->Ledger->Account->postLedgerEntry
($payment,
array('debit_ledger_id' => $A->currentLedgerID($entry['account_id']),
'credit_ledger_id' => $A->currentLedgerID($A->paymentAccountID())
@@ -97,7 +94,7 @@ class Payment extends AppModel {
('first',
array('contain' =>
array(/* e3 */
'DoubleEntry' =>
'LedgerEntry' =>
array('Transaction.id',
'Payment.id',
'Customer.id',
@@ -126,7 +123,7 @@ class Payment extends AppModel {
),
/* e2 */
'DebitReconciliationDoubleEntry' =>
'DebitReconciliationLedgerEntry' =>
array(/* e2 credit */
'CreditLedger' => /* i.e. A/R Ledger */
array('fields' => array(),
@@ -141,11 +138,11 @@ class Payment extends AppModel {
/* e1 */
// STUPID CakePHP bug screws up CLASS contains CLASS.
// Use the same class, but with different name.
'DebitReconciliationDoubleEntry2',
'DebitReconciliationLedgerEntry2',
),
/* e4 */
'CreditReconciliationDoubleEntry' =>
'CreditReconciliationLedgerEntry' =>
array(/* e4 debit */
'DebitLedger' => /* e.g. BANK Ledger */
array('fields' => array('id'),
@@ -170,9 +167,9 @@ class Payment extends AppModel {
$t4_id = null;
$t5_id = null;
foreach ($source['DoubleEntry'] AS $e3) {
foreach ($source['LedgerEntry'] AS $e3) {
// We expect only a single e4 entry
$e4 = $e3['CreditReconciliationDoubleEntry'];
$e4 = $e3['CreditReconciliationLedgerEntry'];
if (count($e4) < 1)
continue;
if (count($e4) > 1)
@@ -188,7 +185,7 @@ class Payment extends AppModel {
$bank_account_id = $e4['DebitLedger']['account_id'];
// post new e5
$e5_ids = $A->postDoubleEntry
$e5_ids = $A->postLedgerEntry
(array('transaction_id' => $t4_id),
null,
array('debit_ledger_id' => $A->currentLedgerID($bank_account_id),
@@ -211,7 +208,7 @@ class Payment extends AppModel {
// post new e6... this will be our crossover point
// from typical positive entries to negative entries.
// Therefore, no reconciliation on this account.
$e6_ids = $A->postDoubleEntry
$e6_ids = $A->postLedgerEntry
(array('transaction_id' => $t5_id),
array('monetary_source_id' => $e3['monetary_source_id']),
array('debit_ledger_id' => $A->currentLedgerID($nsf_account_id),
@@ -223,7 +220,7 @@ class Payment extends AppModel {
'comment' => "NSF tracker; Monetary Source #{$id}",
),
array('debit' => array
(array('DoubleEntry' =>
(array('LedgerEntry' =>
array('id' => $e5_ids['id'],
'amount' => $amount))),
)
@@ -237,12 +234,12 @@ class Payment extends AppModel {
compact('e6_ids', 'amount')));
$t6_id = null;
foreach ($e3['DebitReconciliationDoubleEntry'] AS $e2) {
foreach ($e2['DebitReconciliationDoubleEntry2'] AS $e1) {
foreach ($e3['DebitReconciliationLedgerEntry'] AS $e2) {
foreach ($e2['DebitReconciliationLedgerEntry2'] AS $e1) {
$amount = -1*$e1['Reconciliation']['amount'];
// post new e7
$e7_ids = $A->postDoubleEntry
$e7_ids = $A->postLedgerEntry
(array('transaction_id' => $t6_id),
null,
array('debit_ledger_id' => $A->currentLedgerID($receipt_account_id),
@@ -254,12 +251,12 @@ class Payment extends AppModel {
'comment' => "NSF Receipt; Monetary Source #{$id}",
),
array('debit' => array
(array('DoubleEntry' =>
(array('LedgerEntry' =>
array('id' => $e6_ids['id'],
'amount' => $amount))),
'credit' => array
(array('DoubleEntry' =>
(array('LedgerEntry' =>
array('id' => $e1['id'],
'amount' => $amount))),
)
@@ -276,11 +273,11 @@ class Payment extends AppModel {
}
// Cheat for now
$customer_id = $source['DoubleEntry'][0]['customer_id'];
$customer_id = $source['LedgerEntry'][0]['customer_id'];
$lease_id = null;
// post new e8
$e8_ids = $A->postDoubleEntry
$e8_ids = $A->postLedgerEntry
(array('transaction_id' => $t6_id),
null,
array('debit_ledger_id' => $A->currentLedgerID($ar_account_id),

View File

@@ -1,13 +0,0 @@
<?php
class Reconciliation extends AppModel {
var $belongsTo = array(
'DebitEntry' => array(
'className' => 'Entry',
),
'CreditEntry' => array(
'className' => 'Entry',
),
);
}

View File

@@ -1,72 +1,25 @@
<?php
class Entry extends AppModel {
class StatementEntry extends AppModel {
var $belongsTo = array(
'Transaction',
'Customer',
'Lease',
'Account',
'DoubleEntry',
// The charge to which this payment applies (if it is one)
'ChargeEntry' => array(
'className' => 'StatementEntry',
),
);
var $hasAndBelongsToMany = array(
// The Charges that match THIS Payment (if it is one)
'Charge' => array(
'className' => 'Entry',
'joinTable' => 'charges_payments',
'linkalias' => 'AppliedCharge',
'foreignKey' => 'payment_entry_id',
'associationForeignKey' => 'charge_entry_id',
),
// The Payments that match THIS Charge (if it is one)
'Payment' => array(
'className' => 'Entry',
'joinTable' => 'charges_payments',
'linkalias' => 'AppliedPayment',
var $hasMany = array(
// The payments that apply to this charge (if it is one)
'PaymentEntry' => array(
'className' => 'StatementEntry',
'foreignKey' => 'charge_entry_id',
'associationForeignKey' => 'payment_entry_id',
),
/* // The Deposits that match THIS Payment (if it is one) */
/* 'Deposit' => array( */
/* 'className' => 'Entry', */
/* 'joinTable' => 'deposits_payments', */
/* 'linkalias' => 'AppliedDeposit', */
/* 'foreignKey' => 'payment_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 */
/* 'REntry' => array( */
/* 'className' => 'Entry', */
/* 'joinTable' => 'reconciliations', */
/* //'linkalias' => 'AppliedCredit', */
/* 'foreignKey' => false, */
/* 'associationForeignKey' => false, */
/* 'conditions' => array( */
/* "Reconciliation.credit_entry_id */
/* = IF(Entry.crdr = 'CREDIT', Entry.id, REntry.id)", */
/* "Reconciliation.debit_entry_id */
/* = IF(Entry.crdr = 'DEBIT', Entry.id, REntry.id)" */
/* ), */
/* ), */
);
@@ -77,22 +30,22 @@ class Entry extends AppModel {
*/
function chargePaymentFields($sum = false, $entry_name = 'Entry', $double_name = 'DoubleEntry') {
function chargePaymentFields($sum = false, $entry_name = 'StatementEntry') {
$fields = array
(
($sum ? 'SUM(' : '') .
"IF({$entry_name}.type = 'CHARGE'," .
" {$double_name}.amount, NULL)" .
" {$entry_name}.amount, NULL)" .
($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''),
($sum ? 'SUM(' : '') .
"IF({$entry_name}.type = 'PAYMENT'," .
" {$double_name}.amount, NULL)" .
" {$entry_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)" .
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
($sum ? ')' : '') . ' AS balance',
);
@@ -124,7 +77,7 @@ class Entry extends AppModel {
$charge['lease_id'] = $lease_id;
$charge['type'] = 'CHARGE';
$ids = $this->Entry->Ledger->Account->postDoubleEntry
$ids = $this->Entry->Ledger->Account->postLedgerEntry
($transaction,
$charge,
array('debit_ledger_id' => $A->currentLedgerID($data['account_id']),
@@ -160,7 +113,7 @@ class Entry extends AppModel {
$payment['customer_id'] = $customer_id;
$payment['type'] = 'PAYMENT';
$ids = $this->Entry->Ledger->Account->postDoubleEntry
$ids = $this->Entry->Ledger->Account->postLedgerEntry
($transaction,
$payment,
array('debit_ledger_id' => $A->currentLedgerID($data['account_id']),
@@ -300,24 +253,16 @@ OPTION 2
$this->queryInit($query);
if ($set == 'CHARGE' || $set == 'PAYMENT')
$query['conditions'][] = array('Entry.type' => $set);
elseif ($set == 'DEBIT' || $set == 'CREDIT')
$query['conditions'][] = array('Entry.crdr' => $set);
$query['conditions'][] = array('StatementEntry.type' => $set);
else
die("INVALID RECONCILE SET");
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
if ($set == 'CHARGE')
$query['link']['Payment'] = array('fields' => array("SUM(AppliedPayment.amount) AS reconciled"));
$query['link']['PaymentEntry'] = array('fields' => array("SUM(PaymentEntry.amount) AS reconciled"));
if ($set == 'PAYMENT')
$query['link']['Charge'] = array('fields' => array("SUM(AppliedCharge.amount) AS reconciled"));
/* if ($set == 'DEBIT') */
/* $query['link']['Credit'] = array('fields' => array("SUM(AppliedCredit.amount) AS reconciled")); */
/* if ($set == 'CREDIT') */
/* $query['link']['Debit'] = array('fields' => array("SUM(AppliedDebit.amount) AS reconciled")); */
$query['link']['ChargeEntry'] = array('fields' => array("SUM(ChargeEntry.amount) AS reconciled"));
$query['group'] = 'Entry.id';
$query['group'] = 'StatementEntry.id';
return $query;
}
@@ -329,15 +274,16 @@ OPTION 2
$resultset = array();
foreach ($result AS $i => $entry) {
$entry['DoubleEntry'] += $entry[0];
pr(compact('entry'));
$entry['StatementEntry'] += $entry[0];
unset($entry[0]);
$entry['DoubleEntry']['balance'] =
$entry['DoubleEntry']['amount'] - $entry['DoubleEntry']['reconciled'];
$entry['StatementEntry']['balance'] =
$entry['StatementEntry']['amount'] - $entry['StatementEntry']['reconciled'];
// Since HAVING isn't a builtin feature of CakePHP,
// we'll have to post-process to get the desired entries
if ($entry['DoubleEntry']['balance'] == 0) {
if ($entry['StatementEntry']['balance'] == 0) {
if (!$unrec)
$resultset[] = $entry;
}
@@ -347,10 +293,12 @@ OPTION 2
}
}
//pr(array('StatementEntry::reconciledSet()' => compact('resultset')));
//$resultset['stats'] = $this->stats(null, $query);
//pr($this->stats(null, $query));
return array('entries' => $resultset,
'summary' => $this->stats(null, $query, $set));
'summary' => $this->stats(null, $query));
}
@@ -364,20 +312,16 @@ OPTION 2
function reconciledEntriesQuery($id, $query = null) {
$this->queryInit($query, false);
$entry = $this->find('first', array('conditions' => array('Entry.id' => $id),
'recursive' => -1));
$entry = $entry['Entry'];
$this->id = $id;
$this->recursive = -1;
$this->read();
$query['conditions'][] = array('Entry.id' => $id);
$query['conditions'][] = array('StatementEntry.id' => $id);
if ($entry['type'] == 'CHARGE')
$query['contain']['Payment'] = array('fields' => array('Payment.*', 'ChargesPayment.amount'));
if ($entry['type'] == 'PAYMENT')
$query['contain']['Charge'] = array('fields' => array('Charge.*', 'ChargesPayment.amount'));
/* if ($entry['crdr'] == 'DEBIT') */
/* $query['contain']['Credit'] = array('fields' => array('Credit.*', 'Reconciliation.amount')); */
/* if ($entry['crdr'] == 'CREDIT') */
/* $query['contain']['Debit'] = array('fields' => array('Debit.*', 'Reconciliation.amount')); */
if ($this->data['StatementEntry']['type'] == 'CHARGE')
$query['link']['PaymentEntry'] = array();
if ($this->data['StatementEntry']['type'] == 'PAYMENT')
$query['link']['ChargeEntry'] = array();
return $query;
}
@@ -386,11 +330,13 @@ OPTION 2
$lquery = $this->reconciledEntriesQuery($id, $query);
//pr(array('reconciledEntries', compact('entry', 'contain')));
$result = $this->find('first', $lquery);
unset($result['Entry']);
$result = $this->find('all', $lquery);
foreach (array_keys($result) AS $i)
unset($result[$i]['StatementEntry']);
return array('entries' => $result,
'summary' => $this->stats($id, $query));
//pr(array('StatementEntry::reconciledEntries()' => compact('result')));
return array('entries' => $result);
//'summary' => $this->stats($id, $query));
}
@@ -398,59 +344,138 @@ OPTION 2
**************************************************************************
**************************************************************************
* function: stats
* - Returns summary data from the requested ledger entry
* - Returns summary data from the requested statement entry
*/
function stats($id = null, $query = null, $set = null) {
function stats($id = null, $query = null) {
$this->queryInit($query);
unset($query['group']);
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
/* if (!isset($query['link']['DoubleEntry']['fields'])) */
/* $query['link']['DoubleEntry']['fields'] = array(); */
if (isset($id))
$query['conditions'][] = array('Entry.id' => $id);
if (isset($id)) {
$this->id = $id;
$this->recursive = -1;
$this->read();
if (isset($set))
$set = strtoupper($set);
if ($this->data['StatementEntry']['type'] == 'PAYMENT') {
// Payment has only a _single_ charge, and by definition
// 100% of the payment is used to reconcile that charge.
return array('total' => $this->data['StatementEntry']['amount'],
'reconciled' => $this->data['StatementEntry']['amount'],
'balance' => 0);
}
$query['link']['PaymentEntry'] =
array('fields' => array("SUM(COALESCE(PaymentEntry.amount,0)) AS reconciled"),
//'type' => 'INNER',
);
$query['fields'] = array();
$query['fields'][] = "StatementEntry.amount AS total";
//$query['conditions'][] = array("{$Set}Entry.id !=" => null);
$query['conditions'][] = array('StatementEntry.id' => $id);
$query['group'] = 'StatementEntry.id';
$result = $this->find('first', $query);
$result[0]['balance'] = $result[0]['total'] - $result[0]['reconciled'];
//pr(compact('query', 'result'));
return $result['StatementEntry'] + $result[0];
}
$stats = array();
$rquery = $query;
$rquery['link']['PaymentEntry'] =
array('fields' => array("SUM(COALESCE(PaymentEntry.amount,0)) AS reconciled"),
//'type' => 'INNER',
);
$rquery['fields'] = array();
$rquery['fields'][] = "SUM(StatementEntry.amount) AS total";
$rquery['conditions'][] = array("PaymentEntry.id !=" => null);
$result = $this->find('first', $rquery);
$result[0]['balance'] = $result[0]['total'] - $result[0]['reconciled'];
$stats['Payment'] = $result[0];
//pr(array('stats Payment', compact('rquery', 'stats')));
$rquery = $query;
$rquery['fields'] = array();
$rquery['fields'][] = "SUM(StatementEntry.amount) AS total";
$rquery['fields'][] = "SUM(StatementEntry.amount) AS reconciled";
$result = $this->find('first', $rquery);
$result[0]['balance'] = $result[0]['total'] - $result[0]['reconciled'];
$stats['Charge'] = $result[0];
//pr(array('stats Charge', compact('rquery', 'stats')));
return $stats;
$this->id = $id;
$this->recursive = -1;
$this->read();
//pr(array('stats()', compact('id', 'query', 'set')));
$rtypes = array('charge', 'payment',
// 'debit', 'credit',
);
$stats = array();
foreach($rtypes AS $rtype) {
$Rtype = ucfirst($rtype);
if (($rtype == 'charge' && (!isset($set) || $set == 'PAYMENT')) ||
($rtype == 'payment' && (!isset($set) || $set == 'CHARGE'))
/* ($rtype == 'debit' && (!isset($set) || $set == 'CREDIT')) || */
/* ($rtype == 'credit' && (!isset($set) || $set == 'DEBIT')) */
) {
/* if ($this->data['StatementEntry']['type'] == 'CHARGE') */
/* $set = 'PAYMENT'; */
/* else */
/* $set = 'CHARGE'; */
$rquery = $query;
$rquery['link'][$Rtype] =
array('fields' => array("SUM(COALESCE(Applied{$Rtype}.amount,0)) AS reconciled"));
/* $Set = ucfirst(strtolower($set)); */
$rquery['fields'] = array();
//$rquery['fields'][] = "SUM(DoubleEntry.amount) AS total";
$rquery['fields'][] = "SUM(DoubleEntry.amount) - SUM(COALESCE(Applied{$Rtype}.amount,0)) AS balance";
$rquery['conditions'][] = array("Applied{$Rtype}.id !=" => null);
/* $query['link'][$Set.'Entry'] = */
/* array('fields' => array("SUM(COALESCE({$Set}Entry.amount,0)) AS reconciled"), */
/* //'type' => 'INNER', */
/* ); */
$result = $this->find('first', $rquery);
//pr(compact('Rtype', 'rquery', 'result'));
/* $query['fields'] = array(); */
/* $query['fields'][] = "StatementEntry.amount AS total"; */
/* $query['fields'][] = "StatementEntry.amount - SUM(COALESCE({$Set}Entry.amount,0)) AS balance"; */
/* //$query['conditions'][] = array("{$Set}Entry.id !=" => null); */
$sumfld = $Rtype;
$stats[$sumfld] = $result[0];
/* if (!isset($stats[$sumfld]['applied'])) */
/* $stats[$sumfld]['applied'] = 0; */
}
/* $query['conditions'][] = array('StatementEntry.id' => $id); */
/* $query['group'] = 'StatementEntry.id'; */
/* $result = $this->find('first', $query); */
/* pr(compact('Rtype', 'query', 'result')); */
/* return $result['StatementEntry'] + $result[0]; */
if ($this->data['StatementEntry']['type'] == 'PAYMENT') {
// Payment has only a _single_ charge, and by definition
// 100% of the payment is used to reconcile that charge.
return array('total' => $this->data['StatementEntry']['amount'],
'reconciled' => $this->data['StatementEntry']['amount'],
'balance' => 0);
}
return $stats;
$query['link']['PaymentEntry'] =
array('fields' => array("SUM(COALESCE(PaymentEntry.amount,0)) AS reconciled"),
//'type' => 'INNER',
);
$query['fields'] = array();
$query['fields'][] = "StatementEntry.amount AS total";
$query['fields'][] = "StatementEntry.amount - SUM(COALESCE(PaymentEntry.amount,0)) AS balance";
//$query['conditions'][] = array("{$Set}Entry.id !=" => null);
$query['conditions'][] = array('StatementEntry.id' => $id);
$query['group'] = 'StatementEntry.id';
$result = $this->find('first', $query);
//pr(compact('Rtype', 'query', 'result'));
return $result['StatementEntry'] + $result[0];
}
}

View File

@@ -1,17 +1,14 @@
<?php
class Transaction extends AppModel {
var $validate = array(
'stamp' => array('date')
);
var $belongsTo = array(
'Customer',
'Lease',
'Account',
'Ledger',
);
var $hasMany = array(
'DoubleEntry',
'LedgerEntry',
'StatementEntry',
);
@@ -37,15 +34,15 @@ class Transaction extends AppModel {
// Determine the total charges on the invoice
$invoice['amount'] = 0;
foreach ($data['DoubleEntry'] AS $entry)
foreach ($data['LedgerEntry'] AS $entry)
$invoice['amount'] += $entry['amount'];
// Go through the entered charges
foreach ($data['DoubleEntry'] AS $entry) {
foreach ($data['LedgerEntry'] AS $entry) {
//pr(compact('entry'));
// Create the receipt entry, and reconcile the credit side
// of the double-entry (which should be A/R) as a payment.
$ids = $this->DoubleEntry->Ledger->Account->postDoubleEntry
$ids = $this->LedgerEntry->Ledger->Account->postLedgerEntry
($invoice,
array('debit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID()),
'credit_ledger_id' => $A->currentLedgerID($entry['account_id'])
@@ -83,14 +80,14 @@ class Transaction extends AppModel {
// Determine the total charges on the receipt
$receipt['amount'] = 0;
foreach ($data['DoubleEntry'] AS $entry)
foreach ($data['LedgerEntry'] AS $entry)
$receipt['amount'] += $entry['amount'];
// Go through the entered charges
foreach ($data['DoubleEntry'] AS $entry) {
foreach ($data['LedgerEntry'] AS $entry) {
// Create the receipt entry, and reconcile the credit side
// of the double-entry (which should be A/R) as a receipt.
$ids = $this->DoubleEntry->Ledger->Account->postDoubleEntry
$ids = $this->LedgerEntry->Ledger->Account->postLedgerEntry
($receipt,
array('debit_ledger_id' => $A->currentLedgerID($entry['account_id']),
'credit_ledger_id' => $A->currentLedgerID($A->receiptAccountID())