'Transactions', 'header' => true), array('name' => 'All', 'url' => array('controller' => 'transactions', 'action' => 'all')), ); /************************************************************************** ************************************************************************** ************************************************************************** * override: sideMenuLinks * - Generates controller specific links for the side menu */ function sideMenuLinks() { return array_merge(parent::sideMenuLinks(), $this->sidemenu_links); } /************************************************************************** ************************************************************************** ************************************************************************** * action: index / all * - Generate a listing of transactions */ function index() { $this->all(); } function all() { $this->jqGridView('All Transactions', 'all'); } /************************************************************************** ************************************************************************** ************************************************************************** * virtuals: jqGridData * - With the application controller handling the jqGridData action, * these virtual functions ensure that the correct data is passed * to jqGrid. */ function jqGridRecordLinks(&$params, &$model, &$records, $links) { $links['Transaction'] = array('id'); return parent::jqGridRecordLinks($params, $model, $records, $links); } /************************************************************************** ************************************************************************** ************************************************************************** * action: view * - Displays information about a specific transaction */ function view($id = null) { if (!$id) { $this->Session->setFlash(__('Invalid Item.', true)); $this->redirect(array('action'=>'index')); } $transaction = $this->Transaction->find ('first', array('contain' => array(// Models 'LedgerEntry' => array('fields' => array('LedgerEntry.id', 'LedgerEntry.amount', 'LedgerEntry.comment'), //Models 'DebitLedger' => array ('fields' => array('DebitLedger.id', 'DebitLedger.sequence'), 'Account' => array ('fields' => array('Account.id', 'Account.name')), ), 'CreditLedger' => array ('fields' => array('CreditLedger.id', 'CreditLedger.sequence'), 'Account' => array ('fields' => array('Account.id', 'Account.name')), ), ), ), 'conditions' => array('Transaction.id' => $id), )); // Figure out the transaction total $total = 0; foreach($transaction['LedgerEntry'] AS $entry) $total += $entry['amount']; // OK, prepare to render. $title = 'Transaction #' . $transaction['Transaction']['id']; $this->set(compact('transaction', 'title', 'total')); } /************************************************************************** ************************************************************************** ************************************************************************** * action: postInvoice * - handles the creation of a charge invoice */ function postInvoice() { if (!$this->RequestHandler->isPost()) { echo('

THIS IS NOT A POST FOR SOME REASON

'); return; } /* $this->layout = null; */ /* $this->autoLayout = false; */ /* $this->autoRender = false; */ /* Configure::write('debug', '0'); */ // Sanitize the transaction data if (!$this->data['Transaction']['comment']) $this->data['Transaction']['comment'] = null; if(empty($this->data['Transaction']['stamp'])) { die("Time/Date not valid"); } // Create some models for convenience $A = new Account(); $C = new Customer(); $L = new Lease(); $L->recursive = -1; $lease = $L->read(null, $this->data['Lease']['id']); // Create a transaction for the invoice $invoice_transaction = new Transaction(); $invoice_transaction->create(); if (!$invoice_transaction->save($this->data['Transaction'], array('validate' => false, ))) { die("Unknown Database Failure"); } $invoice_transaction->read(); // Create a transaction for the A/R $ar_transaction = new Transaction(); $ar_transaction->create(); if (!$ar_transaction->save($this->data['Transaction'], array('validate' => false, ))) { die("Unknown Database Failure"); } $ar_transaction->read(); // Go through the entered charges $grand_total = 0; foreach ($this->data['LedgerEntry'] AS &$entry) { // Invoice Transaction // debit: Invoice credit: Charge $entry['transaction_id'] = $invoice_transaction->id; // Invoice must debit the "invoice" asset... $entry['debit_ledger_id'] = $A->currentLedgerID($A->invoiceAccountID()); // ...and credit the charge ledger // REVISIT 20090706 // The charge page should have a list of all income types // and thus the field _should_ contain a valid account // name. At the moment, however, I'm still cobbling things // together, and only have two types. /* $entry['credit_ledger_id'] */ /* = $A->currentLedgerID($A->nameToID($entry['charge_account'])); */ if ($entry['charge_type'] === 'rent') { $entry['credit_ledger_id'] = $A->currentLedgerID($A->rentAccountID()); } elseif ($entry['charge_type'] === 'late') { $entry['credit_ledger_id'] = $A->currentLedgerID($A->lateChargeAccountID()); } else { die("Invalid charge account"); } $entry['customer_id'] = $lease['Lease']['customer_id']; $entry['lease_id'] = $lease['Lease']['id']; // Create it $invoice_entry = new LedgerEntry(); $invoice_entry->create(); if (!$invoice_entry->save($entry, false)) { die("Unknown Database Failure"); } $invoice_entry->read(); $grand_total += $entry['amount']; } // Create an account receivable entry // debit: A/R credit: Invoice $ar_entry_data = array ('debit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID()), 'credit_ledger_id' => $A->currentLedgerID($A->invoiceAccountID()), 'transaction_id' => $ar_transaction->id, 'amount' => $grand_total, 'lease_id' => $lease['Lease']['id'], 'customer_id' => $lease['Lease']['customer_id'], ); // Create a new A/R entry from the data $ar_entry = new LedgerEntry(); $ar_entry->create(); if (!$ar_entry->save($ar_entry_data, false)) { die("Unknown Database Failure"); } // Reconcile the Invoice account. Our two entries look like: // debit: Invoice credit: Charge // debit: A/R credit: Invoice // Since this is from the perspective of the Invoice account, // the credit entry is the Invoice<->A/R, and the debit // entry is the actual invoice ledger entry. $R = new Reconciliation(); $R->create(); if (!$R->save(array('debit_ledger_entry_id' => $invoice_entry->id, 'credit_ledger_entry_id' => $ar_entry->id, 'amount' => $grand_total), false)) { die("Unknown Database Failure"); } // Comment this out to debug $this->redirect($this->data['redirect']); pr($this->data['redirect']); $this->render('/empty'); } /************************************************************************** ************************************************************************** ************************************************************************** * action: postReceipt * - handles the creation of a payment receipt */ function postReceipt() { if (!$this->RequestHandler->isPost()) { echo('

THIS IS NOT A POST FOR SOME REASON

'); return; } $this->layout = null; $this->autoLayout = false; $this->autoRender = false; Configure::write('debug', '0'); // Sanitize the transaction data if (!$this->data['Transaction']['comment']) $this->data['Transaction']['comment'] = null; if(empty($this->data['Transaction']['stamp'])) { die("Time/Date not valid"); } pr($this->data['Transaction']); // Create some models for convenience $A = new Account(); $C = new Customer(); // Create a transaction for the receipt $receipt_transaction = new Transaction(); $receipt_transaction->create(); if (!$receipt_transaction->save($this->data['Transaction'], array('validate' => false, ))) { pr(array('checkpoint' => "receipt transaction save failed")); die("Unknown Database Failure"); } pr("New Transaction Created ({$receipt_transaction->id})!"); $receipt_transaction->read(); pr($receipt_transaction->data); // Create a transaction for the splits $split_transaction = new Transaction(); $split_transaction->create(); if (!$split_transaction->save($this->data['Transaction'], array('validate' => false, ))) { pr(array('checkpoint' => "split transaction save failed")); die("Unknown Database Failure"); } pr("New Transaction Created ({$split_transaction->id})!"); $split_transaction->read(); pr($split_transaction->data); // Go through the entered payments foreach ($this->data['LedgerEntry'] AS &$entry) { // Get the Monetary Source squared away if ($entry['monetary_type_name'] === 'Cash') { // No distinguishing features of Cash, just // use the shared monetary source $entry['monetary_source_id'] = $this->Transaction->LedgerEntry->MonetarySource->nameToID('Cash'); unset($entry['MonetarySource']); } else { // The monetary source needs to be unique // Create a new one dedicated to this entry $entry['MonetarySource']['monetary_type_id'] = $this->Transaction->LedgerEntry->MonetarySource->MonetaryType ->nameToID($entry['monetary_type_name']); $entry['MonetarySource']['name'] = $this->Transaction->LedgerEntry->MonetarySource->MonetaryType ->nameToID($entry['monetary_type_name']); // Give it a fancy name based on the check number $entry['MonetarySource']['name'] = $entry['monetary_type_name']; if ($entry['monetary_type_name'] === 'Check' || $entry['monetary_type_name'] === 'Money Order') { $entry['MonetarySource']['name'] .= ' #' . $entry['MonetarySource']['data1']; } } // This entry of physical money is part of the receipt transaction // debit: Cash/Check/Etc credit: Receipt $entry['transaction_id'] = $receipt_transaction->id; // Receipt must debit the "money" asset (bank, cash, check, etc)... $entry['debit_ledger_id'] = $A->currentLedgerID($A->nameToID($entry['monetary_type_name'])); // ...and credit the Receipt ledger $entry['credit_ledger_id'] = $A->currentLedgerID($A->receiptAccountID()); $entry['customer_id'] = $this->data['customer_id']; // Create it $receipt_entry = new LedgerEntry(); $receipt_entry->create(); if (!$receipt_entry->saveAll($entry, array('validate' => false, ))) { pr(array('checkpoint' => "receipt entry saveAll failed")); die("Unknown Database Failure"); } pr("New Receipt LedgerEntry Created ({$receipt_entry->id})!"); $receipt_entry->read(); pr($receipt_entry->data); $reconciled = $C->reconcileNewLedgerEntry($this->data['customer_id'], 'credit', $entry['amount']); pr(compact('entry', 'reconciled')); foreach (array_merge($reconciled['debit']['entry'], array (array('id' => null, 'applied' => $reconciled['debit']['unapplied'], 'customer_id' => $this->data['customer_id'], 'lease_id' => null))) AS $rec) { pr(array('checkpoint' => "Handle Reconciled Entry", compact('rec'), )); if (!$rec['applied']) continue; // Create an entry to handle the splitting of the funds ("Payment") // Payment must debit the Receipt ledger, and credit the A/R ledger // debit: Receipt credit: A/R $split_entry_data = array ('debit_ledger_id' => $A->currentLedgerID($A->receiptAccountID()), 'credit_ledger_id' => $A->currentLedgerID($A->accountReceivableAccountID()), 'transaction_id' => $split_transaction->id, 'amount' => $rec['applied'], 'lease_id' => $rec['lease_id'], 'customer_id' => $rec['customer_id'], ); // Create a new split entry from the data $split_entry = new LedgerEntry(); $split_entry->create(); if (!$split_entry->save($split_entry_data, array('validate' => false, ))) { pr(array('checkpoint' => "split entry save failed")); die("Unknown Database Failure"); } pr("New Split LedgerEntry Created ({$split_entry->id})!"); $split_entry->read(); pr($split_entry->data); // Reconcile the Receipt account. Our two entries look like: // debit: Cash/Check/Etc credit: Receipt // debit: Receipt credit: A/R // Since this is from the perspective of the Receipt account, // the debit entry is the Receipt<->A/R, and the credit // entry is the actual receipt ledger entry. $R = new Reconciliation(); $R->create(); if (!$R->save(array('debit_ledger_entry_id' => $split_entry->id, 'credit_ledger_entry_id' => $receipt_entry->id, 'amount' => $rec['applied']), array('validate' => false, ))) { pr(array('checkpoint' => "receipt reconcile save failed")); die("Unknown Database Failure"); } pr("New Receipt Reconciliation Created ({$R->id})!"); $R->read(); pr($R->data); // Only reconcile the A/R account if we have an entry // to reconcile with, otherwise, just go on. if (!$rec['id']) continue; // Reconcile the A/R account. Our two entries look like: // debit: Receipt credit: A/R // debit: A/R credit: Invoice // Since this is from the perspective of the A/R account, // the debit entry is the Invoice<->A/R, and the credit // entry is the Receipt<->A/R. $R = new Reconciliation(); $R->create(); if (!$R->save(array('debit_ledger_entry_id' => $rec['id'], 'credit_ledger_entry_id' => $split_entry->id, 'amount' => $rec['applied']), array('validate' => false, ))) { pr(array('checkpoint' => "split reconcile save failed")); die("Unknown Database Failure"); } pr("New Split Reconciliation Created ({$R->id})!"); $R->read(); pr($R->data); } } } }