git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1019 97e9348a-65ac-dc4b-aefc-98561f571b83
853 lines
30 KiB
PHP
853 lines
30 KiB
PHP
<?php
|
|
class Lease extends AppModel {
|
|
|
|
var $belongsTo = array(
|
|
'LeaseType',
|
|
'Unit',
|
|
'Customer',
|
|
'LateSchedule',
|
|
);
|
|
|
|
var $hasMany = array(
|
|
'StatementEntry',
|
|
);
|
|
|
|
//var $default_log_level = array('log' => 30, 'show' => 30);
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: securityDeposits
|
|
* - Returns an array of security deposit entries
|
|
*/
|
|
function securityDeposits($id, $query = null) {
|
|
$this->prEnter(compact('id', 'query'));
|
|
$this->queryInit($query);
|
|
|
|
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
|
$query['conditions'][] = array('StatementEntry.account_id' =>
|
|
$this->StatementEntry->Account->securityDepositAccountID());
|
|
|
|
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
|
return $this->prReturn($set);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: securityDepositBalance
|
|
* - Returns the balance of the lease security deposit(s)
|
|
*/
|
|
|
|
function securityDepositBalance($id, $query = null) {
|
|
$this->prEnter(compact('id', 'query'));
|
|
$this->queryInit($query);
|
|
|
|
// REVISIT <AP>: 20090807
|
|
// Let's try simplifying the security deposit issue.
|
|
// Presume that security deposits are NOT used at all,
|
|
// until the customer moves out of the unit. At that
|
|
// time, the ENTIRE deposit is converted to customer
|
|
// credit. Piece of cake.
|
|
// For more information, see file revision history,
|
|
// including the revision just before this, r503.
|
|
|
|
$this->id = $id;
|
|
$moveout_date = $this->field('moveout_date');
|
|
if (!empty($moveout_date))
|
|
return $this->prReturn(0);
|
|
|
|
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
|
$query['conditions'][] = array('StatementEntry.account_id' =>
|
|
$this->StatementEntry->Account->securityDepositAccountID());
|
|
|
|
$stats = $this->StatementEntry->stats(null, $query);
|
|
return $this->prReturn($stats['Charge']['disbursement']);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: releaseSecurityDeposits
|
|
* - Releases all security deposits associated with this lease.
|
|
* That simply makes a disbursement out of them, which can be used
|
|
* to pay outstanding customer charges, or simply to become
|
|
* a customer surplus (customer credit).
|
|
*/
|
|
function releaseSecurityDeposits($id, $stamp = null, $query = null) {
|
|
//$this->prFunctionLevel(30);
|
|
$this->prEnter(compact('id', 'stamp', 'query'));
|
|
|
|
$secdeps = $this->securityDeposits($id, $query);
|
|
$secdeps = $secdeps['entries'];
|
|
$this->pr(20, compact('secdeps'));
|
|
|
|
// If there are no paid security deposits, then
|
|
// we can consider all security deposits released.
|
|
if (count($secdeps) == 0)
|
|
return $this->prReturn(true);
|
|
|
|
// Build a transaction
|
|
$release = array('Transaction' => array(), 'Entry' => array());
|
|
$release['Transaction']['stamp'] = $stamp;
|
|
$release['Transaction']['comment'] = "Security Deposit Release";
|
|
foreach ($secdeps AS $charge) {
|
|
if ($charge['StatementEntry']['type'] !== 'CHARGE')
|
|
die("INTERNAL ERROR: SECURITY DEPOSIT IS NOT CHARGE");
|
|
|
|
// Since security deposits are being released, this also means
|
|
// any unpaid (or only partially paid) security deposit should
|
|
// have the remaining balance reversed.
|
|
if ($charge['StatementEntry']['balance'] > 0)
|
|
$this->StatementEntry->reverse($charge['StatementEntry']['id'], true, $stamp);
|
|
|
|
$release['Entry'][] =
|
|
array('amount' => $charge['StatementEntry']['reconciled'],
|
|
'account_id' => $this->StatementEntry->Account->securityDepositAccountID(),
|
|
'comment' => "Released Security Deposit",
|
|
);
|
|
}
|
|
|
|
$customer_id = $secdeps[0]['StatementEntry']['customer_id'];
|
|
$lease_id = $secdeps[0]['StatementEntry']['lease_id'];
|
|
|
|
// Add receipt of the security deposit funds. Do NOT
|
|
// flag them as part of the lease, as all received funds
|
|
// are only associated with the customer, for future
|
|
// (or present) disbursement on any lease.
|
|
$result = $this->StatementEntry->Transaction->addReceipt
|
|
($release, $customer_id, null);
|
|
|
|
return $this->prReturn($result);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: rentLastCharges
|
|
* - Returns a list of rent charges from this lease that
|
|
* do not have sequential followup charges. Under normal
|
|
* circumstances, there would only be one entry, which is
|
|
* the most recent rent charge. However, it's possible
|
|
* that there are several, indicating a problem with lease.
|
|
*/
|
|
|
|
function rentLastCharges($id) {
|
|
$this->prEnter(compact('id'));
|
|
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
|
|
$entries = $this->find
|
|
('all',
|
|
array('link' =>
|
|
array(// Models
|
|
'StatementEntry',
|
|
|
|
'SEx' =>
|
|
array('class' => 'StatementEntry',
|
|
'fields' => array(),
|
|
'conditions' => array
|
|
('SEx.lease_id = StatementEntry.lease_id',
|
|
'SEx.type' => 'CHARGE',
|
|
'SEx.account_id' => $rent_account_id,
|
|
'SEx.reverse_transaction_id IS NULL',
|
|
'SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
|
|
),
|
|
),
|
|
),
|
|
|
|
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
|
'fields' => array(),
|
|
'conditions' => array(array('Lease.id' => $id),
|
|
array('StatementEntry.type' => 'CHARGE'),
|
|
array('StatementEntry.account_id' => $rent_account_id),
|
|
array('StatementEntry.reverse_transaction_id IS NULL'),
|
|
array('SEx.id' => null),
|
|
),
|
|
)
|
|
);
|
|
|
|
return $this->prReturn($entries);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: lateCharges
|
|
* - Returns a list of late charges from this lease
|
|
*/
|
|
|
|
function lateCharges($id) {
|
|
$this->prEnter(compact('id'));
|
|
$late_account_id = $this->StatementEntry->Account->lateChargeAccountID();
|
|
$entries = $this->StatementEntry->find
|
|
('all',
|
|
array('link' =>
|
|
array(// Models
|
|
'Lease',
|
|
),
|
|
|
|
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
|
'conditions' => array(array('Lease.id' => $id),
|
|
array('StatementEntry.type' => 'CHARGE'),
|
|
array('StatementEntry.account_id' => $late_account_id),
|
|
),
|
|
)
|
|
);
|
|
|
|
return $this->prReturn($entries);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: rentChargeGaps
|
|
* - Checks for gaps in rent charges
|
|
*/
|
|
|
|
function rentChargeGaps($id) {
|
|
$this->prEnter(compact('id'));
|
|
$entries = $this->rentLastCharges($id);
|
|
if ($entries && count($entries) > 1)
|
|
return $this->prReturn(true);
|
|
return $this->prReturn(false);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: rentChargeThrough
|
|
* - Determines the date that rent has been charged through
|
|
* Returns one of:
|
|
* null: There are gaps in the charges
|
|
* false: There are not yet any charges
|
|
* date: The date rent has been charged through
|
|
*/
|
|
|
|
function rentChargeThrough($id) {
|
|
$this->prEnter(compact('id'));
|
|
$entries = $this->rentLastCharges($id);
|
|
if (!$entries)
|
|
return $this->prReturn(false);
|
|
if (count($entries) != 1)
|
|
return $this->prReturn(null);
|
|
return $this->prReturn($entries[0]['StatementEntry']['through_date']);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: rentPaidThrough
|
|
* - Determines the date of the first unpaid rent
|
|
*/
|
|
|
|
function rentPaidThrough($id) {
|
|
$this->prEnter(compact('id'));
|
|
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
|
|
|
|
// First, see if we can find any unpaid entries. Of course,
|
|
// the first unpaid entry gives us a very direct indication
|
|
// of when the customer is paid up through, which is 1 day
|
|
// prior to the effective date of that first unpaid charge.
|
|
$rent = $this->StatementEntry->reconciledSet
|
|
('CHARGE',
|
|
array('fields' =>
|
|
array('StatementEntry.*',
|
|
'DATE_SUB(StatementEntry.effective_date, INTERVAL 1 DAY) AS paid_through',
|
|
),
|
|
|
|
'conditions' =>
|
|
array(array('StatementEntry.lease_id' => $id),
|
|
array('StatementEntry.account_id' => $rent_account_id),
|
|
array('StatementEntry.reverse_transaction_id IS NULL'),
|
|
),
|
|
|
|
'order' => array('StatementEntry.effective_date'),
|
|
),
|
|
true);
|
|
$this->pr(20, $rent, "Unpaid rent");
|
|
|
|
if ($rent['entries'])
|
|
return $this->prReturn($rent['entries'][0]['StatementEntry']['paid_through']);
|
|
|
|
|
|
// If we don't have any unpaid charges (great!), then the
|
|
// customer is paid up through the last day of the last
|
|
// charge. So, search for paid charges, which already
|
|
// have the paid through date saved as part of the entry.
|
|
$rent = $this->StatementEntry->reconciledSet
|
|
('CHARGE',
|
|
array('conditions' =>
|
|
array(array('StatementEntry.lease_id' => $id),
|
|
array('StatementEntry.account_id' => $rent_account_id),
|
|
array('StatementEntry.reverse_transaction_id IS NULL'),
|
|
),
|
|
|
|
'order' => array('StatementEntry.through_date DESC'),
|
|
),
|
|
false);
|
|
$this->pr(20, $rent, "Paid rent");
|
|
|
|
if ($rent['entries'])
|
|
return $this->prReturn($rent['entries'][0]['StatementEntry']['through_date']);
|
|
|
|
|
|
// After all that, having found that there are no unpaid
|
|
// charges, and in fact, no paid charges either, we cannot
|
|
// possibly say when the customer is paid through.
|
|
return $this->prReturn(null);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: assessMonthlyRent
|
|
* - Charges rent for the month, if not already charged.
|
|
*/
|
|
|
|
function assessMonthlyRent($id, $date = null) {
|
|
$this->prEnter(compact('id', 'date'));
|
|
$this->id = $id;
|
|
|
|
if (empty($date))
|
|
$date = time();
|
|
|
|
if (is_string($date))
|
|
$date = strtotime($date);
|
|
|
|
// REVISIT <AP>: 20090808
|
|
// Anniversary Billing not supported
|
|
$anniversary = 0 && $this->field('anniversary_billing');
|
|
if (empty($anniversary)) {
|
|
$date_parts = getdate($date);
|
|
$date = mktime(0, 0, 0, $date_parts['mon'], 1, $date_parts['year']);
|
|
}
|
|
|
|
// Make sure we're not trying to assess rent on a closed lease
|
|
$close_date = $this->field('close_date');
|
|
$this->pr(17, compact('close_date'));
|
|
if (!empty($close_date))
|
|
return $this->prReturn(null);
|
|
|
|
// Don't assess rent after customer has moved out
|
|
$moveout_date = $this->field('moveout_date');
|
|
$this->pr(17, compact('moveout_date'));
|
|
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
|
return $this->prReturn(null);
|
|
|
|
// Determine when the customer has already been charged through
|
|
// and, of course, don't charge them if they've already been.
|
|
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
|
$this->pr(17, compact('date', 'charge_through_date')
|
|
+ array('date_str' => date('Y-m-d', $date),
|
|
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
|
|
if (!$charge_through_date)
|
|
return $this->prReturn(null);
|
|
if ($charge_through_date >= $date)
|
|
return $this->prReturn(null);
|
|
|
|
// OK, it seems we're going to go ahead and charge the customer
|
|
// on this lease. Calculate the new charge through date, which
|
|
// is 1 day shy of 1 month from $date. For example, if we're
|
|
// charging for 8/1/09, charge through will be 8/31/09, and
|
|
// charging for 8/15/09, charge through will be 9/14/09.
|
|
$date_parts = getdate($date);
|
|
$charge_through_date = mktime(0, 0, 0,
|
|
$date_parts['mon']+1,
|
|
$date_parts['mday']-1,
|
|
$date_parts['year']);
|
|
|
|
// Build the invoice transaction
|
|
$invoice = array('Transaction' => array(), 'Entry' => array());
|
|
// REVISIT <AP>: 20090808
|
|
// Keeping Transaction.stamp until the existing facility
|
|
// is up to date. Then we want the stamp to be now()
|
|
// (and so can just delete the next line).
|
|
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
|
$invoice['Entry'][] =
|
|
array('effective_date' => date('Y-m-d', $date),
|
|
'through_date' => date('Y-m-d', $charge_through_date),
|
|
'amount' => $this->field('rent'),
|
|
'account_id' => $this->StatementEntry->Account->rentAccountId(),
|
|
);
|
|
|
|
// Record the invoice and return the result
|
|
$this->pr(21, compact('invoice'));
|
|
$result = $this->StatementEntry->Transaction->addInvoice
|
|
($invoice, null, $id);
|
|
return $this->prReturn($result);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: assessMonthlyRentAll
|
|
* - Ensures rent has been charged on all open leases
|
|
*/
|
|
|
|
function assessMonthlyRentAll($date = null) {
|
|
$this->prEnter(compact('date'));
|
|
$leases = $this->find
|
|
('all', array('contain' => false,
|
|
'conditions' => array('Lease.close_date' => null),
|
|
));
|
|
|
|
$ret = array('Lease' => array());
|
|
foreach ($leases AS $lease) {
|
|
$result = $this->assessMonthlyRent($lease['Lease']['id'], $date);
|
|
$ret['Lease'][$lease['Lease']['id']] = $result;
|
|
if ($result['error'])
|
|
$ret['error'] = true;
|
|
}
|
|
return $this->prReturn($ret + array('error' => false));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: assessMonthlyLate
|
|
* - Assess late charges for the month, if not already charged.
|
|
*/
|
|
|
|
function assessMonthlyLate($id, $date = null) {
|
|
$this->prEnter(compact('id', 'date'));
|
|
$this->id = $id;
|
|
|
|
if (empty($date))
|
|
$date = time();
|
|
|
|
if (is_string($date))
|
|
$date = strtotime($date);
|
|
|
|
// REVISIT <AP>: 20090808
|
|
// Anniversary Billing not supported
|
|
$anniversary = 0 && $this->field('anniversary_billing');
|
|
if (empty($anniversary)) {
|
|
$date_parts = getdate($date);
|
|
$date = mktime(0, 0, 0, $date_parts['mon'], 11, $date_parts['year']);
|
|
}
|
|
|
|
// Don't assess a late charge if the late charge date hasn't
|
|
// even come yet. This is questionable whether we really
|
|
// should restrict, since the user could know what they're
|
|
// doing, and/or the server clock could be off (although that
|
|
// would certainly have much larger ramifications). But, the
|
|
// fact is that this check likely handles the vast majority
|
|
// of the expected behavior, and presents an issue for very
|
|
// few users, if any at all.
|
|
if ($date > time())
|
|
return $this->prReturn(null);
|
|
|
|
// Make sure we're not trying to assess late charges on a closed lease
|
|
$close_date = $this->field('close_date');
|
|
$this->pr(17, compact('close_date'));
|
|
if (!empty($close_date))
|
|
return $this->prReturn(null);
|
|
|
|
// Don't assess late charges after customer has moved out
|
|
$moveout_date = $this->field('moveout_date');
|
|
$this->pr(17, compact('moveout_date'));
|
|
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
|
return $this->prReturn(null);
|
|
|
|
// Determine when the customer has been charged through for rent
|
|
// and don't mark them as late if they haven't even been charged rent
|
|
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
|
$this->pr(17, compact('date', 'charge_through_date')
|
|
+ array('date_str' => date('Y-m-d', $date),
|
|
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
|
|
if ($charge_through_date <= $date)
|
|
return $this->prReturn(null);
|
|
|
|
// Determine if the customer is actually late. This is based on
|
|
// when they've paid through, plus 10 days before they're late.
|
|
// REVISIT <AP>: 20090813
|
|
// Of course, 10 days is a terrible hardcode. This should be
|
|
// driven from the late schedule, saved as part of the lease
|
|
// (when finally implemented).
|
|
$paid_through_date = strtotime($this->rentPaidThrough($id));
|
|
$this->pr(17, compact('date', 'paid_through_date')
|
|
+ array('date_str' => date('Y-m-d', $date),
|
|
'paid_through_date_str' => date('Y-m-d', $paid_through_date)));
|
|
$date_parts = getdate($paid_through_date);
|
|
$paid_through_date = mktime(0, 0, 0, $date_parts['mon'], $date_parts['mday']+10, $date_parts['year']);
|
|
if ($paid_through_date >= $date)
|
|
return $this->prReturn(null);
|
|
|
|
// Determine if the customer has already been charged a late fee
|
|
// and, of course, don't charge them if they've already been.
|
|
$late_charges = $this->lateCharges($id);
|
|
foreach ($late_charges AS $late) {
|
|
if (strtotime($late['StatementEntry']['effective_date']) == $date)
|
|
return $this->prReturn(null);
|
|
}
|
|
|
|
// Build the invoice transaction
|
|
$invoice = array('Transaction' => array(), 'Entry' => array());
|
|
// REVISIT <AP>: 20090808
|
|
// Keeping Transaction.stamp until the existing facility
|
|
// is up to date. Then we want the stamp to be now()
|
|
// (and so can just delete the next line).
|
|
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
|
$invoice['Entry'][] =
|
|
array('effective_date' => date('Y-m-d', $date),
|
|
'amount' => 10,
|
|
'account_id' => $this->StatementEntry->Account->lateChargeAccountId(),
|
|
);
|
|
|
|
// Record the invoice and return the result
|
|
$this->pr(21, compact('invoice'));
|
|
$result = $this->StatementEntry->Transaction->addInvoice
|
|
($invoice, null, $id);
|
|
return $this->prReturn($result);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: assessMonthlyLateAll
|
|
* - Ensures rent has been charged on all open leases
|
|
*/
|
|
|
|
function assessMonthlyLateAll($date = null) {
|
|
$this->prEnter(compact('date'));
|
|
$leases = $this->find
|
|
('all', array('contain' => false,
|
|
'conditions' => array('Lease.close_date' => null),
|
|
));
|
|
|
|
$ret = array('Lease' => array());
|
|
foreach ($leases AS $lease) {
|
|
$result = $this->assessMonthlyLate($lease['Lease']['id'], $date);
|
|
$ret['Lease'][$lease['Lease']['id']] = $result;
|
|
if ($result['error'])
|
|
$ret['error'] = true;
|
|
}
|
|
return $this->prReturn($ret + array('error' => false));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* functions: delinquency
|
|
* - SQL fragments to determine whether a lease is delinquent
|
|
*/
|
|
|
|
function conditionDelinquent($table_name = 'Lease') {
|
|
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
|
return ("({$t}close_date IS NULL AND" .
|
|
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 1 DAY))");
|
|
}
|
|
|
|
function delinquentDaysSQL($table_name = 'Lease') {
|
|
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
|
return ("IF(" . $this->conditionDelinquent($table_name) . "," .
|
|
" DATEDIFF(NOW(), {$t}paid_through_date)-1," .
|
|
" NULL)");
|
|
}
|
|
|
|
function delinquentField($table_name = 'Lease') {
|
|
return ($this->delinquentDaysSQL($table_name) . " AS 'delinquent'");
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: moveIn
|
|
* - Moves the specified customer into the specified lease
|
|
*/
|
|
|
|
function moveIn($customer_id, $unit_id,
|
|
$deposit = null, $rent = null,
|
|
$stamp = null, $comment = null)
|
|
{
|
|
$this->prEnter(compact('customer_id', 'unit_id',
|
|
'deposit', 'rent', 'stamp', 'comment'));
|
|
|
|
$lt = $this->LeaseType->find('first',
|
|
array('conditions' =>
|
|
array('code' => 'SL')));
|
|
|
|
// Use NOW if not given a movein date
|
|
if (!isset($stamp))
|
|
$stamp = date('Y-m-d G:i:s');
|
|
|
|
if (!$comment)
|
|
$comment = null;
|
|
|
|
if (!isset($deposit) || !isset($rent)) {
|
|
$rates = $this->Unit->find
|
|
('first',
|
|
array('contain' =>
|
|
array('UnitSize' =>
|
|
array('deposit', 'rent'),
|
|
),
|
|
'fields' => array('deposit', 'rent'),
|
|
'conditions' => array('Unit.id' => $unit_id),
|
|
));
|
|
|
|
$deposit =
|
|
(isset($deposit)
|
|
? $deposit
|
|
: (isset($rates['Unit']['deposit'])
|
|
? $rates['Unit']['deposit']
|
|
: (isset($rates['UnitSize']['deposit'])
|
|
? $rates['UnitSize']['deposit']
|
|
: 0)));
|
|
|
|
$rent =
|
|
(isset($rent)
|
|
? $rent
|
|
: (isset($rates['Unit']['rent'])
|
|
? $rates['Unit']['rent']
|
|
: (isset($rates['UnitSize']['rent'])
|
|
? $rates['UnitSize']['rent']
|
|
: 0)));
|
|
}
|
|
|
|
|
|
// Save this new lease.
|
|
$this->create();
|
|
if (!$this->save(array('lease_type_id' => $lt['LeaseType']['id'],
|
|
'unit_id' => $unit_id,
|
|
'customer_id' => $customer_id,
|
|
'lease_date' => $stamp,
|
|
'movein_date' => $stamp,
|
|
'deposit' => $deposit,
|
|
'rent' => $rent,
|
|
'comment' => $comment), false)) {
|
|
return $this->prReturn(null);
|
|
}
|
|
|
|
// Set the lease number to be the same as the lease ID
|
|
$this->id;
|
|
$this->saveField('number', $this->id);
|
|
|
|
// Update the current lease count for the customer
|
|
$this->Customer->updateLeaseCount($customer_id);
|
|
|
|
// Update the unit status
|
|
$this->Unit->updateStatus($unit_id, 'OCCUPIED');
|
|
|
|
// REVISIT <AP>: 20090702
|
|
// We need to assess the security deposit charge,
|
|
// and probably rent as well. Rent, however, will
|
|
// require user parameters to indicate whether it
|
|
// was waived, pro-rated, etc.
|
|
|
|
// Return the new lease ID
|
|
return $this->prReturn($this->id);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: moveOut
|
|
* - Moves the customer out of the specified lease
|
|
*/
|
|
|
|
function moveOut($id, $status = 'VACANT',
|
|
$stamp = null, $close = true)
|
|
{
|
|
$this->prEnter(compact('id', 'status', 'stamp', 'close'));
|
|
|
|
// Use NOW if not given a moveout date
|
|
if (!isset($stamp))
|
|
$stamp = date('Y-m-d G:i:s');
|
|
|
|
// Reset the data
|
|
$this->create();
|
|
$this->id = $id;
|
|
|
|
// Set the customer move-out date
|
|
$this->data['Lease']['moveout_date'] = $stamp;
|
|
|
|
// Save it!
|
|
$this->save($this->data, false);
|
|
|
|
// Release the security deposit(s)
|
|
$this->releaseSecurityDeposits($id, $stamp);
|
|
|
|
// Close the lease, if so requested
|
|
if ($close)
|
|
$this->close($id, $stamp);
|
|
|
|
// Update the current lease count for the customer
|
|
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
|
|
|
// Finally, update the unit status
|
|
$this->recursive = -1;
|
|
$this->read();
|
|
$this->Unit->updateStatus($this->data['Lease']['unit_id'], $status);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: close
|
|
* - Closes the lease to further action
|
|
*/
|
|
|
|
function close($id, $stamp = null) {
|
|
$this->prEnter(compact('id', 'stamp'));
|
|
|
|
if (!$this->closeable($id))
|
|
return $this->prReturn(false);
|
|
|
|
// Reset the data
|
|
$this->create();
|
|
$this->id = $id;
|
|
|
|
// Use NOW if not given a moveout date
|
|
if (!isset($stamp))
|
|
$stamp = date('Y-m-d G:i:s');
|
|
|
|
// Set the close date
|
|
$this->data['Lease']['close_date'] = $stamp;
|
|
|
|
// Save it!
|
|
$this->save($this->data, false);
|
|
|
|
// Update the current lease count for the customer
|
|
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
|
|
|
return $this->prReturn(true);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: closeable
|
|
* - Indicates whether or not the lease can be closed
|
|
*/
|
|
|
|
function closeable($id) {
|
|
$this->prEnter(compact('id'));
|
|
|
|
$this->recursive = -1;
|
|
$this->read(null, $id);
|
|
|
|
// We can't close a lease that's still in use
|
|
if (!isset($this->data['Lease']['moveout_date']))
|
|
return $this->prReturn(false);
|
|
|
|
// We can't close a lease that's already closed
|
|
if (isset($this->data['Lease']['close_date']))
|
|
return $this->prReturn(false);
|
|
|
|
// A lease can only be closed if there are no outstanding
|
|
// security deposits ...
|
|
if ($this->securityDepositBalance($id) != 0)
|
|
return $this->prReturn(false);
|
|
|
|
// ... and if the account balance is zero.
|
|
if ($this->balance($id) != 0)
|
|
return $this->prReturn(false);
|
|
|
|
// Apparently this lease meets all the criteria!
|
|
return $this->prReturn(true);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: refund
|
|
* - Marks any lease balance as payable to the customer.
|
|
*/
|
|
|
|
function refund($id, $stamp = null) {
|
|
$this->prEnter(compact('id'));
|
|
$balance = $this->balance($id);
|
|
|
|
if ($balance >= 0)
|
|
return $this->prReturn(array('error' => true));
|
|
|
|
$balance *= -1;
|
|
|
|
// Build a transaction
|
|
$refund = array('Transaction' => array(), 'Entry' => array());
|
|
$refund['Transaction']['stamp'] = $stamp;
|
|
$refund['Transaction']['comment'] = "Lease Refund";
|
|
|
|
$refund['Entry'][] =
|
|
array('amount' => $balance);
|
|
|
|
$result = $this->StatementEntry->Transaction->addRefund
|
|
($refund, null, $id);
|
|
|
|
return $this->prReturn($result);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: update
|
|
* - Update any cached or calculated fields
|
|
*/
|
|
function update($id) {
|
|
$this->prEnter(compact('id'));
|
|
|
|
$this->id = $id;
|
|
$this->saveField('charge_through_date', $this->rentChargeThrough($id));
|
|
$this->saveField('paid_through_date', $this->rentPaidThrough($id));
|
|
|
|
$moveout = $this->field('moveout_date');
|
|
if (empty($moveout))
|
|
$this->Unit->update($this->field('unit_id'));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: balance
|
|
* - Returns the balance of money owed on the lease
|
|
*/
|
|
|
|
function balance($id) {
|
|
$this->prEnter(compact('id'));
|
|
$stats = $this->stats($id);
|
|
return $this->prReturn($stats['balance']);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: stats
|
|
* - Returns summary data from the requested lease.
|
|
*/
|
|
|
|
function stats($id = null, $query = null) {
|
|
$this->prEnter(compact('id', 'query'));
|
|
if (!$id)
|
|
return $this->prReturn(null);
|
|
|
|
$find_stats = $this->StatementEntry->find
|
|
('first', array
|
|
('contain' => false,
|
|
'fields' => $this->StatementEntry->chargeDisbursementFields(true),
|
|
'conditions' => array('StatementEntry.lease_id' => $id),
|
|
));
|
|
$find_stats = $find_stats[0];
|
|
return $this->prReturn($find_stats);
|
|
}
|
|
|
|
}
|
|
?>
|