First pass at making ACH items auto-deposit. Things are really set up for a separate deposit transaction though, and I should just bite the bullet and do that instead. I don't want them to show up as Deposits though, but perhaps it would be easiest just to make a new type 'AUTO_DEPOSIT' or something.

git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@607 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
abijah
2009-08-17 21:16:16 +00:00
parent 3eb989e03c
commit 709689b15b
4 changed files with 225 additions and 22 deletions

View File

@@ -1148,6 +1148,9 @@ CREATE TABLE `pmgr_tender_types` (
-- include credit cards, debit cards, and ACH transfers.
`tillable` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
-- Should these items be deposited automatically?
`auto_deposit` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
-- Names of the 4 data fields (or NULL if not used)
-- Not the most robust of solutions, especially since
-- it requires (or strongly implicates) that all fields
@@ -1171,6 +1174,10 @@ CREATE TABLE `pmgr_tender_types` (
-- account, either distinct or non-distinct from others
`account_id` INT(10) UNSIGNED NOT NULL,
-- Which account should these items be deposited in?
-- This may or may not actually be used for all types
-- but will likely get used for auto deposit items.
`deposit_account_id` INT(10) UNSIGNED DEFAULT NULL,
`comment` VARCHAR(255) DEFAULT NULL,

View File

@@ -567,7 +567,9 @@ foreach my $tender_name ('Cash', 'Check', 'Money Order', 'ACH',
addRow('tender_types', {
'name' => $tender_name,
'account_id' => $newdb{'lookup'}{'account'}{$tender_name}{'account_id'},
'deposit_account_id' => $newdb{'lookup'}{'account'}{'Bank'}{'account_id'},
'tillable' => $tillable,
'auto_deposit' => ($tender_name eq 'ACH') ? 1 : 0,
'data1_name' => $name1,
'data2_name' => $name2,
'data3_name' => $name3,

View File

@@ -50,7 +50,7 @@ class Transaction extends AppModel {
);
//var $default_log_level = array('log' => 30, 'show' => 15);
var $default_log_level = array('log' => 30, 'show' => 15);
//var $max_log_level = 10;
/**************************************************************************
@@ -121,23 +121,180 @@ class Transaction extends AppModel {
'lease_id' => $lease_id,
);
// Go through the statement entries and flag as disbursements
foreach ($data['Entry'] AS &$entry)
$entry += array('type' => 'DISBURSEMENT', // not used
'account_id' =>
(isset($entry['Tender']['tender_type_id'])
? ($this->LedgerEntry->Tender->TenderType->
accountID($entry['Tender']['tender_type_id']))
: null),
);
// Go through the statement entries, making sure the tender
// is recorded into the correct account, and then performing
// an auto-deposit if necessary.
$deposit = array();
foreach ($data['Entry'] AS &$entry) {
if (empty($entry['Tender']['tender_type_id']))
continue;
$ttype = $this->LedgerEntry->Tender->TenderType->find
('first', array('contain' => false,
'conditions' =>
array('id' => $entry['Tender']['tender_type_id'])));
$ttype = $ttype['TenderType'];
// Set the account for posting.
$entry += array('account_id' => $ttype['account_id']);
/* // Check for auto deposit */
/* if (!empty($ttype['auto_deposit'])) { */
/* $deposit[] = array('id' => 0, */
/* 'account_id' => $ttype['deposit_account_id']); */
/* } */
}
unset($entry); // prevent trouble since $entry is reference
$ids = $this->addTransaction($data['control'], $data['Transaction'], $data['Entry']);
if (isset($ids['transaction_id']))
$ids['receipt_id'] = $ids['transaction_id'];
if (!empty($ids['error']))
return $this->prReturn(array('error' => true) + $ids);
$tender_ids = array();
foreach ($ids['entries'] AS $entry) {
$entry1 = $entry['DoubleEntry']['Entry1'];
if (!empty($entry1['Tender']['tender_id']))
$tender_ids[] = $entry1['Tender']['tender_id'];
}
$deposit_tenders = $this->LedgerEntry->Tender->find
('all', array('contain' => array('TenderType' => array('fields' => array()),
'LedgerEntry' => array('fields' => array()),
),
'fields' => array('TenderType.deposit_account_id',
'TenderType.account_id',
'CONCAT("CREDIT") AS crdr',
'CONCAT("Auto Deposit") AS comment',
'SUM(LedgerEntry.amount) AS amount'),
'conditions' => array('Tender.id' => $tender_ids,
'TenderType.auto_deposit' => true,
),
'group' => 'TenderType.deposit_account_id',
));
if (!empty($deposit_tenders)) {
foreach ($deposit_tenders AS &$tender)
$tender = $tender[0] + array_diff_key($tender['TenderType'], array('id'=>1));
$this->pr(10, compact('tender_ids', 'deposit_tenders'));
// REVISIT <AP>: 20090817
// Multiple tenders could result in deposits to more than one
// account. We're already mucking with things by having a
// ledger entry that's not involved with the account_id of the
// transaction. We could handle this by not using the helper
// _splitEntries function, and just building or individual
// entries right here (which we should probably do anyway).
// However, I'm ignoring the issue for now...
if (count($deposit_tenders) > 1)
$this->INTERNAL_ERROR("Only expecting one tender type");
$deposit_ids = $this->addTransactionEntries
(array('include_ledger_entry' => true,
'include_statement_entry' => false,
),
array('id' => $ids['transaction_id'],
// REVISIT <AP>: 20090817
// This is an awful cheat, and we're going to
// get burned from it someday.
'type' => 'DEPOSIT',
'crdr' => 'DEBIT',
'account_id' => $deposit_tenders[0]['deposit_account_id'],
),
$deposit_tenders);
$ids['deposit'] = $deposit_ids;
if (!empty($deposit_ids['error']))
return $this->prReturn(array('error' => true) + $ids);
if (!empty($tender_ids))
$this->LedgerEntry->Tender->updateAll
(array('Tender.deposit_transaction_id' => $ids['transaction_id']),
array('Tender.id' => $tender_ids)
);
}
return $this->prReturn($ids);
}
// REVISIT <AP>: 20090817
// Delete after rolling up the old items
function temp_auto_deposit_old_ach_items() {
$all_tenders = $this->LedgerEntry->Tender->find
('all', array('link' => array('TenderType',
'LedgerEntry' =>
array('Transaction')),
'conditions' => array(array('TenderType.auto_deposit' => true),
array('Tender.deposit_transaction_id' => null)),
));
//$this->pr(10, compact('all_tenders'));
foreach ($all_tenders AS $cur_tender) {
$tender_ids = array($cur_tender['Tender']['id']);
$ids = array('transaction_id' => $cur_tender['Transaction']['id']);
$tenders = $this->LedgerEntry->Tender->find
('all', array('contain' => array('TenderType' => array('fields' => array()),
'LedgerEntry' => array('fields' => array()),
),
'fields' => array('TenderType.deposit_account_id',
'TenderType.account_id',
'CONCAT("CREDIT") AS crdr',
'CONCAT("Auto Deposit") AS comment',
'SUM(LedgerEntry.amount) AS amount'),
'conditions' => array('Tender.id' => $tender_ids,
'TenderType.auto_deposit' => true,
),
'group' => 'TenderType.deposit_account_id',
));
foreach ($tenders AS &$tender)
$tender = $tender[0] + array_diff_key($tender['TenderType'], array('id'=>1));
$this->pr(10, compact('tender_ids', 'tenders'));
// REVISIT <AP>: 20090817
// Multiple tenders could result in deposits to more than one
// account. We're already mucking with things by having a
// ledger entry that's not involved with the account_id of the
// transaction. We could handle this by not using the helper
// _splitEntries function, and just building or individual
// entries right here (which we should probably do anyway).
// However, I'm ignoring the issue for now...
if (count($tenders) > 1)
$this->INTERNAL_ERROR("Only expecting one tender type");
$deposit_ids = $this->addTransactionEntries
(array('include_ledger_entry' => true,
'include_statement_entry' => false,
),
array('id' => $ids['transaction_id'],
// REVISIT <AP>: 20090817
// This is an awful cheat, and we're going to
// get burned from it someday.
'type' => 'DEPOSIT',
'crdr' => 'DEBIT',
'account_id' => $tenders[0]['deposit_account_id'],
),
$tenders);
if (empty($deposit_ids['error'])) {
if (!empty($tender_ids))
$this->LedgerEntry->Tender->updateAll
(array('Tender.deposit_transaction_id' => $ids['transaction_id']),
array('Tender.id' => $tender_ids)
);
}
}
}
/**************************************************************************
**************************************************************************
@@ -279,6 +436,7 @@ class Transaction extends AppModel {
array('assign' => false,
'include_ledger_entry' => true,
'include_statement_entry' => false,
'allow_no_entries' => true,
);
// Establish the transaction as a close
@@ -656,7 +814,7 @@ class Transaction extends AppModel {
// Verify that we have a transaction and entries
if (empty($transaction) ||
($transaction['type'] !== 'CLOSE' && empty($entries)))
(empty($entries) && empty($control['allow_no_entries'])))
return $this->prReturn(array('error' => true));
// set ledger ID as the current ledger of the specified account
@@ -902,16 +1060,20 @@ class Transaction extends AppModel {
}
}
// Add the sole ledger entry for this transaction
$rollback['Entry'][] =
array('include_ledger_entry' => true,
'include_statement_entry' => false,
'amount' => $rollback['Transaction']['amount'],
'account_id' => $this->Account->accountReceivableAccountID(),
);
// Add the sole ledger entry for this transaction. If there
// is not a transaction amount, then there is no point in
// recording a ledger entry of $0.00
if (!empty($rollback['Transaction']['amount'])) {
$rollback['Entry'][] =
array('include_ledger_entry' => true,
'include_statement_entry' => false,
'amount' => $rollback['Transaction']['amount'],
'account_id' => $this->Account->accountReceivableAccountID(),
);
// Set the transaction amount to be negative
$rollback['Transaction']['amount'] *= -1;
// Set the transaction amount to be negative
$rollback['Transaction']['amount'] *= -1;
}
// Record the transaction, which will un-pay previously paid
// charges, void any credits, and other similar work.
@@ -966,8 +1128,12 @@ class Transaction extends AppModel {
}
}
}
if (empty($ret['rollback']['error']) && empty($ret['nsf_ledger_entry_id']))
$this->INTERNAL_ERROR("NSF LE ID not found under rollback entries");
if (empty($ret['rollback']['error']) && empty($ret['nsf_ledger_entry_id'])) {
//$this->INTERNAL_ERROR("NSF LE ID not found under rollback entries");
// Actually, this can happen if an item is NSF without having ever
// been applied to any charges.
$ret['nsf_ledger_entry_id'] = null;
}
$ret['nsf_transaction_id'] = $ret['bounce']['transaction_id'];
return $this->prReturn($ret + array('error' => false));

View File

@@ -2,12 +2,18 @@ Fix ACH deposits into bank. Make it happen automatically,
perhaps after 3 days. Without this, we cannot NSF an ACH
transaction.
Add NSF Fee to the NSF entry page (It's hardcoded right now
in Transaction to $35).
Sub-Total is broken, since it will only subtotal the current
page of the grid. It needs to be implemented in SQL as it
was in early (VERY early) implementations. At that time, I
had to a use temporary variable to keep a running total. It
worked, but was MySQL specific.
Unit Size has no controller. Either remove the link from the
units grid, or implement the controller.
Add a move-out charges field to the move-out page.
Otherwise, if the balance is zero, the lease will automatically
be closed and no more charges are possible. The other option
@@ -44,10 +50,32 @@ Change the menu structure to be $menu['section']['item'], so that
items don't have to be added in order of section. Perhaps even
array(array(name, priority, items => array(name, priority, link)))
Change menu to be
'Reports' (or 'Overview', or 'Summary')
'Activities'
- New Receipt
- New Customer
- Move-in
Change New Customer form to have contact 'New' radio pre-checked
Add explanatory information on the New Customer page
- Customer name can be omitted and will come from primary tenant.
- Phone numbers, etc can be added later directly to the contact
Add dynamic check to see if customer already exists before being
created. Ideally, check +/- a few characters to check for
alternate spellings. Same for contact.
Reduce the number of cached items. Figure out how to get Cake to
automatically make CONCAT(TenderType.name, ' #', Tender.id) part
of each returned query.
Implement, as part of the User model, a function to return the
security level. Have it be a static function, so that we don't
need to instantiate it, and right now, return a level based on
the route.
MUST reports:
- Delinquent customers