Fixed bug when marking NSF of a tender that has only been used as a surplus and never applied to any charges. Modified the applyCredits algorithm to try and distinguish between surplus credits of a lease and general customer surplus. I don't know if it works completely, but I do know it creates an issue since a lease surplus can now never be utilized without additional lease charges, a refund (no yet implemented), or moving the surplus to the customer level (not intended to be implemented).

git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@483 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
abijah
2009-08-04 21:19:20 +00:00
parent 1afed6a6e0
commit 67280c89e7
5 changed files with 152 additions and 77 deletions

View File

@@ -178,17 +178,33 @@ class CustomersController extends AppController {
$this->redirect(array('action'=>'index')); $this->redirect(array('action'=>'index'));
} }
/* //$result = $this->Customer->securityDeposits($id); */ // Get details on this customer, its contacts and leases
/* $result = $this->Customer->excessPayments($id); */ $customer = $this->Customer->find
/* //$result = $this->Customer->unreconciledCharges($id); */ ('first', array
/* echo('<HR>'); */ ('contain' => array
/* pr($result); */ (// Models
/* $this->autoRender = false; */ 'Contact' =>
/* return; */ array('order' => array('Contact.display_name'),
// Models
'ContactPhone',
'ContactEmail',
'ContactAddress',
),
'Lease' =>
array('Unit' =>
array('order' => array('sort_order'),
'fields' => array('id', 'name'),
),
),
),
$customer = $this->Customer->details($id); 'conditions' => array('Customer.id' => $id),
));
//pr($customer); //pr($customer);
$outstanding_balance = $customer['stats']['balance'];
// Figure out the outstanding balances for this customer
$stats = $this->Customer->stats($id);
$outstanding_balance = $stats['balance'];
$outstanding_deposit = $this->Customer->securityDepositBalance($id); $outstanding_deposit = $this->Customer->securityDepositBalance($id);
// Figure out if this customer has any non-closed leases // Figure out if this customer has any non-closed leases
@@ -229,6 +245,11 @@ class CustomersController extends AppController {
$id)); $id));
} }
if ($outstanding_balance < 0)
$this->sidemenu_links[] =
array('name' => 'Issue Refund',
'url' => array('action' => 'refund', $id));
// Prepare to render. // Prepare to render.
$title = 'Customer: ' . $customer['Customer']['name']; $title = 'Customer: ' . $customer['Customer']['name'];
$this->set(compact('customer', 'title', $this->set(compact('customer', 'title',

View File

@@ -213,22 +213,38 @@ class LeasesController extends AppController {
} }
/* /\************************************************************************** */
/* ************************************************************************** */
/* ************************************************************************** */
/* * action: promote_credit */
/* * - Moves any lease credit up to the customer level, so that */
/* * it may be used for charges other than those on this lease. */
/* *\/ */
/* function promote_surplus($id) { */
/* $this->Lease->promoteSurplus($id); */
/* pr("PREVENTING REDIRECT"); */
/* $this->render('fake'); */
/* $this->redirect(array('controller' => 'leases', */
/* 'action' => 'view', */
/* $id)); */
/* } */
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
* action: apply_deposit * action: refund
* - Applies the security deposit to charges. This is much * - Provides lease customer with a refund
* like a receipt, but it's separated to keep it simple and
* to prevent feature overload on the receipt page.
*/ */
function apply_deposit($id) { function refund($id) {
$this->Lease->releaseSecurityDeposits($id); // Obtain the overall lease balance
pr("PREVENTING REDIRECT"); $stats = $this->Lease->stats($id);
$this->render('fake'); $outstanding_balance = $stats['balance'];
$this->redirect(array('controller' => 'leases',
'action' => 'view', $this->set(compact('lease', 'title',
$id)); 'outstanding_balance'));
} }
@@ -290,31 +306,6 @@ class LeasesController extends AppController {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* action: refund
* - Provides user with a refund
* REVISIT <AP>: 20090710
* Should this be a customer function?
*/
function refund($id) {
/* // Obtain the overall lease balance */
/* $stats = $this->Lease->stats($id); */
/* $outstanding_balance = $stats['balance']; */
/* // Determine the lease security deposit */
/* $deposits = $this->Lease->securityDeposits($id); */
/* $outstanding_deposit = $deposits['summary']['balance']; */
/* $this->set(compact('lease', 'title', */
/* 'outstanding_deposit', */
/* 'outstanding_balance')); */
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -435,19 +426,17 @@ class LeasesController extends AppController {
'action' => 'receipt', 'action' => 'receipt',
$lease['Customer']['id'])); $lease['Customer']['id']));
if (isset($lease['Lease']['moveout_date']) && $outstanding_deposit > 0 && $outstanding_balance > 0) /* if ($outstanding_balance < 0) */
$this->sidemenu_links[] = /* $this->sidemenu_links[] = */
array('name' => 'Apply Deposit', 'url' => array('action' => 'apply_deposit', /* array('name' => 'Transfer Credit to Customer', */
$id)); /* 'url' => array('action' => 'promote_surplus', $id)); */
if (isset($lease['Lease']['moveout_date']) && if ($outstanding_balance < 0)
$outstanding_balance <= 0 &&
($outstanding_deposit - $outstanding_balance) > 0)
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Issue Refund', 'url' => array('action' => 'refund', array('name' => 'Issue Refund',
$id)); 'url' => array('action' => 'refund', $id));
if (isset($lease['Lease']['moveout_date']) && $outstanding_deposit == 0 && $outstanding_balance > 0) if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0)
$this->sidemenu_links[] = $this->sidemenu_links[] =
array('name' => 'Write-Off', 'url' => array('action' => 'bad_debt', array('name' => 'Write-Off', 'url' => array('action' => 'bad_debt',
$id)); $id));

View File

@@ -48,6 +48,20 @@ class Lease extends AppModel {
$query['conditions'][] = array('StatementEntry.account_id' => $query['conditions'][] = array('StatementEntry.account_id' =>
$this->StatementEntry->Account->securityDepositAccountID()); $this->StatementEntry->Account->securityDepositAccountID());
// REVISIT <AP>: 20090804
// Dilemma... how to handle security deposits used to pay
// charges on the lease, yet are not part of the lease
// security deposit(s)? For example, Lease A & Lease B,
// each with $25 Sec. Dep. Move out of Lease A, and
// promote the lease surplus to the customer. A new
// charge on Lease B for $15, which is assigned $15/$25
// from the promoted Lease A surplus. They way this
// function works at present, it will presume the $15 is
// part of the security deposit balance, and will end up
// calculating it as only $10, which is wrong. Perhaps
// the fix is to release security deposits into some sort
// of income account.
$stats = $this->StatementEntry->stats(null, $query); $stats = $this->StatementEntry->stats(null, $query);
return $this->prReturn($stats['account_balance']); return $this->prReturn($stats['account_balance']);
} }
@@ -450,18 +464,6 @@ class Lease extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addCharge
* - Adds an additional charge to the lease
*/
function addCharge($id, $charge) {
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************

View File

@@ -22,7 +22,7 @@ class StatementEntry extends AppModel {
); );
//var $default_log_level = array('log' => 30, 'show' => 15); var $default_log_level = array('log' => 30, 'show' => 15);
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
@@ -380,12 +380,15 @@ OPTION 2
$charge_ids = null, $payment_type = null, $charge_ids = null, $payment_type = null,
$customer_id = null, $lease_id = null) $customer_id = null, $lease_id = null)
{ {
//$this->prFunctionLevel(25); $this->prFunctionLevel(25);
$this->prEnter(compact('query', 'receipt_id', $this->prEnter(compact('query', 'receipt_id',
'charge_ids', 'payment_type', 'charge_ids', 'payment_type',
'customer_id', 'lease_id')); 'customer_id', 'lease_id'));
$this->queryInit($query); $this->queryInit($query);
if (!empty($customer_id))
$query['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
if (empty($payment_type)) if (empty($payment_type))
$payment_type = 'PAYMENT'; $payment_type = 'PAYMENT';
@@ -394,6 +397,22 @@ OPTION 2
// First, find all known credits // First, find all known credits
$lquery = $query; $lquery = $query;
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS'); $lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
// REVISIT <AP>: 20090804
// We need to ensure that we're using surplus credits ONLY from either
// the given lease, or those that do not apply to any specific lease.
// However, by doing this, it forces any lease surplus amounts to
// remain frozen with that lease until either there is a lease charge,
// we refund the money, or we "promote" that surplus to the customer
// level and out of the leases direct control.
// That seems like a pain. Perhaps we should allow any customer
// surplus to be used on any customer charge.
$lquery['conditions'][] =
array('OR' =>
array(array('StatementEntry.lease_id' => null),
(!empty($lease_id)
? array('StatementEntry.lease_id' => $lease_id)
: array()),
));
$lquery['order'][] = 'StatementEntry.effective_date ASC'; $lquery['order'][] = 'StatementEntry.effective_date ASC';
$credits = $this->find('all', $lquery); $credits = $this->find('all', $lquery);
$this->pr(18, compact('credits'), $this->pr(18, compact('credits'),
@@ -403,6 +422,7 @@ OPTION 2
$receipt_credit = null; $receipt_credit = null;
if (!empty($receipt_id)) { if (!empty($receipt_id)) {
$lquery = $query; $lquery = $query;
$lquery['link'] = array('StatementEntry' => $lquery['link']);
$lquery['link'] += array('LedgerEntry' => $lquery['link'] += array('LedgerEntry' =>
array('conditions' => array('conditions' =>
//array(LedgerEntry.'crdr'=>'DEBIT'), //array(LedgerEntry.'crdr'=>'DEBIT'),
@@ -429,6 +449,9 @@ OPTION 2
'conditions' => array('StatementEntry.id' => $charge_ids)); 'conditions' => array('StatementEntry.id' => $charge_ids));
} else { } else {
$lquery = $query; $lquery = $query;
// If we're working with a specific lease, then limit charges to it
if (!empty($lease_id))
$lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id);
} }
$lquery['order'] = 'StatementEntry.effective_date ASC'; $lquery['order'] = 'StatementEntry.effective_date ASC';
$charges = $this->reconciledSet('CHARGE', $lquery, true); $charges = $this->reconciledSet('CHARGE', $lquery, true);

View File

@@ -246,6 +246,44 @@ class Transaction extends AppModel {
} }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addRefund
* - Adds a new refund transaction
*/
function addRefund($data, $customer_id, $lease_id = null) {
$this->prEnter(compact('data', 'customer_id', 'lease_id'));
// REVISIT <AP>: 20090804
// NOT IMPLEMENTED AT ALL. Just cut and paste so far
return array('error' => true);
// Establish the transaction as an refund
$refund =& $data['Transaction'];
$refund +=
array('type' => 'VOUCHER',
'crdr' => 'DEBIT',
'account_id' => $this->Account->accountReceivableAccountID(),
'customer_id' => $customer_id,
'lease_id' => $lease_id,
);
// Go through the statement entries and flag as charges
foreach ($data['Entry'] AS &$entry)
$entry += array('type' => 'CHARGE',
'crdr' => 'CREDIT',
);
$ids = $this->addTransaction($data['Transaction'], $data['Entry']);
if (isset($ids['transaction_id']))
$ids['refund_id'] = $ids['transaction_id'];
return $this->prReturn($ids);
}
/************************************************************************** /**************************************************************************
************************************************************************** **************************************************************************
************************************************************************** **************************************************************************
@@ -511,8 +549,7 @@ class Transaction extends AppModel {
$transaction['type'] == 'RECEIPT') && $transaction['type'] == 'RECEIPT') &&
$subtype !== 'NSF' && !$ret['error']) { $subtype !== 'NSF' && !$ret['error']) {
$result = $this->StatementEntry->assignCredits $result = $this->StatementEntry->assignCredits
(array('link' => array('Customer'), (null,
'conditions' => array('Customer.id' => $transaction['customer_id'])),
($transaction['type'] == 'RECEIPT' ($transaction['type'] == 'RECEIPT'
? $ret['transaction_id'] ? $ret['transaction_id']
: null), : null),
@@ -621,11 +658,13 @@ class Transaction extends AppModel {
// 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.
$rollback_result = $this->addTransaction($rollback['Transaction'], $rollback['Entry'], 'NSF'); if (count($rollback['Entry'])) {
$this->pr(20, compact('rollback', 'rollback_result')); $rollback_result = $this->addTransaction($rollback['Transaction'], $rollback['Entry'], 'NSF');
$ret['rollback'] = $rollback_result; $this->pr(20, compact('rollback', 'rollback_result'));
if ($rollback_result['error']) $ret['rollback'] = $rollback_result;
return $this->prReturn(array('error' => true) + $ret); if ($rollback_result['error'])
return $this->prReturn(array('error' => true) + $ret);
}
// Add NSF Charge // Add NSF Charge
$charge_result = $this->addInvoice $charge_result = $this->addInvoice
@@ -651,7 +690,8 @@ class Transaction extends AppModel {
return $this->prReturn(array('error' => true) + $ret); return $this->prReturn(array('error' => true) + $ret);
$ret['nsf_transaction_id'] = $ret['bounce']['transaction_id']; $ret['nsf_transaction_id'] = $ret['bounce']['transaction_id'];
$ret['nsf_ledger_entry_id'] = $ret['rollback']['entries'][0]['DoubleEntry']['Entry1']['ledger_entry_id']; if (!empty($ret['rollback']))
$ret['nsf_ledger_entry_id'] = $ret['rollback']['entries'][0]['DoubleEntry']['Entry1']['ledger_entry_id'];
return $this->prReturn($ret + array('error' => false)); return $this->prReturn($ret + array('error' => false));
} }