Files
pmgr/models/entry.php
abijah d5bcd9a496 Another snapshot
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716/site@356 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-07-20 23:35:11 +00:00

457 lines
16 KiB
PHP

<?php
class Entry extends AppModel {
var $belongsTo = array(
'Account',
'DoubleEntry',
);
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',
'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)" */
/* ), */
/* ), */
);
/**************************************************************************
**************************************************************************
**************************************************************************
* 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;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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->postDoubleEntry
($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->postDoubleEntry
($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: reconciledSet
* - Returns the set of entries satisfying the given conditions,
* along with any entries that they reconcile
*/
function reconciledSetQuery($set, $query) {
$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);
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"));
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['group'] = 'Entry.id';
return $query;
}
function reconciledSet($set, $query = null, $unrec = false) {
$lquery = $this->reconciledSetQuery($set, $query);
$result = $this->find('all', $lquery);
//pr(array('reconciledSet', compact('set', 'lquery', 'result')));
$resultset = array();
foreach ($result AS $i => $entry) {
$entry['DoubleEntry'] += $entry[0];
unset($entry[0]);
$entry['DoubleEntry']['balance'] =
$entry['DoubleEntry']['amount'] - $entry['DoubleEntry']['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 (!$unrec)
$resultset[] = $entry;
}
else {
if ($unrec)
$resultset[] = $entry;
}
}
//$resultset['stats'] = $this->stats(null, $query);
//pr($this->stats(null, $query));
return array('entries' => $resultset,
'summary' => $this->stats(null, $query, $set));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reconciledEntries
* - Returns a list of entries that reconcile against the given entry.
* (such as payments towards a charge).
*/
function reconciledEntriesQuery($id, $query = null) {
$this->queryInit($query, false);
$entry = $this->find('first', array('conditions' => array('Entry.id' => $id),
'recursive' => -1));
$entry = $entry['Entry'];
$query['conditions'][] = array('Entry.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')); */
return $query;
}
function reconciledEntries($id, $query = null) {
$lquery = $this->reconciledEntriesQuery($id, $query);
//pr(array('reconciledEntries', compact('entry', 'contain')));
$result = $this->find('first', $lquery);
unset($result['Entry']);
return array('entries' => $result,
'summary' => $this->stats($id, $query));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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;
}
}