From 44df78e69f53a376e9614c74cfc1d7acd8c9cf80 Mon Sep 17 00:00:00 2001 From: abijah Date: Wed, 1 Jul 2009 08:17:31 +0000 Subject: [PATCH] Finally, finally... a working version for payment entry. The current schema is working well, and seems to handle our technical needs. However, it does seem to be very confusing with the extra accounts. Nonetheless, it does work and so I'll keep going down this path. This checkin also includes a mechanism to close the books on an account (by closing the underlying ledger) and start a new ledger. One of the decisions worth revisiting is separating out ledger entries that are really part of the same transaction. Without this change, inspecting a transaction results in the transaction total being off by a factor of two, since all money movement is in their twice (once for the expected reason, and again to hit the invoice/receipt ledger). git-svn-id: file:///svn-source/pmgr/branches/invoice_receipt_20090629@195 97e9348a-65ac-dc4b-aefc-98561f571b83 --- db/schema.sql | 14 +- scripts/sitelink2pmgr.pl | 34 +- site/app_model.php | 11 +- site/controllers/accounts_controller.php | 25 ++ site/controllers/transactions_controller.php | 342 ++++++++++--------- site/models/account.php | 47 ++- site/models/ledger.php | 66 ++++ site/models/ledger_entry.php | 10 + site/models/reconciliation.php | 15 + site/models/transaction.php | 8 +- site/views/accounts/view.ctp | 2 +- site/views/customers/payment.ctp | 51 +-- site/views/elements/accounts.ctp | 4 +- site/views/elements/jqGrid.ctp | 4 +- site/views/elements/ledger_entries.ctp | 16 +- site/views/elements/ledgers.ctp | 7 +- site/views/ledger_entries/view.ctp | 2 - site/views/monetary_sources/view.ctp | 4 + 18 files changed, 455 insertions(+), 207 deletions(-) create mode 100644 site/models/reconciliation.php diff --git a/db/schema.sql b/db/schema.sql index 44c495c..ad6daa4 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -1007,8 +1007,20 @@ CREATE TABLE `pmgr_monetary_sources` ( -- REVISIT : 20090605 -- Check Number; -- Routing Number, Account Number; - -- Card Number, Expiration Date; CCV2 Code + -- Card Number, Expiration Date; CVV2 Code -- etc. + -- REVISIT 20090630 + -- I _think_ that CVV2 is NEVER supposed to + -- be stored ANYWHERE. Merchants agree to + -- use it only to verify the transaction and + -- then leave no record of it, so that even + -- if their security is compromised, no one + -- will know the CVV2 code unless they are + -- in physical possession of the card. + `data1` VARCHAR(80) DEFAULT NULL, + `data2` VARCHAR(80) DEFAULT NULL, + `data3` VARCHAR(80) DEFAULT NULL, + `data4` VARCHAR(80) DEFAULT NULL, `comment` VARCHAR(255) DEFAULT NULL, diff --git a/scripts/sitelink2pmgr.pl b/scripts/sitelink2pmgr.pl index a37d282..d91667c 100644 --- a/scripts/sitelink2pmgr.pl +++ b/scripts/sitelink2pmgr.pl @@ -868,6 +868,13 @@ foreach $row (@{query($sdbh, $query)}) { 'amount' => $row->{'InvoiceAmount'}, } }; + addRow('transactions', + { 'stamp' => datefmt($row->{'ChargeDate'}), + 'through_date' => datefmt($row->{'EndDate'}) }); + + $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'invoice'}{'charge_tx'} + = $newdb{'tables'}{'transactions'}{'autoid'}; + # Invoice must debit the A/R ledger... $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'invoice'}{'debit_ledger_id'} = $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'}; @@ -900,7 +907,7 @@ $query = "SELECT * FROM Charges ORDER BY ChargeID"; foreach $row (@{query($sdbh, $query)}) { $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'tx'} - = $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'invoice'}{'tx'}; + = $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'invoice'}{'charge_tx'}; $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_id'} = $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'customer_id'}; $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_id'} @@ -1077,7 +1084,15 @@ foreach $row (@{query($sdbh, $query)}) { { 'stamp' => datefmt($row->{'ReceiptDate'}), 'through_date' => undef }); $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}} - = {'tx' => $newdb{'tables'}{'transactions'}{'autoid'} }; + = {'tx' => $newdb{'tables'}{'transactions'}{'autoid'}, + 'date' => datefmt($row->{'ReceiptDate'}), + }; + + addRow('transactions', + { 'stamp' => datefmt($row->{'ReceiptDate'}), + 'through_date' => undef }); + $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'payment_tx'} + = $newdb{'tables'}{'transactions'}{'autoid'}; } if ($row->{'ReceiptDate'} =~ m%3/25/2009%) { @@ -1098,12 +1113,15 @@ foreach $row (@{query($sdbh, $query)}) { # Set up a monetary source for the receipt, if (!$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'monetary_source_id'}) { my $name = $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'name'}; + my $data1; if ($name eq 'Check') { $name = 'Check #' . $row->{'CheckNum'}; + $data1 = $row->{'CheckNum'}; } addRow('monetary_sources', { 'monetary_type_id' => $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'monetary_type'}{'id'}, 'name' => $name, + 'data1' => $data1, 'comment' => "Receipt:$row->{'ReceiptNum'}; Payment:$row->{'PaymentType'}; Check:$row->{'CheckNum'}" }); $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'monetary_source_id'} @@ -1148,7 +1166,15 @@ $newdb{'lookup'}{'payment'} = {}; $query = "SELECT * FROM Payments ORDER BY PaymentID"; foreach $row (@{query($sdbh, $query)}) { - $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}} = {}; +# addRow('transactions', +# { 'stamp' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'date'}, +# 'through_date' => undef }); +# $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}} +# = {'tx' => $newdb{'tables'}{'transactions'}{'autoid'} }; + + $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}} + = { 'tx' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'payment_tx'} }; + # NOTE THE ABOVE LARGE COMMENT BLOCK # The choice of credit/debit ledgers does not mirror the @@ -1172,7 +1198,7 @@ foreach $row (@{query($sdbh, $query)}) # debit: Receipt credit: A/R addRow('ledger_entries', { 'monetary_source_id' => $newdb{'ids'}{'monetary_source'}{'internal'}, - 'transaction_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'tx'}, + 'transaction_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'tx'}, 'debit_ledger_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'debit_ledger_id'}, 'credit_ledger_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'credit_ledger_id'}, 'customer_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_id'}, diff --git a/site/app_model.php b/site/app_model.php index 14fff2d..f2f0197 100644 --- a/site/app_model.php +++ b/site/app_model.php @@ -137,7 +137,16 @@ class AppModel extends Model { */ function dateFormatBeforeSave($dateString) { - return date('Y-m-d', strtotime($dateString)); +/* $time = ''; */ +/* if (preg_match('/(\d+(:\d+))/', $dateString, $match)) */ +/* $time = ' '.$match[1]; */ +/* $dateString = preg_replace('/(\d+(:\d+))/', '', $dateString); */ +/* return date('Y-m-d', strtotime($dateString)) . $time; */ + + if (preg_match('/:/', $dateString)) + return date('Y-m-d H:i:s', strtotime($dateString)); + else + return date('Y-m-d', strtotime($dateString)); } } diff --git a/site/controllers/accounts_controller.php b/site/controllers/accounts_controller.php index c35989a..d957f10 100644 --- a/site/controllers/accounts_controller.php +++ b/site/controllers/accounts_controller.php @@ -119,6 +119,25 @@ class AccountsController extends AppController { } + /************************************************************************** + ************************************************************************** + ************************************************************************** + * action: newledger + * - Close the current account ledger and create a new one, + * carrying forward any balance if necessary. + */ + + function newledger($id = null) { + if (!$this->Account->closeCurrentLedger($id)) { + $this->Session->setFlash(__('Unable to create new Ledger.', true)); + } + if ($id) + $this->redirect(array('action'=>'view', $id)); + else + $this->redirect(array('action'=>'index')); + } + + /************************************************************************** ************************************************************************** ************************************************************************** @@ -160,8 +179,14 @@ class AccountsController extends AppController { $stats = $this->Account->stats($id, true); $stats = $stats['Ledger']; + $this->sidemenu_links[] = + array('name' => 'Operations', 'header' => true); + $this->sidemenu_links[] = + array('name' => 'New Ledger', 'url' => array('action' => 'newledger', $id)); + // Prepare to render $title = 'Account: ' . $account['Account']['name']; $this->set(compact('account', 'title', 'stats')); } + } diff --git a/site/controllers/transactions_controller.php b/site/controllers/transactions_controller.php index e4a3f1f..8f182cf 100644 --- a/site/controllers/transactions_controller.php +++ b/site/controllers/transactions_controller.php @@ -103,186 +103,204 @@ class TransactionsController extends AppController { */ function postReceipt() { - $this->autoRender = false; - if (!$this->RequestHandler->isPost()) { echo('

THIS IS NOT A POST FOR SOME REASON

'); return; } - //pr(array('thisdata' => $this->data)); - if (isset($this->data['customer_id'])) { - $C = new Customer(); - $C->recursive = -1; - $customer = $C->find - ('first', - array('contain' => array('Account.CurrentLedger.id'), - 'fields' => false, - 'conditions' => array('Customer.id', $this->data['customer_id']), - )); - $ledger_id = $customer['Account']['CurrentLedger']['id']; - } - else { - // Payment by Unit, Lease, etc - $ledger_id = 0; + $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']); - $amount = 0; - foreach ($this->data['LedgerEntry'] AS &$entry) { - $reconciled = $C->reconcileNewLedgerEntry($this->data['customer_id'], - 'credit', - $entry['amount']); - pr(compact('entry', 'reconciled')); - - foreach ($reconciled['debit']['entry'] AS $rec) { - $entry['DebitReconciliationLedgerEntry'] = - array('amount' => $rec['applied'], - //'debit_ledger_entry_id' - 'credit_ledger_entry_id' => $rec['id'] - ); - } - - $amount += isset($entry['amount']) ? $entry['amount'] : 0; - $entry['debit_ledger_id'] = 6; // Cash/Payments - $entry['credit_ledger_id'] = $ledger_id; - } - - - pr($this->data); - $T = new Transaction(); - $T->create(); - if ($T->saveAll($this->data, - array( - 'validate' => false, - //'fieldList' => array(), - //'callbacks' => true, - ))) { - $tid = $T->id; - $this->Session->setFlash(__("New Transaction Created ($tid)!", true)); - //$this->redirect(array('action'=>'view', $mid)); - } - else { - $this->autoRender = false; - pr(array('checkpoint' => "saveAll failed")); - } - pr($T->data); - + // Create some models for convenience + $A = new Account(); $C = new Customer(); - $LE = new LedgerEntry(); -/* $reconciled = $C->reconcileNewLedgerEntry($this->data['customer_id'], */ -/* 'credit', */ -/* $amount); */ -/* pr(compact('amount', 'unreconciled', 'reconciled')); */ -/* return; */ + // 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')); - continue; - foreach ($reconciled['debit']['entry'] AS $rec) { - $data = array('LedgerEntry' => - array('DebitReconciliationLedgerEntry' => - array('amount' => $rec['applied'], - //'debit_ledger_entry_id' - 'credit_ledger_entry_id' => $rec['id'] - ), - ), - ); - //'DebitReconciliationLedgerEntry' => array( - //pr(compact('amount', 'unreconciled', '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); } } - } - function saveTest() { - $data = - array( -/* 'Customer' => array */ -/* ('id' => 7, */ -/* ), */ - - 'LedgerEntry' => array - ( - '0' => array( - 'amount' => 100, - 'debit_ledger_id' => 1, - 'credit_ledger_id' => 2, - 'MonetarySource' => array('name' => 'testmoney', 'monetary_type_id' => 2), - ), - '1' => array( - 'amount' => 101, - 'debit_ledger_id' => 1, - 'credit_ledger_id' => 2, - 'MonetarySource' => array('name' => 'testmoney2', 'monetary_type_id' => 2), - ), - ), - - 'Transaction' => array - ( - 'stamp' => '06/18/2009', - 'comment' => 'no comment', - ), - ); - - $data = -/* array( */ -/* 'LedgerEntry' => array */ -/* ( */ -/* '0' => */ - array( - 'amount' => 100, - 'debit_ledger_id' => 1, - 'credit_ledger_id' => 2, - 'transaction_id' => 66, - 'DebitReconciliationLedgerEntry' => - array('amount' => 44, - //'debit_ledger_entry_id' - 'credit_ledger_entry_id' => 17, - ), -/* ), */ -/* ), */ - - ); - - //$M = new Transaction(); - $M = new LedgerEntry(); - $M->create(); - $retval = $M->saveAll($data, - array( - 'validate' => false, - 'fieldList' => array(), - 'callbacks' => true, - )); - - $mid = $M->id; - pr(compact('retval', 'mid')); - if ($mid) { - $this->Session->setFlash(__("New Transaction Created ($mid)!", true)); - //$this->redirect(array('action'=>'view', $mid)); - } - else { - $this->autoRender = false; - pr(array('checkpoint' => "saveAll failed")); - } - - -/* $LE = new LedgerEntry(); */ -/* $LE->create(); */ -/* $ret = $LE->save($data, */ -/* array( */ -/* 'validate' => false, */ -/* 'fieldList' => array(), */ -/* 'callbacks' => true, */ -/* )); */ -/* $leid = $LE->id; */ -/* pr(array('checkpoint' => "New Ledger Entry", */ -/* compact('leid', 'ret'))); */ - //pr($LE); - - } } diff --git a/site/models/account.php b/site/models/account.php index 05c5a39..792eda7 100644 --- a/site/models/account.php +++ b/site/models/account.php @@ -92,6 +92,23 @@ class Account extends AppModel { function invoiceAccountID() { return $this->nameToID('Invoice'); } function receiptAccountID() { return $this->nameToID('Receipt'); } + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: currentLedgerID + * - Returns the current ledger ID of the account + */ + function currentLedgerID($id) { + $this->cacheQueries = true; + $item = $this->find('first', array + ('contain' => 'CurrentLedger', + 'conditions' => array('Account.id' => $id), + )); + $this->cacheQueries = false; + return $item['CurrentLedger']['id']; + } + + /************************************************************************** ************************************************************************** @@ -131,6 +148,34 @@ class Account extends AppModel { } + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: closeCurrentLedger + * - Closes the current account ledger, and opens a new one + * with the old balance carried forward. + */ + function closeCurrentLedger($id = null) { + $contain = array('CurrentLedger' => array('fields' => array('CurrentLedger.id'))); + + $this->cacheQueries = true; + $account = $this->find('all', array + ('contain' => $contain, + 'fields' => array(), + 'conditions' => + $id ? array(array('Account.id' => $id)) : array() + )); + $this->cacheQueries = false; + //pr(compact('id', 'account')); + + foreach ($account AS $acct) { + if (!$this->Ledger->closeLedger($acct['CurrentLedger']['id'])) + return false; + } + return true; + } + + /************************************************************************** ************************************************************************** ************************************************************************** @@ -222,7 +267,7 @@ class Account extends AppModel { ('fields' => array(), "LedgerEntry" => array ('class' => "{$ucfund}LedgerEntry", - 'fields' => array('id', 'amount'), + 'fields' => array('id', 'customer_id', 'lease_id', 'amount'), "ReconciliationLedgerEntry" => array ('class' => "{$ucfund}ReconciliationLedgerEntry", 'fields' => array diff --git a/site/models/ledger.php b/site/models/ledger.php index aa10e76..7e159aa 100644 --- a/site/models/ledger.php +++ b/site/models/ledger.php @@ -44,6 +44,72 @@ class Ledger extends AppModel { ); + /************************************************************************** + ************************************************************************** + ************************************************************************** + * function: closeLedger + * - Closes the current ledger, and returns a fresh one + */ + function closeLedger($id) { + $this->recursive = -1; + + $stamp = date('Y-m-d G:i:s'); + $this->id = $id; + $this->read(); + $this->data['Ledger']['close_stamp'] = $stamp; + $this->data['Ledger']['closed'] = 1; + $this->save($this->data, false); + + $stats = $this->stats($id); + + $this->read(); + $this->data['Ledger']['id'] = null; + $this->data['Ledger']['closed'] = 0; + $this->data['Ledger']['open_stamp'] = $stamp; + $this->data['Ledger']['close_stamp'] = null; + $this->data['Ledger']['comment'] = null; + ++$this->data['Ledger']['sequence']; + $this->id = null; + $this->save($this->data, false); + //pr($this->data); + + if ($stats['balance'] == 0) + return $this->id; + + $this->read(); + $ftype = $this->Account->fundamentalType($this->data['Ledger']['account_id']); + $otype = $this->Account->fundamentalOpposite($ftype); + + // Create a transaction for balance transfer + $transaction = new Transaction(); + $transaction->create(); + if (!$transaction->save(array(), + array('validate' => false, + ))) { + return null; + } + + // Create an entry to carry the balance forward + $carry_entry_data = array + ($ftype.'_ledger_id' => $this->id, + $otype.'_ledger_id' => $id, + 'transaction_id' => $transaction->id, + 'amount' => $stats['balance'], + 'comment' => "Ledger Balance Forward", + ); + + $carry_entry = new LedgerEntry(); + $carry_entry->create(); + if (!$carry_entry->save($carry_entry_data, + array('validate' => false, + ))) { + return null; + } + + return $this->id; + } + + /************************************************************************** ************************************************************************** ************************************************************************** diff --git a/site/models/ledger_entry.php b/site/models/ledger_entry.php index b528820..b51b203 100644 --- a/site/models/ledger_entry.php +++ b/site/models/ledger_entry.php @@ -8,6 +8,16 @@ class LedgerEntry extends AppModel { 'amount' => array('money') ); + var $hasMany = array( + 'DebitReconciliation' => array( + 'className' => 'Reconciliation', + 'foreignKey' => 'debit_ledger_entry_id', + ), + 'CreditReconciliation' => array( + 'className' => 'Reconciliation', + 'foreignKey' => 'credit_ledger_entry_id', + ), + ); var $belongsTo = array( 'MonetarySource', 'Transaction', diff --git a/site/models/reconciliation.php b/site/models/reconciliation.php new file mode 100644 index 0000000..214b3d0 --- /dev/null +++ b/site/models/reconciliation.php @@ -0,0 +1,15 @@ + array( + 'className' => 'LedgerEntry', + //'foreignKey' => 'credit_ledger_entry_id', + ), + 'CreditLedgerEntry' => array( + 'className' => 'LedgerEntry', + //'foreignKey' => 'credit_ledger_entry_id', + ), + ); + +} diff --git a/site/models/transaction.php b/site/models/transaction.php index 2c22348..e7ccb03 100644 --- a/site/models/transaction.php +++ b/site/models/transaction.php @@ -7,7 +7,6 @@ class Transaction extends AppModel { /* ); */ var $belongsTo = array( - 'Customer', ); var $hasMany = array( @@ -17,10 +16,15 @@ class Transaction extends AppModel { function beforeSave() { - if(!empty($this->data['Transaction']['stamp'])) { + if(isset($this->data['Transaction']['stamp']) && + $this->data['Transaction']['stamp'] !== 'CURRENT_TIMESTAMP') { $this->data['Transaction']['stamp'] = $this->dateFormatBeforeSave($this->data['Transaction']['stamp']); } + else { + $this->data['Transaction']['stamp'] = null; + } + return true; } diff --git a/site/views/accounts/view.ctp b/site/views/accounts/view.ctp index d31b926..cf21063 100644 --- a/site/views/accounts/view.ctp +++ b/site/views/accounts/view.ctp @@ -65,7 +65,7 @@ echo $this->element('ledgers', */ echo $this->element('ledger_entries', - array('caption' => "Current Ledger: (#{$account['CurrentLedger']['sequence']})", + array('caption' => "Current Ledger: (#{$account['Account']['id']}-{$account['CurrentLedger']['sequence']})", 'ledger_id' => $account['CurrentLedger']['id'], 'account_type' => $account['Account']['type'], )); diff --git a/site/views/customers/payment.ctp b/site/views/customers/payment.ctp index 4c3dac4..1ac95c0 100644 --- a/site/views/customers/payment.ctp +++ b/site/views/customers/payment.ctp @@ -148,6 +148,17 @@ $grid_setup['onSelectRow'] = array $('#payments').html(''); $('#payment-id').val(0); addPaymentSource(false); + datepickerNow(); + } + + function datepickerNow() { + now = new Date(); + $("#datepicker").val($.datepicker.formatDate('mm/dd/yy', now) + + ' ' + + (now.getHours() < 10 ? '0' : '') + + now.getHours() + ':' + + (now.getMinutes() < 10 ? '0' : '') + + now.getMinutes()); } function addPaymentSource(flash) { @@ -158,16 +169,6 @@ $grid_setup['onSelectRow'] = array '
' + 20090616: - * MUST GET THIS FROM THE DATABASE!! - * HARDCODED VALUES BAD... VERY BAD... - */ - $monetary_type_ids = array('Cash' => 2, - 'Check' => 3, - 'Money Order' => 4, - 'ACH' => 5, - 'Credit Card' => 7, - ); $types = array(); foreach(array('Cash', 'Check', 'Money Order', /*'ACH', 'Credit Card'*/) AS $name) @@ -175,11 +176,10 @@ $grid_setup['onSelectRow'] = array foreach ($types AS $type => $name) { $div = '
'; - $div .= ''; - $div .= ''; + $div .= ' VALUE="'.$name.'" ' . ($name == 'Cash' ? 'CHECKED ' : '') . '/>'; $div .= ' '; $div .= '
'; echo "'$div' +\n"; @@ -228,7 +228,7 @@ function switchPaymentType(paymentid, type) { '
' + ' ' + // REVISIT : 20090617: Use comment field for now. - ' ' + '
'; break; @@ -238,7 +238,7 @@ function switchPaymentType(paymentid, type) { '
' + ' ' + // REVISIT : 20090617: Use comment field for now. - ' ' + '
'; break; @@ -248,14 +248,14 @@ function switchPaymentType(paymentid, type) { '
' + ' ' + // REVISIT : 20090617: Use comment field for now. - ' ' + '
' + '
' + ' ' + // REVISIT : 20090617: Use comment field for now. - ' ' + '
'; break; @@ -265,21 +265,21 @@ function switchPaymentType(paymentid, type) { '
' + ' ' + // REVISIT : 20090617: Use comment field for now. - ' ' + '
' + '
' + ' ' + // REVISIT : 20090617: Use comment field for now. - ' ' + '
' + '
' + ' ' + // REVISIT : 20090617: Use comment field for now. - ' ' + '
'; break; @@ -436,7 +436,8 @@ echo $form->create(null, array('id' => 'payment-form',
' . "\n"; +echo 'Date: '; +echo ' Now
' . "\n"; echo 'Comment:
' . "\n"; echo $form->end('Post Payment'); @@ -457,8 +458,12 @@ echo $form->end('Post Payment');