git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@392 97e9348a-65ac-dc4b-aefc-98561f571b83
403 lines
14 KiB
PHP
403 lines
14 KiB
PHP
<?php
|
|
class Customer extends AppModel {
|
|
|
|
var $name = 'Customer';
|
|
var $validate = array(
|
|
'id' => array('numeric'),
|
|
'name' => array('notempty'),
|
|
);
|
|
|
|
var $belongsTo = array(
|
|
'PrimaryContact' => array(
|
|
'className' => 'Contact',
|
|
),
|
|
);
|
|
|
|
var $hasMany = array(
|
|
'CurrentLease' => array(
|
|
'className' => 'Lease',
|
|
'conditions' => 'CurrentLease.close_date IS NULL',
|
|
),
|
|
'Lease',
|
|
'StatementEntry',
|
|
'ContactsCustomer',
|
|
|
|
'Transaction',
|
|
);
|
|
|
|
var $hasAndBelongsToMany = array(
|
|
'Contact',
|
|
);
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: accountId
|
|
* - Returns the account ID for the given customer
|
|
*/
|
|
function accountId($id) {
|
|
$this->cacheQueries = true;
|
|
$customer = $this->find('first',
|
|
array('contain' => false,
|
|
'fields' => array('account_id'),
|
|
'conditions' => array(array('Customer.id' => $id))));
|
|
$this->cacheQueries = false;
|
|
|
|
return $customer['Customer']['account_id'];
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: leaseIds
|
|
* - Returns the lease IDs for the given customer
|
|
*/
|
|
function leaseIds($id) {
|
|
$this->cacheQueries = true;
|
|
$customer = $this->find('first',
|
|
array('contain' =>
|
|
array('Lease' => array('fields' => array('id'))),
|
|
'fields' => array(),
|
|
'conditions' => array(array('Customer.id' => $id))));
|
|
$this->cacheQueries = false;
|
|
|
|
$ids = array();
|
|
foreach ($customer['Lease'] AS $lease)
|
|
$ids[] = $lease['id'];
|
|
|
|
return $ids;
|
|
}
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: securityDeposits
|
|
* - Returns an array of security deposit entries
|
|
*/
|
|
function securityDeposits($id, $query = null) {
|
|
$this->queryInit($query);
|
|
|
|
$A = new Account();
|
|
|
|
if (!isset($query['link']['Customer']))
|
|
$query['link']['Customer'] = array();
|
|
if (!isset($query['link']['Customer']['fields']))
|
|
$query['link']['Customer']['fields'] = array();
|
|
|
|
$query['conditions'][] = array('Customer.id' => $id);
|
|
$query['conditions'][] = array('StatementEntry.account_id' => $A->securityDepositAccountID());
|
|
|
|
$set = $this->StatementEntry->reconciledSet('CHARGE', $query);
|
|
//pr(compact('set'));
|
|
return $set;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: unreconciledCharges
|
|
* - Returns charges have not yet been fully paid
|
|
*/
|
|
|
|
function unreconciledCharges($id, $query = null) {
|
|
$this->queryInit($query);
|
|
|
|
if (!isset($query['link']['Customer']))
|
|
$query['link']['Customer'] = array();
|
|
if (!isset($query['link']['Customer']['fields']))
|
|
$query['link']['Customer']['fields'] = array();
|
|
/* if (!isset($query['link']['StatementEntry'])) */
|
|
/* $query['link']['StatementEntry'] = array(); */
|
|
/* if (!isset($query['link']['StatementEntry']['Customer'])) */
|
|
/* $query['link']['StatementEntry']['Customer'] = array(); */
|
|
/* if (!isset($query['link']['StatementEntry']['Customer']['fields'])) */
|
|
/* $query['link']['StatementEntry']['Customer']['fields'] = array(); */
|
|
|
|
$query['conditions'][] = array('Customer.id' => $id);
|
|
|
|
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
|
|
//pr(compact('set'));
|
|
return $set;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: excessPayments
|
|
* - Returns payments which have not yet been fully utilized
|
|
*/
|
|
|
|
function excessPayments($id, $query = null) {
|
|
$this->queryInit($query);
|
|
|
|
if (!isset($query['link']['StatementEntry']))
|
|
$query['link']['StatementEntry'] = array();
|
|
/* if (!isset($query['link']['StatementEntry']['Customer'])) */
|
|
/* $query['link']['StatementEntry']['Customer'] = array(); */
|
|
/* if (!isset($query['link']['StatementEntry']['Customer']['fields'])) */
|
|
/* $query['link']['StatementEntry']['Customer']['fields'] = array(); */
|
|
|
|
$query['conditions'][] = array('Customer.id' => $id);
|
|
|
|
$set = $this->StatementEntry->reconciledSet('PAYMENT', $query, true);
|
|
//pr(compact('set'));
|
|
return $set;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: paymentWouldReconcile
|
|
* - Returns which charges a new payment would reconcile
|
|
*
|
|
* - REVISIT <AP> 20090617
|
|
* This should be subject to different algorithms, such
|
|
* as apply to oldest charges first, newest first, to fees
|
|
* before rent, etc. Until we get there, I'll hardcode
|
|
* whatever algorithm is simplest.
|
|
*/
|
|
|
|
function paymentWouldReconcile($id, $amount, $query = null) {
|
|
$unreconciled = array($ofund => array('entry'=>array(), 'balance'=>0));
|
|
$applied = 0;
|
|
|
|
if ($amount <= 0)
|
|
return;
|
|
|
|
$unreconciled = array();
|
|
$unreconciled['entries'] = $this->unreconciledCharges($id, $query);
|
|
|
|
foreach ($unreconciled['entries'] AS $i => &$item) {
|
|
$entry =& $item['StatementEntry'];
|
|
// Determine if amount is sufficient to cover the entry
|
|
if ($amount > $entry['balance'])
|
|
$apply = $entry['balance'];
|
|
elseif ($amount > 0)
|
|
$apply = $amount;
|
|
else {
|
|
unset($unreconciled[$i]);
|
|
continue;
|
|
}
|
|
|
|
$entry['applied'] = $apply;
|
|
$entry['reconciled'] += $apply;
|
|
$entry['balance'] -= $apply;
|
|
$applied += $apply;
|
|
$amount -= $apply;
|
|
}
|
|
|
|
$unreconciled['unapplied'] = $amount;
|
|
$unreconciled['applied'] = $applied;
|
|
$unreconciled['balance'] -= $applied;
|
|
return $unreconciled;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: reconcileLedgerEntries
|
|
* - Returns which ledger entries a new credit/debit would
|
|
* reconcile, and how much.
|
|
*
|
|
* - REVISIT <AP> 20090617
|
|
* This should be subject to different algorithms, such
|
|
* as apply to oldest charges first, newest first, to fees
|
|
* before rent, etc. Until we get there, I'll hardcode
|
|
* whatever algorithm is simplest.
|
|
*/
|
|
|
|
function reconcileLedgerEntries($id) {
|
|
$A = new Account();
|
|
$reconciled = $A->reconcileLedgerEntries
|
|
($A->accountReceivableAccountID(),
|
|
array('StatementEntry.customer_id' => $id));
|
|
|
|
return $reconciled;
|
|
}
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: details
|
|
* - Returns detail information for the customer
|
|
*/
|
|
|
|
function details($id = null) {
|
|
// Query the DB for need information.
|
|
$customer = $this->find
|
|
('first', array
|
|
('contain' => array
|
|
(// Models
|
|
'Contact' =>
|
|
array('order' => array('Contact.display_name'),
|
|
// Models
|
|
'ContactPhone',
|
|
'ContactEmail',
|
|
'ContactAddress',
|
|
),
|
|
'Lease' =>
|
|
array('Unit' =>
|
|
array('order' => array('sort_order'),
|
|
'fields' => array('id', 'name'),
|
|
),
|
|
),
|
|
),
|
|
|
|
'conditions' => array('Customer.id' => $id),
|
|
));
|
|
|
|
// Figure out the outstanding balance for this customer
|
|
$customer['stats'] = $this->stats($id);
|
|
|
|
// Figure out the total security deposit for the current lease.
|
|
$customer['deposits'] = $this->securityDeposits($id);
|
|
|
|
return $customer;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: saveCustomer
|
|
* - Saves the customer and related data
|
|
*/
|
|
|
|
function saveCustomer($id, $data, $primary_contact_entry) {
|
|
|
|
// Go through each contact, and create new ones as needed
|
|
foreach ($data['Contact'] AS &$contact) {
|
|
if (isset($contact['id']))
|
|
continue;
|
|
|
|
$I = new Contact();
|
|
$I->create();
|
|
if (!$I->save($contact, false)) {
|
|
return false;
|
|
}
|
|
$contact['id'] = $I->id;
|
|
}
|
|
|
|
// Set the primary contact ID based on caller selection
|
|
$data['Customer']['primary_contact_id']
|
|
= $data['Contact'][$primary_contact_entry]['id'];
|
|
|
|
// Provide a default customer name if not specified
|
|
if (!$data['Customer']['name']) {
|
|
$this->Contact->recursive = -1;
|
|
$pcontact = $this->Contact->read(null, $data['Customer']['primary_contact_id']);
|
|
$data['Customer']['name'] = $pcontact['Contact']['display_name'];
|
|
}
|
|
|
|
// Save the customer data
|
|
$this->create();
|
|
if ($id)
|
|
$this->id = $id;
|
|
if (!$this->save($data, false)) {
|
|
return false;
|
|
}
|
|
$id = $this->id;
|
|
|
|
// Remove all associated Customer Contacts, as it ensures
|
|
// any entries deleted by the user actually get deleted
|
|
// in the system. We'll recreate the needed ones anyway.
|
|
// REVISIT <AP>: 20090706
|
|
// Appears that $this->save() is already doing the
|
|
// delete. I would have thought this would only happen
|
|
// on a saveAll??
|
|
/* $this->ContactsCustomer->deleteAll */
|
|
/* (array('customer_id' => $id), false); */
|
|
|
|
// At this point, since we've saved data to customer,
|
|
// we'll proceed forward as much as possible, even
|
|
// if we encounter an error. For now, we'll assume
|
|
// the operation will succeed.
|
|
$ret = true;
|
|
|
|
// Go through each entry of this customer method
|
|
foreach ($data['Contact'] AS &$contact) {
|
|
// Update the ContactsCustomer to reflect the appropriate IDs
|
|
$contact['ContactsCustomer']['customer_id'] = $id;
|
|
$contact['ContactsCustomer']['contact_id'] = $contact['id'];
|
|
|
|
// Save the relationship between customer and contact
|
|
$CM = new ContactsCustomer();
|
|
if (!$CM->save($contact['ContactsCustomer'], false)) {
|
|
$ret = false;
|
|
}
|
|
}
|
|
|
|
// Return the result
|
|
return $ret;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* function: stats
|
|
* - Returns summary data from the requested customer.
|
|
*/
|
|
|
|
function stats($id = null, $query = null) {
|
|
if (!$id)
|
|
return null;
|
|
|
|
$this->queryInit($query);
|
|
|
|
// REVISIT <AP>: 20090725
|
|
// We'll need to go directly to the statement entries if
|
|
// transactions are not always associated with the customer.
|
|
// This could happen if either we remove the customer_id
|
|
// field from Transaction, or we allow multiple customers
|
|
// to be part of the same transaction (essentially making
|
|
// the Transaction.customer_id meaningless).
|
|
|
|
/* $stats = $this->StatementEntry->find */
|
|
/* ('first', array */
|
|
/* ('contain' => false, */
|
|
/* 'fields' => $this->StatementEntry->chargePaymentFields(true), */
|
|
/* 'conditions' => array('StatementEntry.customer_id' => $id), */
|
|
/* )); */
|
|
|
|
$find_stats = $this->StatementEntry->find
|
|
('first', array
|
|
('contain' => false,
|
|
'fields' => $this->StatementEntry->chargePaymentFields(true),
|
|
'conditions' => array('StatementEntry.customer_id' => $id),
|
|
));
|
|
pr(compact('find_stats'));
|
|
|
|
$tquery = $query;
|
|
$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
$statement_stats = $this->StatementEntry->stats(null, $tquery);
|
|
$statement_stats['balance'] = $statement_stats['Charge']['balance'];
|
|
pr(compact('statement_stats'));
|
|
|
|
$tquery = $query;
|
|
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
|
$transaction_stats = $this->Transaction->stats(null, $tquery);
|
|
$transaction_stats += $transaction_stats['StatementEntry'];
|
|
pr(compact('transaction_stats'));
|
|
|
|
$tquery = $query;
|
|
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
|
$ar_transaction_stats = $this->Transaction->stats(null, $tquery,
|
|
$this->Transaction->Account->accountReceivableAccountID());
|
|
$ar_transaction_stats += $ar_transaction_stats['LedgerEntry'];
|
|
pr(compact('ar_transaction_stats'));
|
|
|
|
$stats = $ar_transaction_stats;
|
|
return $stats;
|
|
}
|
|
|
|
}
|
|
?>
|