diff --git a/db/schema.sql b/db/schema.sql index 6a3c4a4..7c9c44f 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -956,7 +956,6 @@ CREATE TABLE `pmgr_transactions` ( 'CLOSE', -- 'CREDIT', -- 'REFUND', --- 'WAIVER', 'TRANSFER') NOT NULL, @@ -1065,10 +1064,10 @@ CREATE TABLE `pmgr_statement_entries` ( `type` ENUM('CHARGE', 'PAYMENT', 'SURPLUS', + 'WAIVER', -- REVISIT : 20090730 - -- VOID is just to test out a theory - -- for handling NSF and charge reversals - 'WAIVE', + -- VOID is used for handling NSF and perhaps charge reversals. + -- It's not clear this is the best way to handle these things. 'VOID') NOT NULL, diff --git a/site/controllers/leases_controller.php b/site/controllers/leases_controller.php index e1784b9..24e4012 100644 --- a/site/controllers/leases_controller.php +++ b/site/controllers/leases_controller.php @@ -222,109 +222,13 @@ class LeasesController extends AppController { * to prevent feature overload on the receipt page. */ - function apply_deposit($id = null) { - // Create some models for convenience - $A = new Account(); - - if ($this->data) { - // Handle the move out based on the data given - pr($this->data); - $this->Lease->releaseSecurityDeposits($this->data['Lease']['id']); - die(); - - // Assume this will succeed - $ret = true; - - // Go through the entered payments - $receipt_transaction = array_intersect_key($this->data, - array('Transaction'=>1, - 'transaction_id'=>1)); - foreach ($data['StatementEntry'] AS $entry) { - // Create the receipt entry, and reconcile the credit side - // of the double-entry (which should be A/R) as a payment. - $ids = $this->StatementEntry->Ledger->Account->postLedgerEntry - ($receipt_transaction, - array_intersect_key($entry, array('MonetarySource'=>1)) - + array_intersect_key($entry, array('account_id'=>1)), - array('debit_ledger_id' => $A->currentLedgerID($entry['account_id']), - 'credit_ledger_id' => $A->currentLedgerID($A->receiptAccountID()), - 'customer_id' => $customer_id, - 'lease_id' => $lease_id) - + $entry, - 'receipt'); - - if ($ids['error']) - $ret = false; - - $db = &$model->getDataSource(); - $fields = $db->fields($model, $model->alias); - $fields[] = ("SUM(IF(Account.id IS NULL, 0," . - " IF(LedgerEntry.debit_ledger_id = Account.id," . - " 1, -1))" . - " * IF(LedgerEntry.amount IS NULL, 0, LedgerEntry.amount))" . - " AS 'balance'"); - return $fields; - $receipt_transaction = array_intersect_key($ids, - array('transaction_id'=>1, - 'split_transaction_id'=>1)); - } - - $this->Lease->moveOut($this->data['Lease']['id'], - 'VACANT', - $this->data['Lease']['moveout_date'], - //true // Close this lease, if able - false - ); - - $this->redirect(array('controller' => 'leases', - 'action' => 'view', - $this->data['Lease']['id'])); - $this->autoRender = false; - return; - } - - $A = new Account(); - - $lease = $this->Lease->find - ('first', array - ('contain' => array - (// Models - 'Unit' => - array('order' => array('sort_order'), - 'fields' => array('id', 'name'), - ), - - 'Customer' => - array('fields' => array('id', 'name'), - ), - ), - - 'conditions' => array(array('Lease.id' => $id), - array('Lease.close_date' => null), - ), - )); - - - // Get the lease balance, part of lease stats - $this->Lease->statsMerge($lease['Lease'], - array('stats' => $this->Lease->stats($id))); - - // Determine the lease security deposit - $deposit_balance = $this->Lease->securityDeposits($lease['Lease']['id']); - $this->set(compact('deposit_balance')); - $this->set('customer', $lease['Customer']); - $this->set('unit', $lease['Unit']); - $this->set('lease', $lease['Lease']); - $this->set('account', array('id' => $A->securityDepositAccountID())); - -/* $redirect = array('controller' => 'leases', */ -/* 'action' => 'view', */ -/* $id); */ - - $title = ('Lease #' . $lease['Lease']['number'] . ': ' . - $lease['Unit']['name'] . ': ' . - $lease['Customer']['name'] . ': Utilize Security Deposit'); - $this->set(compact('title', 'redirect')); + function apply_deposit($id) { + $this->Lease->releaseSecurityDeposits($id); + pr("PREVENTING REDIRECT"); + $this->render('fake'); + $this->redirect(array('controller' => 'leases', + 'action' => 'view', + $id)); } diff --git a/site/models/customer.php b/site/models/customer.php index 216ea09..6c5b62e 100644 --- a/site/models/customer.php +++ b/site/models/customer.php @@ -81,12 +81,7 @@ class Customer extends AppModel { $this->prEnter(compact('id', 'query')); $this->queryInit($query); - 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.customer_id' => $id); $query['conditions'][] = array('StatementEntry.account_id' => $this->StatementEntry->Account->securityDepositAccountID()); @@ -106,18 +101,12 @@ class Customer extends AppModel { $this->prEnter(compact('id', 'query')); $this->queryInit($query); - 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.customer_id' => $id); $query['conditions'][] = array('StatementEntry.account_id' => $this->StatementEntry->Account->securityDepositAccountID()); $stats = $this->StatementEntry->stats(null, $query); - $balance = $stats['Charge']['reconciled'] - $stats['Payment']['reconciled']; - return $this->prReturn($balance); + return $this->prReturn($stats['account_balance']); } @@ -132,19 +121,7 @@ class Customer extends AppModel { $this->prEnter(compact('id', 'query')); $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); - + $query['conditions'][] = array('StatementEntry.customer_id' => $id); $set = $this->StatementEntry->reconciledSet('CHARGE', $query, true); return $this->prReturn($set); } @@ -161,15 +138,7 @@ class Customer extends AppModel { $this->prEnter(compact('id', 'query')); $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); - + $query['conditions'][] = array('StatementEntry.customer_id' => $id); $set = $this->StatementEntry->reconciledSet('PAYMENT', $query, true); return $this->prReturn($set); } diff --git a/site/models/lease.php b/site/models/lease.php index 4d83e46..bd1d880 100644 --- a/site/models/lease.php +++ b/site/models/lease.php @@ -12,7 +12,7 @@ class Lease extends AppModel { 'StatementEntry', ); - var $default_log_level = array('log' => 30, 'show' => 15); + //var $default_log_level = array('log' => 30, 'show' => 15); /************************************************************************** ************************************************************************** @@ -24,21 +24,11 @@ class Lease extends AppModel { $this->prEnter(compact('id', 'query')); $this->queryInit($query); - if (!isset($query['link']['Lease'])) - $query['link']['Lease'] = array(); - if (!isset($query['link']['Lease']['fields'])) - $query['link']['Lease']['fields'] = array(); - - $query['conditions'][] = array('Lease.id' => $id); + $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); - -/* $set['summary'] = array('total' => $set['summary']['Charge']['total'], */ -/* 'balance' => $set['summary']['Charge']['reconciled'], */ -/* ); */ - return $this->prReturn($set); } @@ -54,18 +44,12 @@ class Lease extends AppModel { $this->prEnter(compact('id', 'query')); $this->queryInit($query); - if (!isset($query['link']['Lease'])) - $query['link']['Lease'] = array(); - if (!isset($query['link']['Lease']['fields'])) - $query['link']['Lease']['fields'] = array(); - - $query['conditions'][] = array('Lease.id' => $id); + $query['conditions'][] = array('StatementEntry.lease_id' => $id); $query['conditions'][] = array('StatementEntry.account_id' => $this->StatementEntry->Account->securityDepositAccountID()); $stats = $this->StatementEntry->stats(null, $query); - $balance = $stats['Charge']['reconciled'] - $stats['Payment']['reconciled']; - return $this->prReturn($balance); + return $this->prReturn($stats['account_balance']); } @@ -78,9 +62,9 @@ class Lease extends AppModel { * to pay outstanding customer charges, or simply to become * a customer surplus (customer credit). */ - function releaseSecurityDeposits($id, $query = null) { - $this->prFunctionLevel(30); - $this->prEnter(compact('id', 'query')); + function releaseSecurityDeposits($id, $stamp = null, $query = null) { + //$this->prFunctionLevel(30); + $this->prEnter(compact('id', 'stamp', 'query')); $secdeps = $this->securityDeposits($id, $query); $secdeps = $secdeps['entries']; @@ -93,6 +77,7 @@ class Lease extends AppModel { // 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') @@ -102,7 +87,7 @@ class Lease extends AppModel { // any unpaid (or only partially paid) security deposit should // have the remaining balance simply waived. if ($charge['StatementEntry']['balance'] > 0) - $this->StatementEntry->waive($charge['StatementEntry']['id']); + $this->StatementEntry->waive($charge['StatementEntry']['id'], $stamp); $release['Entry'][] = array('amount' => $charge['StatementEntry']['reconciled'], @@ -112,7 +97,7 @@ class Lease extends AppModel { } $customer_id = $secdeps[0]['StatementEntry']['customer_id']; - $lease_id = $secdeps[0]['StatementEntry']['lease_id']; + $lease_id = $secdeps[0]['StatementEntry']['lease_id']; $result = $this->StatementEntry->Transaction->addReceipt ($release, $customer_id, $lease_id); @@ -377,6 +362,9 @@ class Lease extends AppModel { // 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); @@ -477,40 +465,8 @@ class Lease extends AppModel { return $this->prReturn(null); $this->queryInit($query); - - //$query['link'] = array('Lease' => $query['link']); -/* if (!isset($query['link']['StatementEntry'])) */ -/* $query['link']['StatementEntry'] = array(); */ -/* if (!isset($query['link']['StatementEntry']['ChargeEntry'])) */ -/* $query['link']['StatementEntry']['ChargeEntry'] = array(); */ - -/* $query['link']['StatementEntry']['fields'] = array(); */ -/* $query['link']['ChargeEntry']['fields'] = array(); */ -/* $query['link']['ChargeEntry']['Account']['fields'] = array(); */ -/* $query['link']['ChargeEntry']['StatementEntry']['fields'] = array(); */ -/* $query['link']['ChargeEntry']['StatementEntry']['Invoice']['fields'] = array(); */ - - if (!isset($query['fields'])) - $query['fields'] = array(); - - $query['fields'] = array_merge($query['fields'], - $this->StatementEntry->chargePaymentFields(true)); - $query['conditions'][] = array('StatementEntry.lease_id' => $id); - - $query['group'] = null; - - $stats = $this->StatementEntry->find('first', $query); - //$this->pr(20, compact('query', 'stats')); - - // The fields are all tucked into the [0] index, - // and the rest of the array is useless (empty). - $stats = $stats[0]; - - // Make sure we have a non-null balance - if (!isset($stats['balance'])) - $stats['balance'] = 0; - + $stats = $this->StatementEntry->stats(null, $query); return $this->prReturn($stats); } diff --git a/site/models/statement_entry.php b/site/models/statement_entry.php index 6563eee..f55f03a 100644 --- a/site/models/statement_entry.php +++ b/site/models/statement_entry.php @@ -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); /************************************************************************** ************************************************************************** @@ -40,14 +40,14 @@ class StatementEntry extends AppModel { ($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''), ($sum ? 'SUM(' : '') . - //"IF({$entry_name}.type IN('PAYMENT', 'SURPLUS', 'WAIVE')," . + //"IF({$entry_name}.type IN('PAYMENT', 'SURPLUS', 'WAIVER')," . "IF({$entry_name}.type NOT IN('CHARGE', 'VOID')," . " {$entry_name}.amount, NULL)" . ($sum ? ')' : '') . ' AS payment' . ($sum ? 's' : ''), ($sum ? 'SUM(' : '') . //"IF({$entry_name}.type = 'CHARGE', 1," . - //" IF({$entry_name}.type IN('PAYMENT', 'SURPLUS', 'WAIVE'), -1, 0))" . + //" IF({$entry_name}.type IN('PAYMENT', 'SURPLUS', 'WAIVER'), -1, 0))" . "IF({$entry_name}.type = 'VOID', 0," . " IF({$entry_name}.type = 'CHARGE', 1, -1))" . " * IF({$entry_name}.amount, {$entry_name}.amount, 0)" . @@ -377,10 +377,13 @@ OPTION 2 * */ function assignCredits($query = null, $receipt_id = null, - $charge_ids = null, $payment_type = null) + $charge_ids = null, $payment_type = null, + $customer_id = null, $lease_id = null) { //$this->prFunctionLevel(25); - $this->prEnter( compact('query', 'receipt_id', 'charge_ids', 'payment_type')); + $this->prEnter(compact('query', 'receipt_id', + 'charge_ids', 'payment_type', + 'customer_id', 'lease_id')); $this->queryInit($query); if (empty($payment_type)) @@ -570,7 +573,8 @@ OPTION 2 'amount' => $credit['balance'], 'effective_date' => $credit['Transaction']['stamp'], 'transaction_id' => $credit['Transaction']['id'], - 'customer_id' => $credit['Customer']['id'], + 'customer_id' => $customer_id, + 'lease_id' => $lease_id, )); $ret['Credit'] = $result; if ($result['error']) @@ -597,92 +601,95 @@ OPTION 2 if (isset($id)) $query['conditions'][] = array('StatementEntry.id' => $id); - $rquery = $query; - unset($rquery['link']['ChargeEntry']); - $rquery['link']['PaymentEntry'] = array('fields' => array()); + // Determine the total in charges + $charge_query = $query; + unset($charge_query['link']['ChargeEntry']); + unset($charge_query['link']['PaymentEntry']); - $rquery['fields'] = array(); - $rquery['fields'][] = "StatementEntry.amount"; - $rquery['fields'][] = "SUM(PaymentEntry.amount) AS reconciled"; + $charge_query['fields'] = array(); + $charge_query['fields'][] = "SUM(StatementEntry.amount) AS total"; + $charge_query['conditions'][] = array('StatementEntry.type' => 'CHARGE'); + $result = $this->find('first', $charge_query); + $stats['Charge'] = $result[0]; - $rquery['conditions'][] = array('StatementEntry.type' => 'CHARGE'); - $rquery['group'] = 'StatementEntry.id'; - - $result = $this->find('all', $rquery); - $stats['Charge'] = array('total' => 0, 'reconciled' => 0); - foreach($result AS $charge) { - $stats['Charge']['total'] += $charge['StatementEntry']['amount']; - $stats['Charge']['reconciled'] += $charge[0]['reconciled']; - } - $stats['Charge']['balance'] = - $stats['Charge']['total'] - $stats['Charge']['reconciled']; - - $this->pr(17, compact('rquery', 'result'), + $this->pr(17, compact('charge_query', 'result'), 'Charges'); - $rquery = $query; - unset($rquery['link']['ChargeEntry']); - $rquery['link']['PaymentEntry'] = array('fields' => array(), -/* 'conditions' => */ -/* array('PaymentEntry.type' => 'WAIVE'), */ - ); - - $rquery['fields'] = array(); - $rquery['fields'][] = "SUM(PaymentEntry.amount) AS reconciled"; - - $rquery['conditions'][] = array('StatementEntry.type' => 'CHARGE'); - $rquery['conditions'][] = array('PaymentEntry.type' => 'WAIVE'); - $rquery['group'] = 'StatementEntry.id'; - - $result = $this->find('first', $rquery); - $stats['Charge']['waived'] = $result[0]['reconciled']; -/* $stats['Waiver'] = array('total' => 0, 'reconciled' => 0); */ -/* foreach($result AS $charge) { */ -/* $stats['Waiver']['total'] += $charge['StatementEntry']['amount']; */ -/* $stats['Waiver']['reconciled'] += $charge[0]['reconciled']; */ -/* } */ -/* $stats['Waiver']['balance'] = */ -/* $stats['Waiver']['total'] - $stats['Waiver']['reconciled']; */ + // Tally the amount actually _paid_ to those charges + $charge_payment_query = $charge_query; + $charge_payment_query['link']['PaymentEntry'] = array('fields' => array()); + $charge_payment_query['fields'] = array(); + $charge_payment_query['fields'][] = "COALESCE(SUM(PaymentEntry.amount),0) AS paid"; + $charge_payment_query['conditions'][] = array('PaymentEntry.type' => 'PAYMENT'); + $result = $this->find('first', $charge_payment_query); + $stats['Charge'] += $result[0]; - $this->pr(17, compact('rquery', 'result'), - 'Waived'); + $this->pr(17, compact('charge_payment_query', 'result'), + 'Charge Payments'); - $rquery = $query; - unset($rquery['link']['PaymentEntry']); - $rquery['link']['ChargeEntry'] = array('fields' => array()); + // Tally the amount of charges that have been waived + $charge_waiver_query = $charge_query; + $charge_waiver_query['link']['PaymentEntry'] = array('fields' => array()); + $charge_waiver_query['fields'] = array(); + $charge_waiver_query['fields'][] = "COALESCE(SUM(PaymentEntry.amount),0) AS waived"; + $charge_waiver_query['conditions'][] = array('PaymentEntry.type' => 'WAIVER'); + $result = $this->find('first', $charge_waiver_query); + $stats['Charge'] += $result[0]; + + $this->pr(17, compact('charge_waiver_query', 'result'), + 'Charge Waivers'); - $rquery['fields'] = array(); - $rquery['fields'][] = "SUM(StatementEntry.amount) AS total"; - $rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, 0, StatementEntry.amount)) AS reconciled"; - $rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, StatementEntry.amount, 0)) AS balance"; + // Compute some summary information for charges + $stats['Charge']['reconciled'] = + $stats['Charge']['paid'] + $stats['Charge']['waived']; + $stats['Charge']['balance'] = + $stats['Charge']['total'] - $stats['Charge']['reconciled']; + if (!isset($stats['Charge']['balance'])) + $stats['Charge']['balance'] = 0; - $rquery['conditions'][] = array('StatementEntry.type' => 'PAYMENT'); - $result = $this->find('first', $rquery); - if (!isset($result[0]['balance'])) - $result[0]['balance'] = 0; + + // Determine the total in payments, including those which + // are charge waivers and those that do not even reconcile + // to charges (i.e. they are surplus payments). + $payment_query = $query; + unset($payment_query['link']['PaymentEntry']); + $payment_query['link']['ChargeEntry'] = array('fields' => array()); + + $payment_query['fields'] = array(); + $payment_query['fields'][] = "SUM(StatementEntry.amount) AS total"; + $payment_query['fields'][] = "COALESCE(SUM(IF(ChargeEntry.id IS NULL, 0, StatementEntry.amount)), 0) AS charged"; + $payment_query['fields'][] = "COALESCE(SUM(IF(ChargeEntry.id IS NULL, StatementEntry.amount, 0)), 0) AS surplus"; + + $payment_query['conditions'][] = array('StatementEntry.type' => array('PAYMENT', 'WAIVER', 'SURPLUS')); + $result = $this->find('first', $payment_query); $stats['Payment'] = $result[0]; - $this->pr(17, compact('rquery', 'result'), + $this->pr(17, compact('payment_query', 'result'), 'Payments'); - $rquery = $query; - unset($rquery['link']['PaymentEntry']); - unset($rquery['link']['ChargeEntry']); + // Compute some summary information for payments. + // Add a reconciled field just for consistency with Charge. + $stats['Payment']['reconciled'] = + $stats['Payment']['charged']; + $stats['Payment']['balance'] = + $stats['Payment']['total'] - $stats['Payment']['reconciled']; + if (!isset($stats['Payment']['balance'])) + $stats['Payment']['balance'] = 0; - $rquery['fields'] = array(); - $rquery['fields'][] = "SUM(StatementEntry.amount) AS total"; - $rquery['fields'][] = "SUM(0) AS reconciled"; - - $rquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS'); - $result = $this->find('first', $rquery); - $result[0]['balance'] = $result[0]['total'] - $result[0]['reconciled']; - if (!isset($result[0]['balance'])) - $result[0]['balance'] = 0; - $stats['Surplus'] = $result[0]; - - $this->pr(17, compact('rquery', 'result'), - 'Surplus'); + // 'balance' is simply the difference between + // the balances of charges and payments + $stats['balance'] = $stats['Charge']['balance'] - $stats['Payment']['balance']; + if (!isset($stats['balance'])) + $stats['balance'] = 0; + // 'account_balance' is really only relevant to + // callers that have requested charge and payment + // stats with respect to a particular account. + // It represents the difference between inflow + // and outflow from that account. + $stats['account_balance'] = $stats['Charge']['paid'] - $stats['Payment']['total']; + if (!isset($stats['account_balance'])) + $stats['account_balance'] = 0; return $this->prReturn($stats); } diff --git a/site/models/transaction.php b/site/models/transaction.php index 2001852..f257080 100644 --- a/site/models/transaction.php +++ b/site/models/transaction.php @@ -37,7 +37,7 @@ class Transaction extends AppModel { ); - var $default_log_level = array('log' => 30, 'show' => 15); + //var $default_log_level = array('log' => 30, 'show' => 15); /************************************************************************** ************************************************************************** @@ -127,7 +127,7 @@ class Transaction extends AppModel { // Just make sure the payment(s) are marked as waivers // and that they go to cover the specific charge. - $data['Transaction']['payment_type'] = 'WAIVE'; + $data['Transaction']['payment_type'] = 'WAIVER'; $data['Transaction']['charge_entry_id'] = $charge_id; // In all other respects this is just a receipt. @@ -521,7 +521,9 @@ class Transaction extends AppModel { : null), (!empty($transaction['payment_type']) ? $transaction['payment_type'] - : null) + : null), + $transaction['customer_id'], + $transaction['lease_id'] ); $ret['assigned'] = $result;