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:
@@ -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,
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
|
||||
28
todo.notes
28
todo.notes
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user