git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1030 97e9348a-65ac-dc4b-aefc-98561f571b83
520 lines
18 KiB
PHP
520 lines
18 KiB
PHP
<?php
|
|
|
|
class TransactionsController extends AppController {
|
|
|
|
var $components = array('RequestHandler');
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* override: addGridViewSideMenuLinks
|
|
* - Adds grid view navigation side menu links
|
|
*/
|
|
|
|
function addGridViewSideMenuLinks() {
|
|
parent::addGridViewSideMenuLinks();
|
|
|
|
$this->addSideMenuLink('Invoices',
|
|
array('controller' => 'transactions', 'action' => 'invoice'), null,
|
|
'CONTROLLER');
|
|
$this->addSideMenuLink('Receipts',
|
|
array('controller' => 'transactions', 'action' => 'receipt'), null,
|
|
'CONTROLLER');
|
|
$this->addSideMenuLink('Deposits',
|
|
array('controller' => 'transactions', 'action' => 'deposit'), null,
|
|
'CONTROLLER');
|
|
$this->addSideMenuLink('All',
|
|
array('controller' => 'transactions', 'action' => 'all'), null,
|
|
'CONTROLLER');
|
|
|
|
// REVISIT <AP>: 20090824
|
|
// Right now, we wish to keep things simple. Don't make these
|
|
// links available to non-admin users.
|
|
if (empty($this->params['admin']))
|
|
$this->sideMenuEnable('CONTROLLER', $this->std_area, false);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: index / all
|
|
* - Generate a listing of transactions
|
|
*/
|
|
|
|
function index() { $this->all(); }
|
|
function all() { $this->gridView('All Transactions', 'all'); }
|
|
function invoice() { $this->gridView('Invoices'); }
|
|
function receipt() { $this->gridView('Receipts'); }
|
|
function deposit() {
|
|
/* $this->addSideMenuLink('New Deposit', */
|
|
/* array('controller' => 'tenders', 'action' => 'deposit'), null, */
|
|
/* 'CONTROLLER', $this->new_area); */
|
|
$this->gridView('Deposits');
|
|
}
|
|
|
|
function gridView($title, $action = null, $element = null) {
|
|
if ($title != 'Deposits')
|
|
$this->set('include', array('Customer'));
|
|
parent::gridView($title, $action, $element);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* virtuals: gridData
|
|
* - With the application controller handling the gridData action,
|
|
* these virtual functions ensure that the correct data is passed
|
|
* to jqGrid.
|
|
*/
|
|
|
|
function gridDataCountTables(&$params, &$model) {
|
|
return array
|
|
('link' =>
|
|
array(// Models
|
|
'Account' => array('fields' => array()),
|
|
),
|
|
);
|
|
}
|
|
|
|
function gridDataTables(&$params, &$model) {
|
|
$link = $this->gridDataCountTables($params, $model);
|
|
$link['link']['StatementEntry'] = array('fields' => array());
|
|
$link['link']['DepositTender'] = array('fields' => array());
|
|
$link['link']['Customer'] = array('fields' => array('id', 'name'));
|
|
return $link;
|
|
}
|
|
|
|
function gridDataFields(&$params, &$model) {
|
|
$fields = parent::gridDataFields($params, $model);
|
|
//$fields[] = 'COUNT(StatementEntry.id) AS entries';
|
|
$fields[] = ("IF(Transaction.type = 'DEPOSIT'," .
|
|
" COUNT(DepositTender.id)," .
|
|
" COUNT(StatementEntry.id)) AS entries");
|
|
return $fields;
|
|
}
|
|
|
|
function gridDataConditions(&$params, &$model) {
|
|
$conditions = parent::gridDataConditions($params, $model);
|
|
|
|
if (in_array($params['action'], array('invoice', 'receipt', 'deposit')))
|
|
$conditions[] = array('Transaction.type' => strtoupper($params['action']));
|
|
|
|
return $conditions;
|
|
}
|
|
|
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
|
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
|
|
? 'deposit_slip' : 'view'));
|
|
$links['Customer'] = array('name');
|
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: postInvoice
|
|
* - handles the creation of a charge invoice
|
|
*/
|
|
|
|
function postInvoice($redirect = true) {
|
|
if (!$this->RequestHandler->isPost()) {
|
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
return;
|
|
}
|
|
|
|
if (!$this->Transaction->addInvoice($this->data, null,
|
|
$this->data['Lease']['id'])) {
|
|
$this->Session->setFlash("INVOICE FAILED", true);
|
|
// REVISIT <AP> 20090706:
|
|
// Until we can work out the session problems,
|
|
// just die.
|
|
die("<H1>INVOICE FAILED</H1>");
|
|
}
|
|
|
|
if ($redirect) {
|
|
if (!empty($this->data['Customer']['id']))
|
|
$this->redirect(array('controller' => 'customers',
|
|
'action' => 'receipt',
|
|
$this->data['Customer']['id']));
|
|
else
|
|
$this->redirect(array('controller' => 'leases',
|
|
'action' => 'view',
|
|
$this->data['Lease']['id']));
|
|
}
|
|
|
|
$this->layout = null;
|
|
$this->autoLayout = false;
|
|
$this->autoRender = false;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: postReceipt
|
|
* - handles the creation of a receipt
|
|
*/
|
|
|
|
function postReceipt($redirect = true) {
|
|
if (!$this->RequestHandler->isPost()) {
|
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
return;
|
|
}
|
|
|
|
foreach($this->data['Entry'] AS &$entry) {
|
|
$entry['Tender'] = $entry['type'][$entry['tender_type_id']];
|
|
unset($entry['type']);
|
|
unset($entry['tender_type_id']);
|
|
}
|
|
|
|
if (!$this->Transaction->addReceipt($this->data,
|
|
$this->data['Customer']['id'],
|
|
(isset($this->data['Lease']['id'])
|
|
? $this->data['Lease']['id']
|
|
: null ))) {
|
|
$this->Session->setFlash("RECEIPT FAILED", true);
|
|
// REVISIT <AP> 20090706:
|
|
// Until we can work out the session problems,
|
|
// just die.
|
|
die("<H1>RECEIPT FAILED</H1>");
|
|
}
|
|
|
|
if ($redirect)
|
|
$this->redirect(array('controller' => 'customers',
|
|
'action' => 'view',
|
|
$this->data['Customer']['id']));
|
|
|
|
$this->layout = null;
|
|
$this->autoLayout = false;
|
|
$this->autoRender = false;
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: postDeposit
|
|
* - handles the creation of a deposit transaction
|
|
*/
|
|
|
|
function postDeposit() {
|
|
if (!$this->RequestHandler->isPost()) {
|
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
return;
|
|
}
|
|
|
|
//pr($this->data);
|
|
|
|
// Go through each type of tender presented to the user
|
|
// Determine which are to be deposited, and which are to
|
|
// have their corresponding account ledgers closed.
|
|
$deposit_tender_ids = array();
|
|
$deposit_type_ids = array();
|
|
$close_type_ids = array();
|
|
foreach ($this->data['TenderType'] AS $type_id => $type) {
|
|
$type['items'] = unserialize($type['items']);
|
|
if (empty($type['selection']) ||
|
|
$type['selection'] === 'none' ||
|
|
($type['selection'] === 'subset' && count($type['items']) == 0))
|
|
continue;
|
|
|
|
// The deposit includes either the whole type, or just certain tenders
|
|
if ($type['selection'] === 'all')
|
|
$deposit_type_ids[] = $type_id;
|
|
else
|
|
$deposit_tender_ids = array_merge($deposit_tender_ids, $type['items']);
|
|
|
|
// Should we close the ledger for this tender type?
|
|
// First, the user would have to request that we do so,
|
|
// but additionally, we shouldn't close a ledger unless
|
|
// all the tenders are included in this deposit. That
|
|
// doesn't guarantee that the ledger has a zero balance,
|
|
// but it does carry the balance forward, and a total
|
|
// deposit would imply a fresh start, so go for it.
|
|
if (!empty($type['close']) && $type['selection'] === 'all')
|
|
$close_type_ids[] = $type_id;
|
|
}
|
|
|
|
// Make sure we actually have something to deposit
|
|
if (empty($deposit_type_ids) && empty($deposit_tender_ids)) {
|
|
$this->Session->setFlash(__('Nothing to Deposit', true));
|
|
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
|
|
}
|
|
|
|
// Build up a set of conditions based on user selection
|
|
$deposit_conditions = array();
|
|
if (!empty($deposit_type_ids))
|
|
$deposit_conditions[] = array('TenderType.id' => $deposit_type_ids);
|
|
if (!empty($deposit_tender_ids))
|
|
$deposit_conditions[] = array('DepositTender.id' => $deposit_tender_ids);
|
|
|
|
// Add in confirmation that items have not already been deposited
|
|
$deposit_conditions =
|
|
array(array('DepositTender.deposit_transaction_id' => null),
|
|
array('OR' => $deposit_conditions));
|
|
|
|
// Lookup the items to be deposited
|
|
$tenders = $this->Transaction->DepositTender->find
|
|
('all',
|
|
array('contain' => array('TenderType', 'LedgerEntry'),
|
|
'conditions' => $deposit_conditions,
|
|
));
|
|
|
|
// Build the deposit transaction
|
|
$deposit = array('Transaction' => array(), 'Entry' => array());
|
|
foreach ($tenders AS $tender) {
|
|
$deposit['Entry'][] =
|
|
array('tender_id' => $tender['DepositTender']['id'],
|
|
'account_id' => $tender['LedgerEntry']['account_id'],
|
|
'amount' => $tender['LedgerEntry']['amount'],
|
|
);
|
|
}
|
|
|
|
//pr(compact('deposit_type_ids', 'deposit_tender_ids', 'close_type_ids', 'deposit_conditions', 'deposit'));
|
|
|
|
// OK, perform the deposit and associated accounting
|
|
$result = $this->Transaction->addDeposit
|
|
($deposit, $this->data['Deposit']['Account']['id']);
|
|
//pr(compact('deposit', 'result'));
|
|
|
|
// Close any ledgers necessary
|
|
if (!empty($close_type_ids)) {
|
|
// Find the accounts associated with the types to close ...
|
|
$accounts = $this->Transaction->DepositTender->find
|
|
('all',
|
|
array('contain' => array('TenderType.account_id'),
|
|
'conditions' => array(array('TenderType.id' => $close_type_ids)),
|
|
));
|
|
|
|
// ... and close them
|
|
$this->Transaction->Account->closeCurrentLedgers
|
|
(array_map(create_function('$item', 'return $item["TenderType"]["account_id"];'), $accounts));
|
|
}
|
|
|
|
// Look out for errors
|
|
if ($result['error']) {
|
|
$this->Session->setFlash(__('Unable to Create Deposit', true));
|
|
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
|
|
}
|
|
|
|
// Present the deposit slip to the user
|
|
$this->redirect(array('controller' => 'transactions',
|
|
'action' => 'deposit_slip',
|
|
$result['transaction_id']));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: postWriteOff
|
|
* - handles the write off of bad debt
|
|
*/
|
|
|
|
function postWriteOff() {
|
|
if (!$this->RequestHandler->isPost()) {
|
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
return;
|
|
}
|
|
|
|
$data = $this->data;
|
|
if (empty($data['Customer']['id']))
|
|
$data['Customer']['id'] = null;
|
|
if (empty($data['Lease']['id']))
|
|
$data['Lease']['id'] = null;
|
|
|
|
pr(compact('data'));
|
|
|
|
if (!$this->Transaction->addWriteOff($data,
|
|
$data['Customer']['id'],
|
|
$data['Lease']['id'])) {
|
|
$this->Session->setFlash("WRITE OFF FAILED", true);
|
|
// REVISIT <AP> 20090706:
|
|
// Until we can work out the session problems,
|
|
// just die.
|
|
die("<H1>WRITE-OFF FAILED</H1>");
|
|
}
|
|
|
|
// Return to viewing the lease/customer
|
|
if (empty($data['Lease']['id']))
|
|
$this->redirect(array('controller' => 'customers',
|
|
'action' => 'view',
|
|
$data['Customer']['id']));
|
|
else
|
|
$this->redirect(array('controller' => 'leases',
|
|
'action' => 'view',
|
|
$data['Lease']['id']));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: postRefund
|
|
* - handles issuing a customer refund
|
|
*/
|
|
|
|
function postRefund() {
|
|
if (!$this->RequestHandler->isPost()) {
|
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
return;
|
|
}
|
|
|
|
$data = $this->data;
|
|
if (empty($data['Customer']['id']))
|
|
$data['Customer']['id'] = null;
|
|
if (empty($data['Lease']['id']))
|
|
$data['Lease']['id'] = null;
|
|
|
|
if (!$this->Transaction->addRefund($data,
|
|
$data['Customer']['id'],
|
|
$data['Lease']['id'])) {
|
|
$this->Session->setFlash("REFUND FAILED", true);
|
|
// REVISIT <AP> 20090706:
|
|
// Until we can work out the session problems,
|
|
// just die.
|
|
die("<H1>REFUND FAILED</H1>");
|
|
}
|
|
|
|
// Return to viewing the lease/customer
|
|
if (empty($data['Lease']['id']))
|
|
$this->redirect(array('controller' => 'customers',
|
|
'action' => 'view',
|
|
$data['Customer']['id']));
|
|
else
|
|
$this->redirect(array('controller' => 'leases',
|
|
'action' => 'view',
|
|
$data['Lease']['id']));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: destroy
|
|
* - Deletes a transaction and associated entries
|
|
* - !!WARNING!! This should be used with EXTREME caution, as it
|
|
* irreversibly destroys the data. It is not for normal use.
|
|
*/
|
|
|
|
function destroy($id) {
|
|
$this->Transaction->id = $id;
|
|
$customer_id = $this->Transaction->field('customer_id');
|
|
$this->Transaction->destroy($id);
|
|
$this->redirect(array('controller' => 'customers', 'action' => 'view', $customer_id));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: view
|
|
* - Displays information about a specific transaction
|
|
*/
|
|
|
|
function view($id = null) {
|
|
$transaction = $this->Transaction->find
|
|
('first',
|
|
array('contain' =>
|
|
array(// Models
|
|
'Account(id,name,level)',
|
|
'Ledger(id,sequence)',
|
|
'NsfTender(id,name)',
|
|
),
|
|
'conditions' => array(array('Transaction.id' => $id),
|
|
),
|
|
));
|
|
|
|
if (empty($transaction)) {
|
|
$this->Session->setFlash(__('Invalid Item.', true));
|
|
$this->redirect(array('action'=>'index'));
|
|
}
|
|
|
|
$transaction['Account']['link'] =
|
|
$transaction['Account']['level'] >=
|
|
$this->Permission->level('controller.accounts');
|
|
|
|
if ($transaction['Transaction']['type'] === 'DEPOSIT')
|
|
$this->addSideMenuLink('View Slip',
|
|
array('action' => 'deposit_slip', $id), null,
|
|
'ACTION');
|
|
|
|
$this->addSideMenuLink('Destroy',
|
|
array('action' => 'destroy', $id),
|
|
array('confirmMessage' =>
|
|
"This may leave the database in an unstable state." .
|
|
" Do NOT do this unless you know what you're doing." .
|
|
" Proceed anyway?"),
|
|
'ACTION', $this->admin_area);
|
|
|
|
// OK, prepare to render.
|
|
$title = 'Transaction #' . $transaction['Transaction']['id'];
|
|
$this->set(compact('transaction', 'title'));
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
**************************************************************************
|
|
**************************************************************************
|
|
* action: deposit_slip
|
|
* - Special presentation
|
|
* Processes the user input and updates the database
|
|
*/
|
|
|
|
function deposit_slip($id) {
|
|
// Find the deposit transaction
|
|
$this->Transaction->id = $id;
|
|
$deposit = $this->Transaction->find('first', array('contain' => array('Account')));
|
|
|
|
// Get a summary of all forms of tender in the deposit
|
|
$tenders = $this->Transaction->find
|
|
('all',
|
|
array('link' => array('DepositTender' =>
|
|
array('fields' => array(),
|
|
'TenderType',
|
|
'LedgerEntry' =>
|
|
array('fields' => array()))),
|
|
'fields' => array(//'TenderType.id', 'TenderType.name',
|
|
"COUNT(DepositTender.id) AS 'count'",
|
|
"SUM(LedgerEntry.amount) AS 'total'"),
|
|
//'conditions' => array(array('DepositTender.deposit_transaction_id' => $id)),
|
|
'conditions' => array(array('Transaction.id' => $id)),
|
|
'group' => 'TenderType.id',
|
|
));
|
|
|
|
// Verify the deposit exists, and that something was actually deposited
|
|
if (empty($deposit) || empty($tenders)) {
|
|
$this->Session->setFlash(__('Invalid Deposit.', true));
|
|
$this->redirect(array('action'=>'deposit'));
|
|
}
|
|
|
|
// Add the summary to our deposit slip data container
|
|
$deposit['types'] = array();
|
|
foreach ($tenders AS $tender) {
|
|
$deposit['types'][$tender['TenderType']['id']] =
|
|
$tender['TenderType'] + $tender[0];
|
|
}
|
|
|
|
$deposit_total = 0;
|
|
foreach ($deposit['types'] AS $type)
|
|
$deposit_total += $type['total'];
|
|
|
|
if (abs($deposit['Transaction']['amount'] - $deposit_total) >= .001)
|
|
$this->INTERNAL_ERROR("Deposit items ($deposit_total) do not add up to deposit slip total (".$deposit['Transaction']['amount'].")");
|
|
|
|
$this->addSideMenuLink('View',
|
|
array('action' => 'view', $id), null,
|
|
'ACTION');
|
|
|
|
$title = 'Deposit Slip';
|
|
$this->set(compact('title', 'deposit'));
|
|
$this->render('deposit_slip');
|
|
return;
|
|
}
|
|
|
|
}
|