Getting closer on the reversal issue. There is definitely more testing to do, and some tweaks as well, but this may be approximately what we will finally settle on.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716/site@565 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
@@ -245,19 +245,14 @@ class StatementEntriesController extends AppController {
|
|||||||
|
|
||||||
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
|
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
|
||||||
|
|
||||||
$reversal = $this->StatementEntry->find
|
$reversable = $this->StatementEntry->reversable($id);
|
||||||
('first',
|
|
||||||
array('link' => array('DisbursementEntry'),
|
|
||||||
'conditions' => array(array('StatementEntry.id' => $id),
|
|
||||||
array('DisbursementEntry.type' => 'REVERSAL')),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Set up dynamic menu items
|
// Set up dynamic menu items
|
||||||
if (empty($reversal) || $stats['balance'] > 0)
|
if ($reversable || $stats['balance'] > 0)
|
||||||
$this->sidemenu_links[] =
|
$this->sidemenu_links[] =
|
||||||
array('name' => 'Operations', 'header' => true);
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
|
||||||
if (empty($reversal))
|
if ($reversable)
|
||||||
$this->sidemenu_links[] =
|
$this->sidemenu_links[] =
|
||||||
array('name' => 'Reverse',
|
array('name' => 'Reverse',
|
||||||
'url' => array('action' => 'reverse',
|
'url' => array('action' => 'reverse',
|
||||||
|
|||||||
@@ -181,8 +181,8 @@ class StatementEntry extends AppModel {
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
* function: reverse
|
* function: reversable
|
||||||
* - Reverses the charges
|
* - Returns true if the charge can be reversed; false otherwise
|
||||||
*/
|
*/
|
||||||
function reversable($id) {
|
function reversable($id) {
|
||||||
$this->prEnter(compact('id'));
|
$this->prEnter(compact('id'));
|
||||||
@@ -194,15 +194,9 @@ class StatementEntry extends AppModel {
|
|||||||
return $this->prReturn(false);
|
return $this->prReturn(false);
|
||||||
|
|
||||||
// Determine anything reconciled against the charge
|
// Determine anything reconciled against the charge
|
||||||
$reconciled = $this->reconciledEntries($id);
|
$reverse_transaction_id = $this->field('reverse_transaction_id');
|
||||||
$this->pr(21, compact('reconciled'));
|
if (!empty($reverse_transaction_id))
|
||||||
|
|
||||||
if (!empty($reconciled)) {
|
|
||||||
// Double check that this charge has not already been reversed
|
|
||||||
foreach ($reconciled['entries'] AS $entry)
|
|
||||||
if ($entry['DisbursementEntry']['type'] === 'REVERSAL')
|
|
||||||
return $this->prReturn(false);
|
return $this->prReturn(false);
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn(true);
|
return $this->prReturn(true);
|
||||||
}
|
}
|
||||||
@@ -222,28 +216,19 @@ class StatementEntry extends AppModel {
|
|||||||
|
|
||||||
// Get the basic information about this charge
|
// Get the basic information about this charge
|
||||||
$charge = $this->find('first', array('contain' => true));
|
$charge = $this->find('first', array('contain' => true));
|
||||||
$charge = $charge['StatementEntry'];
|
//$charge = $charge['StatementEntry'];
|
||||||
|
|
||||||
// Query the stats to get the remaining balance
|
// Query the stats to get the remaining balance
|
||||||
$stats = $this->stats($id);
|
$stats = $this->stats($id);
|
||||||
|
$charge['paid'] = $stats['Charge']['disbursement'];
|
||||||
// Build a transaction
|
|
||||||
$reversal = array('Transaction' => array(), 'Entry' => array());
|
|
||||||
$reversal['Transaction']['stamp'] = $stamp;
|
|
||||||
$reversal['Transaction']['comment'] = "Credit Note: Charge Reversal";
|
|
||||||
|
|
||||||
// Add the charge reversal
|
|
||||||
$reversal['Entry'][] =
|
|
||||||
array('amount' => $stats['Charge']['total'],
|
|
||||||
'account_id' => $charge['account_id'],
|
|
||||||
'comment' => 'Charge Reversal',
|
|
||||||
);
|
|
||||||
|
|
||||||
// Record the reversal transaction
|
// Record the reversal transaction
|
||||||
$result = $this->Transaction->addReversal
|
$result = $this->Transaction->addReversal
|
||||||
($reversal,
|
($charge, $stamp, 'Charge Reversal');
|
||||||
$id, $stats['Charge']['disbursement'],
|
|
||||||
$charge['customer_id'], $charge['lease_id']);
|
// Mark the charge as reversed
|
||||||
|
$this->id = $id;
|
||||||
|
$this->saveField('reverse_transaction_id', $result['transaction_id']);
|
||||||
|
|
||||||
return $this->prReturn($result);
|
return $this->prReturn($result);
|
||||||
}
|
}
|
||||||
@@ -416,8 +401,8 @@ class StatementEntry extends AppModel {
|
|||||||
array('StatementEntry',
|
array('StatementEntry',
|
||||||
'LedgerEntry' =>
|
'LedgerEntry' =>
|
||||||
array('conditions' =>
|
array('conditions' =>
|
||||||
array('LedgerEntry.account_id !=' =>
|
array('LedgerEntry.account_id <> Transaction.account_id')
|
||||||
$this->Account->accountReceivableAccountID()),
|
//$this->Account->accountReceivableAccountID()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'conditions' => array('Transaction.id' => $receipt_id),
|
'conditions' => array('Transaction.id' => $receipt_id),
|
||||||
|
|||||||
@@ -178,14 +178,17 @@ class Transaction extends AppModel {
|
|||||||
* - Adds a new charge reversal
|
* - Adds a new charge reversal
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function addReversal($data, $charge_id, $credit_amount, $customer_id, $lease_id = null) {
|
function addReversal1($data, $charge) {
|
||||||
$this->prEnter(compact('data', 'charge_id', 'credit_amount', 'customer_id', 'lease_id'));
|
$this->prEnter(compact('data', 'charge'));
|
||||||
|
|
||||||
if (count($data['Entry']) != 1)
|
if (count($data['Entry']) != 1)
|
||||||
$this->INTERNAL_ERROR("Should be one Entry for addReversal");
|
$this->INTERNAL_ERROR("Should be one Entry for addReversal");
|
||||||
|
|
||||||
$data += array('control' => array());
|
$data += array('control' => array());
|
||||||
|
|
||||||
|
/* 'amount' => $stats['Charge']['total'], */
|
||||||
|
/* 'account_id' => $charge['account_id'], */
|
||||||
|
|
||||||
// First, reverse the charge
|
// First, reverse the charge
|
||||||
$reversal = $data;
|
$reversal = $data;
|
||||||
$reversal['control'] +=
|
$reversal['control'] +=
|
||||||
@@ -194,20 +197,22 @@ class Transaction extends AppModel {
|
|||||||
'include_statement_entry' => true,
|
'include_statement_entry' => true,
|
||||||
);
|
);
|
||||||
|
|
||||||
$reversal['Transaction']['type'] = 'CREDIT_NOTE';
|
//$reversal['Transaction']['type'] = 'CREDIT_NOTE';
|
||||||
//$reversal['Transaction']['crdr'] = 'CREDIT';
|
|
||||||
$reversal['Entry'][0]['charge_entry_id'] = $charge_id;
|
$reversal['Entry'][0]['charge_entry_id'] = $charge_id;
|
||||||
$reversal['Entry'][0]['type'] = 'REVERSAL';
|
//$reversal['Entry'][0]['type'] = 'REVERSAL';
|
||||||
|
$reversal['Entry'][0]['amount'] *= -1;
|
||||||
|
|
||||||
|
//$reversal['Transaction']['crdr'] = 'CREDIT';
|
||||||
//$reversal['Entry'][0]['crdr'] = 'DEBIT';
|
//$reversal['Entry'][0]['crdr'] = 'DEBIT';
|
||||||
$ids['reversal'] = $this->addReceipt($reversal, $customer_id, $lease_id);
|
|
||||||
|
$ids['reversal'] = $this->addInvoice($reversal, $customer_id, $lease_id);
|
||||||
|
|
||||||
|
|
||||||
// Then issue a credit for the amount already paid, if any
|
// Then issue a credit for the amount already paid, if any
|
||||||
if ($credit_amount > 0) {
|
if ($credit_amount > 0) {
|
||||||
$ids['credit'] = $this->addReceipt
|
$ids['credit'] = $this->addReceipt
|
||||||
(array('control' =>
|
(array('control' =>
|
||||||
array('assign' => true,
|
array('include_ledger_entry' => false,
|
||||||
'assign_receipt' => true,
|
|
||||||
'include_ledger_entry' => false,
|
|
||||||
'include_statement_entry' => true,
|
'include_statement_entry' => true,
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -218,6 +223,8 @@ class Transaction extends AppModel {
|
|||||||
'Entry' =>
|
'Entry' =>
|
||||||
array(array('amount' => $credit_amount,
|
array(array('amount' => $credit_amount,
|
||||||
'charge_entry_id' => $charge_id,
|
'charge_entry_id' => $charge_id,
|
||||||
|
// REVISIT <AP>: 20090814
|
||||||
|
// TEMPORARY. JUST NEED AN ACCOUNT AT THE MOMENT
|
||||||
'account_id' => $this->StatementEntry->Account->accountPayableAccountID(),
|
'account_id' => $this->StatementEntry->Account->accountPayableAccountID(),
|
||||||
))),
|
))),
|
||||||
$customer_id, $lease_id);
|
$customer_id, $lease_id);
|
||||||
@@ -590,7 +597,7 @@ class Transaction extends AppModel {
|
|||||||
// Break each entry out of the combined statement/ledger entry
|
// Break each entry out of the combined statement/ledger entry
|
||||||
// and into individual entries appropriate for saving. While
|
// and into individual entries appropriate for saving. While
|
||||||
// we're at it, calculate the transaction total as well.
|
// we're at it, calculate the transaction total as well.
|
||||||
$transaction['amount'] = 0;
|
$transaction_amount = 0;
|
||||||
foreach ($entries AS &$entry) {
|
foreach ($entries AS &$entry) {
|
||||||
// Ensure these items are null'ed out so we don't
|
// Ensure these items are null'ed out so we don't
|
||||||
// accidentally pick up stale data.
|
// accidentally pick up stale data.
|
||||||
@@ -614,7 +621,11 @@ class Transaction extends AppModel {
|
|||||||
$entry['statement_entry_comment'] = null;
|
$entry['statement_entry_comment'] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($control['include_ledger_entry']) || !empty($entry['include_ledger_entry'])) {
|
// Priority goes to settings defined in $entry, but
|
||||||
|
// use the control information as defaults.
|
||||||
|
$entry += $control;
|
||||||
|
|
||||||
|
if (!empty($entry['include_ledger_entry'])) {
|
||||||
// Create one half of the Double Ledger Entry (and the Tender)
|
// Create one half of the Double Ledger Entry (and the Tender)
|
||||||
$le1 =
|
$le1 =
|
||||||
array_intersect_key($entry,
|
array_intersect_key($entry,
|
||||||
@@ -643,10 +654,10 @@ class Transaction extends AppModel {
|
|||||||
$le1 = $le1_tender = $le2 = null;
|
$le1 = $le1_tender = $le2 = null;
|
||||||
|
|
||||||
// Now that the ledger entries are in place, respect the 'negative' flag
|
// Now that the ledger entries are in place, respect the 'negative' flag
|
||||||
if (!empty($control['negative']))
|
if (!empty($entry['negative']))
|
||||||
$entry['amount'] *= -1;
|
$entry['amount'] *= -1;
|
||||||
|
|
||||||
if (!empty($control['include_statement_entry']) || !empty($entry['include_statement_entry'])) {
|
if (!empty($entry['include_statement_entry'])) {
|
||||||
// Create the statement entry
|
// Create the statement entry
|
||||||
$se =
|
$se =
|
||||||
array_intersect_key($entry,
|
array_intersect_key($entry,
|
||||||
@@ -659,7 +670,9 @@ class Transaction extends AppModel {
|
|||||||
$se['comment'] = $entry['statement_entry_comment'];
|
$se['comment'] = $entry['statement_entry_comment'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!empty($control['assign'])) {
|
if (!empty($entry['assign']) &&
|
||||||
|
!empty($entry['type']) &&
|
||||||
|
empty($entry['charge_entry_id'])) {
|
||||||
if (empty($assign_disbursement_type))
|
if (empty($assign_disbursement_type))
|
||||||
$assign_disbursement_type = $entry['type'];
|
$assign_disbursement_type = $entry['type'];
|
||||||
elseif ($entry['type'] != $assign_disbursement_type)
|
elseif ($entry['type'] != $assign_disbursement_type)
|
||||||
@@ -670,12 +683,16 @@ class Transaction extends AppModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add entry amount into the transaction total
|
// Add entry amount into the transaction total
|
||||||
$transaction['amount'] += $entry['amount'];
|
$transaction_amount += $entry['amount'];
|
||||||
|
|
||||||
// Replace combined entry with our new individual entries
|
// Replace combined entry with our new individual entries
|
||||||
$entry = compact('le1', 'le1_tender', 'le2', 'se');
|
$entry = compact('le1', 'le1_tender', 'le2', 'se');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If transaction amount is not already set, use the
|
||||||
|
// sum of the entry amounts.
|
||||||
|
$transaction += array('amount' => $transaction_amount);
|
||||||
|
|
||||||
/* // Add a summary ledger entry if requested */
|
/* // Add a summary ledger entry if requested */
|
||||||
/* if (!empty($control['summary_double_entry'])) { */
|
/* if (!empty($control['summary_double_entry'])) { */
|
||||||
/* $entry = $control['summary_double_entry']; */
|
/* $entry = $control['summary_double_entry']; */
|
||||||
@@ -854,7 +871,7 @@ class Transaction extends AppModel {
|
|||||||
|
|
||||||
'Entry' => array());
|
'Entry' => array());
|
||||||
|
|
||||||
$summary_amount = 0;
|
$rollback['Transaction']['amount'] = 0;
|
||||||
foreach ($nsf_ledger_entry['Transaction']['StatementEntry'] AS $disbursement) {
|
foreach ($nsf_ledger_entry['Transaction']['StatementEntry'] AS $disbursement) {
|
||||||
if ($disbursement['type'] === 'SURPLUS') {
|
if ($disbursement['type'] === 'SURPLUS') {
|
||||||
$disbursement['type'] = 'VOID';
|
$disbursement['type'] = 'VOID';
|
||||||
@@ -870,7 +887,7 @@ class Transaction extends AppModel {
|
|||||||
'lease_id' => $disbursement['lease_id'],
|
'lease_id' => $disbursement['lease_id'],
|
||||||
'charge_entry_id' => $disbursement['charge_entry_id'],
|
'charge_entry_id' => $disbursement['charge_entry_id'],
|
||||||
);
|
);
|
||||||
$summary_amount += $disbursement['amount'];
|
$rollback['Transaction']['amount'] += $disbursement['amount'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -878,11 +895,14 @@ class Transaction extends AppModel {
|
|||||||
$rollback['Entry'][] =
|
$rollback['Entry'][] =
|
||||||
array('include_ledger_entry' => true,
|
array('include_ledger_entry' => true,
|
||||||
'include_statement_entry' => false,
|
'include_statement_entry' => false,
|
||||||
'amount' => $summary_amount,
|
'amount' => $rollback['Transaction']['amount'],
|
||||||
'account_id' => $this->Account->accountReceivableAccountID(),
|
'account_id' => $this->Account->accountReceivableAccountID(),
|
||||||
'crdr' => 'DEBIT',
|
'crdr' => 'DEBIT',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Set the transaction amount to be negative
|
||||||
|
$rollback['Transaction']['amount'] *= -1;
|
||||||
|
|
||||||
// Record the transaction, which will un-pay previously paid
|
// Record the transaction, which will un-pay previously paid
|
||||||
// charges, void any credits, and other similar work.
|
// charges, void any credits, and other similar work.
|
||||||
if (count($rollback['Entry'])) {
|
if (count($rollback['Entry'])) {
|
||||||
@@ -925,6 +945,98 @@ class Transaction extends AppModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addReversal
|
||||||
|
* - Adds a new charge reversal
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addReversal($charge, $stamp = null, $comment = null) {
|
||||||
|
$this->prEnter(compact('charge', 'stamp', 'comment'));
|
||||||
|
|
||||||
|
$ret = array();
|
||||||
|
|
||||||
|
// Finding all statement entries affected by reversing this charge.
|
||||||
|
$disb_entries = $this->StatementEntry->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array('DisbursementEntry' =>
|
||||||
|
array(//'fields' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'conditions' => array('StatementEntry.id' => $charge['StatementEntry']['id']),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->pr(20, compact('disb_entries'));
|
||||||
|
if (!$disb_entries)
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
// Build a transaction to adjust all of the statement entries
|
||||||
|
// These are all disbursements against the charge we're reversing
|
||||||
|
$rollback =
|
||||||
|
array('control' =>
|
||||||
|
array('assign' => true,
|
||||||
|
'assign_receipt' => true,
|
||||||
|
'include_ledger_entry' => false,
|
||||||
|
'include_statement_entry' => true,
|
||||||
|
),
|
||||||
|
|
||||||
|
'Transaction' =>
|
||||||
|
array('stamp' => $stamp,
|
||||||
|
//'type' => 'RECEIPT',
|
||||||
|
'type' => 'CREDIT_NOTE',
|
||||||
|
// The transaction amount will equal that of the charge
|
||||||
|
'amount' => $charge['StatementEntry']['amount'],
|
||||||
|
'account_id' => $charge['StatementEntry']['account_id'],
|
||||||
|
'crdr' => 'DEBIT',
|
||||||
|
'customer_id' => $charge['StatementEntry']['customer_id'],
|
||||||
|
'lease_id' => null,
|
||||||
|
'comment' => $comment,
|
||||||
|
),
|
||||||
|
|
||||||
|
'Entry' => array());
|
||||||
|
|
||||||
|
foreach ($disb_entries['DisbursementEntry'] AS $disbursement) {
|
||||||
|
$rollback['Entry'][] =
|
||||||
|
array('type' => $disbursement['type'],
|
||||||
|
'amount' => -1 * $disbursement['amount'],
|
||||||
|
'account_id' => $disbursement['account_id'],
|
||||||
|
'customer_id' => $disbursement['customer_id'],
|
||||||
|
'lease_id' => $disbursement['lease_id'],
|
||||||
|
'charge_entry_id' => $disbursement['charge_entry_id'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the sole ledger entry for this transaction
|
||||||
|
$rollback['Entry'][] =
|
||||||
|
array('include_ledger_entry' => true,
|
||||||
|
'include_statement_entry' => false,
|
||||||
|
'type' => 'REVERSAL',
|
||||||
|
'amount' => $rollback['Transaction']['amount'],
|
||||||
|
//'account_id' => $this->Account->accountPayableAccountID(),
|
||||||
|
'account_id' => $this->Account->accountReceivableAccountID(),
|
||||||
|
'crdr' => 'CREDIT',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Record the transaction, which will un-disburse previously
|
||||||
|
// disbursed payments, and other similar work.
|
||||||
|
if (count($rollback['Entry'])) {
|
||||||
|
$rollback_result = $this->addTransaction($rollback['control'],
|
||||||
|
$rollback['Transaction'],
|
||||||
|
$rollback['Entry']);
|
||||||
|
$this->pr(20, compact('rollback', 'rollback_result'));
|
||||||
|
$ret['rollback'] = $rollback_result;
|
||||||
|
if ($rollback_result['error'])
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* $ret['nsf_transaction_id'] = $ret['bounce']['transaction_id']; */
|
||||||
|
/* if (!empty($ret['rollback'])) */
|
||||||
|
/* $ret['nsf_ledger_entry_id'] = $ret['rollback']['entries'][0]['DoubleEntry']['Entry1']['ledger_entry_id']; */
|
||||||
|
$ret = $ret['rollback'];
|
||||||
|
return $this->prReturn($ret + array('error' => false));
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
|
|||||||
Reference in New Issue
Block a user