Compare commits

...

6 Commits

Author SHA1 Message Date
abijah
861eabc6b5 Forgot the new files on the last checkin
git-svn-id: file:///svn-source/pmgr/branches/statements_20090623@185 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-06-24 17:18:25 +00:00
abijah
6baa7fa6e6 Nowhere near complete, but must snapshot prior to my Boston trip.
git-svn-id: file:///svn-source/pmgr/branches/statements_20090623@184 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-06-24 17:16:39 +00:00
abijah
8cb45ad1d6 Branch for adding the concepts of statements. I suspect I'll end up killing it.
git-svn-id: file:///svn-source/pmgr/branches/statements_20090623@183 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-06-24 17:14:39 +00:00
abijah
ce4fa4131a More changes. I just can't seem to come up with a solution that works that I like. The problem now, without invoice/receipt, is that one check cannot cleanly pay for two units.
git-svn-id: file:///svn-source/pmgr/branches/single_AR_20090622@182 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-06-24 00:33:39 +00:00
abijah
80f8bd36d5 Nowhere near done yet, but checking in a snapshot of semi-working code. There is some simultaneous support for both with and without use of the Invoice/Receipt account. I want to do away with them completely, but will need to change how sitelink payments are mapped (right now, they split a payment into multiple parts to match the charge).
git-svn-id: file:///svn-source/pmgr/branches/single_AR_20090622@181 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-06-23 19:04:41 +00:00
abijah
7aa1100cac Moving to the standard accounting method of a single Account Receiveable.
git-svn-id: file:///svn-source/pmgr/branches/single_AR_20090622@180 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-06-22 23:46:03 +00:00
24 changed files with 1087 additions and 538 deletions

View File

@@ -633,14 +633,8 @@ CREATE TABLE `pmgr_customers` (
-- If NULL, rely on the contact info exclusively
`name` VARCHAR(80) DEFAULT NULL,
-- A customer gets their own account, although any
-- lease specific charge (rent, late fees, etc) will
-- be debited against the lease account. This one
-- will be used for non-lease related charges, as
-- well as charges that intentionally span more than
-- one lease (such as one security deposit to cover
-- two or more units).
`account_id` INT(10) UNSIGNED NOT NULL,
-- Statement of charges/payments
`statement_id` INT(10) UNSIGNED NOT NULL,
-- Primary Contact... every customer must have one
-- (and presumably, most customers will _be_ one).
@@ -703,12 +697,13 @@ CREATE TABLE `pmgr_leases` (
-- Allow user to specify their own lease numbers
-- If NULL, `id` will be used
`number` VARCHAR(20) DEFAULT NULL,
-- `number` VARCHAR(20) DEFAULT NULL,
`number` INT(10) UNSIGNED DEFAULT NULL,
`lease_type_id` INT(10) UNSIGNED NOT NULL,
`unit_id` INT(10) UNSIGNED NOT NULL,
`customer_id` INT(10) UNSIGNED NOT NULL,
`account_id` INT(10) UNSIGNED NOT NULL,
`statement_id` INT(10) UNSIGNED NOT NULL,
`late_schedule_id` INT(10) UNSIGNED DEFAULT NULL,
`lease_date` DATE NOT NULL,
@@ -866,15 +861,18 @@ LOCK TABLES `pmgr_accounts` WRITE;
INSERT INTO `pmgr_accounts` (`type`, `name`, `trackable`)
VALUES
('ASSET', 'A/R', 1),
('ASSET', 'Invoice', 1),
('ASSET', 'Receipt', 1),
('LIABILITY', 'A/P', 1),
('LIABILITY', 'Tax', 0),
('LIABILITY', 'Customer Credit', 1),
('ASSET', 'Bank', 0),
('ASSET', 'Payment', 0),
('ASSET', 'Till', 0),
('LIABILITY', 'Security Deposit', 1),
('INCOME', 'Rent', 0),
('INCOME', 'Late Charge', 0),
('EXPENSE', 'Concession', 0);
('EXPENSE', 'Concession', 0),
('EXPENSE', 'Bad Debt', 0);
UNLOCK TABLES;
@@ -965,6 +963,8 @@ CREATE TABLE `pmgr_ledger_entries` (
`name` VARCHAR(80) DEFAULT NULL,
`monetary_source_id` INT(10) UNSIGNED DEFAULT NULL, -- NULL if internal transfer
`transaction_id` INT(10) UNSIGNED NOT NULL,
`customer_id` INT(10) UNSIGNED DEFAULT NULL,
`lease_id` INT(10) UNSIGNED DEFAULT NULL,
`amount` FLOAT(12,2) NOT NULL,
`debit_ledger_id` INT(10) UNSIGNED NOT NULL,
@@ -986,13 +986,27 @@ CREATE TABLE `pmgr_reconciliations` (
`debit_ledger_entry_id` INT(10) UNSIGNED NOT NULL,
`credit_ledger_entry_id` INT(10) UNSIGNED NOT NULL,
`terminal_ledger_entry_id` INT(10) UNSIGNED DEFAULT NULL,
`amount` FLOAT(12,2) NOT NULL,
`amount` FLOAT(12,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ##
-- ## MONETARY
-- ##
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_monetary_sources
@@ -1047,6 +1061,59 @@ UNLOCK TABLES;
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ##
-- ## STATEMENTS
-- ##
-- ## Statements are supplementary financial information. They should
-- ## NEVER be used in financial calculations, but rather are secondary
-- ## information, to be created where needed.
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_statements
DROP TABLE IF EXISTS `pmgr_statements`;
CREATE TABLE `pmgr_statements` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_statement_entries
DROP TABLE IF EXISTS `pmgr_statement_entries`;
CREATE TABLE `pmgr_statement_entries` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`type` ENUM('CHARGE',
'PAYMENT')
NOT NULL,
`statement_id` INT(10) UNSIGNED NOT NULL,
`ledger_entry_id` INT(10) UNSIGNED NOT NULL,
`amount` FLOAT(12,2) NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ######################################################################
-- ######################################################################

View File

@@ -92,6 +92,32 @@ sub addRow {
}
######################################################################
######################################################################
## updateRow
sub updateRow {
my ($table, $id, $cols) = @_;
die unless $table;
die unless $id;
die unless ref($cols) eq 'HASH';
die "Table `$table` is unknown!"
unless defined $newdb{'tables'}{$table};
die "Table `$table` : ID `$id` does not exist!"
unless $newdb{'tables'}{$table}{'rows'}[$id];
# For debug purposes
my $line = (caller())[2];
$cols->{'--UPDATE-LINE--'} = [] unless $cols->{'--UPDATE-LINE--'};
push(@{$cols->{'--UPDATE-LINE--'}}, "updateRow called from line: $line");
#$newdb{'tables'}{$table}{'rows'}[$id] = $cols;
return $id;
}
######################################################################
######################################################################
## query
@@ -145,7 +171,13 @@ sub executeSchema {
sub buildTables {
foreach my $table (values %{$newdb{'tables'}}) {
printf(STDERR "%-30s : %d rows\n", $table->{'name'}, int(@{$table->{'rows'}}));
my $count = 0;
foreach (@{$table->{'rows'}}) {
next unless defined $_;
++$count;
}
printf(STDERR "%-30s : %d rows\n", $table->{'name'}, $count);
foreach (@{$table->{'rows'}}) {
next unless defined $_;
@@ -437,9 +469,9 @@ foreach $row (@$result) {
'comment' => undef });
$newdb{'lookup'}{'account'}{$row->{'name'}}
= {'account' => $row->{'id'},
= {'account_id' => $row->{'id'},
'tillable' => $row->{'tillable'},
'ledger' => $newdb{'tables'}{'ledgers'}{'autoid'} };
'ledger_id' => $newdb{'tables'}{'ledgers'}{'autoid'} };
if ((!defined $newdb{'tables'}{'accounts'}{'autoid'}) ||
$row->{'id'} > $newdb{'tables'}{'accounts'}{'autoid'}) {
@@ -449,7 +481,7 @@ foreach $row (@$result) {
# For compatibility, while deciding on account names
$newdb{'lookup'}{'account'}{'Cash'}
= $newdb{'lookup'}{'account'}{'Payment'};
= $newdb{'lookup'}{'account'}{'Till'};
$newdb{'lookup'}{'charge_type'} = {};
$newdb{'lookup'}{'charge_type'}{'Rent'} =
@@ -474,15 +506,15 @@ foreach $row (@$result) {
$newdb{'lookup'}{'payment_type'} = {};
$newdb{'lookup'}{'payment_type'}{1}
= { 'name' => 'Cash', 'account' => 'Cash', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Cash'} };
= { 'name' => 'Cash', 'account_name' => 'Cash', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Cash'} };
$newdb{'lookup'}{'payment_type'}{2}
= { 'name' => 'Check', 'account' => 'Cash', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Check'} };
= { 'name' => 'Check', 'account_name' => 'Cash', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Check'} };
$newdb{'lookup'}{'payment_type'}{3}
= { 'name' => 'Money Order', 'account' => 'Cash', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Money Order'} };
= { 'name' => 'Money Order', 'account_name' => 'Cash', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Money Order'} };
$newdb{'lookup'}{'payment_type'}{4}
= { 'name' => 'ACH', 'account' => 'Bank', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'ACH'} };
= { 'name' => 'ACH', 'account_name' => 'Bank', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'ACH'} };
$newdb{'lookup'}{'payment_type'}{12}
= { 'name' => 'Concession', 'account' => 'Concession', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Other Non-Tillable'} };
= { 'name' => 'Concession', 'account_name' => 'Concession', 'monetary_type' => $newdb{'lookup'}{'monetary_type'}{'Other Non-Tillable'} };
$newdb{'ids'}{'monetary_source'} = {};
@@ -490,14 +522,14 @@ $newdb{'ids'}{'monetary_source'}{'internal'} = undef;
addRow('monetary_sources',
{ 'monetary_type_id' => $newdb{'lookup'}{'monetary_type'}{'Cash'}{'id'},
'name' => 'Cash Source',
'name' => 'Cash',
'comment' => 'Monetary source used for any cash transaction' });
$newdb{'ids'}{'monetary_source'}{'Cash'} =
$newdb{'tables'}{'monetary_sources'}{'autoid'};
addRow('monetary_sources',
{ 'monetary_type_id' => $newdb{'lookup'}{'monetary_type'}{'Other Non-Tillable'}{'id'},
'name' => 'Closing Monies Credited',
'name' => 'Closing',
'comment' => 'Credited at the closing table' });
$newdb{'ids'}{'monetary_source'}{'Closing'} =
$newdb{'tables'}{'monetary_sources'}{'autoid'};
@@ -651,6 +683,13 @@ foreach $row (@{query($sdbh, $query)}) {
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}
= { 'name' => "$row->{'LastName'}, $row->{'FirstName'}" };
# Each tenants receives a statement
addRow('statements',
{ 'comment' => ("Statement for " .
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'name'}) });
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'statement_id'} =
$newdb{'tables'}{'statements'}{'autoid'};
addRow('contacts',
{ 'first_name' => $row->{'FirstName'},
'middle_name' => $row->{'MiddleName'},
@@ -661,34 +700,16 @@ foreach $row (@{query($sdbh, $query)}) {
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'} =
$newdb{'tables'}{'contacts'}{'autoid'};
# Every customer gets their own account
addRow('accounts',
{ 'type' => 'ASSET',
'trackable' => 1,
'name' => ('Customer #' . ($newdb{'tables'}{'customers'}{'autoid'}+1) .
' ('.$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'name'} . ')'),
'comment' => undef });
#'comment' => 'For direct customer transaction, NOT lease charges!' });
addRow('ledgers',
{ 'account_id' => $newdb{'tables'}{'accounts'}{'autoid'},
'open_stamp' => '2009-01-01',
'comment' => undef });
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'account'} =
$newdb{'tables'}{'accounts'}{'autoid'};
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'ledger'} =
$newdb{'tables'}{'ledgers'}{'autoid'};
addRow('customers',
{ 'name' => "$row->{'LastName'}, $row->{'FirstName'}",
'primary_contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'},
'account_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'account'} });
'statement_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'statement_id'},
'primary_contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'} });
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'cust'} =
$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'} =
$newdb{'tables'}{'customers'}{'autoid'};
addRow('contacts_customers',
{ 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'cust'},
{ 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'id'},
'type' => 'TENANT' },
1);
@@ -754,7 +775,7 @@ foreach $row (@{query($sdbh, $query)}) {
$newdb{'tables'}{'contacts'}{'autoid'};
addRow('contacts_customers',
{ 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'cust'},
{ 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'contact_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'alt'},
'type' => 'ALTERNATE' },
1);
@@ -800,53 +821,31 @@ $query = "SELECT L.*, A.TenantID FROM TenantLedger L LEFT JOIN `Access` A ON A.L
foreach $row (@{query($sdbh, $query)}) {
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}
= { 'cust' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'cust'} };
= { 'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'customer_statement_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'statement_id'},
};
if (1) {
# Every lease gets its own account
addRow('accounts',
{ 'type' => 'ASSET',
'trackable' => 1,
'name' => ('Lease #' . $row->{'LedgerID'}
. ' ('.$newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'name'} . ')'),
'comment' => undef });
#'comment' => 'For lease related transaction, NOT personal charges!' });
addRow('ledgers',
{ 'account_id' => $newdb{'tables'}{'accounts'}{'autoid'},
'open_stamp' => datefmt($row->{'DateIn'}),
'comment' => undef });
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'account'}
= $newdb{'tables'}{'accounts'}{'autoid'};
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'ledger'}
= $newdb{'tables'}{'ledgers'}{'autoid'};
}
else {
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'account'}
= $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'account'};
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'ledger'}
= $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'ledger'};
}
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'cust_account'}
= $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'account'};
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'cust_ledger'}
= $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'ledger'};
# Each lease receives a statement
addRow('statements',
{ 'comment' => ("Statement for Lease #" . $row->{'LedgerID'}) });
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease_statement_id'} =
$newdb{'tables'}{'statements'}{'autoid'};
addRow('leases',
{ 'number' => $row->{'LedgerID'},
'statement_id' => $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease_statement_id'},
'lease_type_id' => $newdb{'tables'}{'lease_types'}{'autoid'},
'unit_id' => $newdb{'lookup'}{'unit'}{$row->{'UnitID'}}{'id'},
'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'cust'},
'account_id' => $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'account'},
'customer_id' => $newdb{'lookup'}{'tenant'}{$row->{'TenantID'}}{'customer_id'},
'lease_date' => datefmt($row->{'DateIn'}),
'movein_date' => datefmt($row->{'DateIn'}),
'moveout_date' => datefmt($row->{'DateOut'}),
'close_date' => datefmt($row->{'DateClosed'}),
'amount' => $row->{'Rent'} });
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease'} =
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease_id'} =
$newdb{'tables'}{'leases'}{'autoid'};
}
@@ -868,63 +867,59 @@ $newdb{'lookup'}{'charge'} = {};
$query = "SELECT * FROM Charges ORDER BY ChargeID";
foreach $row (@{query($sdbh, $query)}) {
addRow('transactions',
{ 'stamp' => datefmt($row->{'ChargeDate'}),
'through_date' => datefmt($row->{'EndDate'}) });
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}
= { 'tx' => $newdb{'tables'}{'transactions'}{'autoid'},
'ledger' => $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'ledger'},
'amount' => $row->{'ChargeAmount'},
'tax_amount' => $row->{'TaxAmount'},
'lease_statement_id' => $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'lease_statement_id'},
'customer_statement_id' => $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'customer_statement_id'},
};
addRow('ledger_entries',
{ 'monetary_source_id' => $newdb{'ids'}{'monetary_source'}{'internal'},
'transaction_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'tx'},
'debit_ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ledger'},
'credit_ledger_id' => $newdb{'lookup'}{'charge_type'}{$row->{'ChargeDescription'}}{'ledger'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'charge_type'}{$row->{'ChargeDescription'}}{'ledger_id'},
'amount' => $row->{'ChargeAmount'},
'comment' => "Charge: $row->{'ChargeID'}; Ledger: $row->{'LedgerID'}" });
my $debit_entry_id = $newdb{'tables'}{'ledger_entries'}{'autoid'},
addRow('ledger_entries',
{ 'monetary_source_id' => $newdb{'ids'}{'monetary_source'}{'internal'},
'transaction_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'tx'},
'debit_ledger_id' => $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'cust_ledger'},
'credit_ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ledger'},
'amount' => $row->{'ChargeAmount'},
'comment' => "Charge: $row->{'ChargeID'}; Ledger: $row->{'LedgerID'}" });
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'terminal'}
= $debit_entry_id;
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'entry'}
= $newdb{'tables'}{'ledger_entries'}{'autoid'},
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ledger'}
= $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'cust_ledger'};
addRow('reconciliations',
{ 'debit_ledger_entry_id' => $debit_entry_id,
'credit_ledger_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'entry'},
'terminal_ledger_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'terminal'},
'amount' => $row->{'ChargeAmount'},
});
foreach ($newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_statement_id'},
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_statement_id'}) {
addRow('statement_entries',
{ 'type' => 'CHARGE',
'statement_id' => $_,
'ledger_entry_id' => $newdb{'tables'}{'ledger_entries'}{'autoid'},
'amount' => $row->{'ChargeAmount'} });
}
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ledger_entry_id'}
= $newdb{'tables'}{'ledger_entries'}{'autoid'};
next unless $row->{'TaxAmount'};
addRow('ledger_entries',
{ 'monetary_source_id' => $newdb{'ids'}{'monetary_source'}{'internal'},
'transaction_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'tx'},
'debit_ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ledger'},
'credit_ledger_id' => $newdb{'lookup'}{'charge_type'}{'Tax'}{'ledger'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'charge_type'}{'Tax'}{'ledger_id'},
'amount' => $row->{'TaxAmount'},
'comment' => undef });
foreach ($newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_statement_id'},
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_statement_id'}) {
addRow('statement_entries',
{ 'type' => 'CHARGE',
'statement_id' => $_,
'ledger_entry_id' => $newdb{'tables'}{'ledger_entries'}{'autoid'},
'amount' => $row->{'TaxAmount'} });
}
$newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'tax_entry'}
= $newdb{'tables'}{'ledger_entries'}{'autoid'},
= $newdb{'tables'}{'ledger_entries'}{'autoid'};
}
@@ -944,10 +939,10 @@ $query =
foreach $row (@{query($sdbh, $query)}) {
if ($newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}) {
die unless ($newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'cust'}
== $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'cust'});
die unless ($newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'customer_id'}
== $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'customer_id'});
push(@{$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'ledgers'}},
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'ledger'});
$newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'ledger_id'});
#print Dumper $receipt_map{$row->{'ReceiptNum'}};
next;
}
@@ -958,8 +953,12 @@ foreach $row (@{query($sdbh, $query)}) {
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}
= {'tx' => $newdb{'tables'}{'transactions'}{'autoid'},
'cust' => $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'cust'},
'ledgers' => [ $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'ledger'} ] };
# NOTE: Use of 'lease_id' would be invalid, since the
# receipt could be for multiple leases. 'customer_id'
# could be OK, but better to avoid this issue all
# together by excluding them both from this lookup.
'ledgers' => [ $newdb{'lookup'}{'ledger'}{$row->{'LedgerID'}}{'ledger_id'} ] };
}
@@ -975,48 +974,104 @@ $newdb{'lookup'}{'payment'} = {};
$query = "SELECT * FROM Payments ORDER BY PaymentID";
foreach $row (@{query($sdbh, $query)})
{
my $monetary_source_id;
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}} = {};
if ($row->{'PaymentDate'} =~ m%3/25/2009%) {
$monetary_source_id = $newdb{'ids'}{'monetary_source'}{'closing'};
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'monetary_source_id'}
= $newdb{'ids'}{'monetary_source'}{'Closing'};
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'account_name'}
= 'Bank';
}
else {
$monetary_source_id = $newdb{'ids'}{'monetary_source'}{
$newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'name'}
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'monetary_source_id'}
= $newdb{'ids'}{'monetary_source'}{
$newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'name'}
};
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'account_name'}
= $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'account_name'};
}
if (!defined $monetary_source_id) {
addRow('monetary_sources',
{ 'monetary_type_id' => $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'monetary_type'}{'id'},
'name' => $row->{'RecdFrom'},
'comment' => "Payment: $row->{'PaymentID'}; Type: $row->{'PaymentType'}; Check: $row->{'CheckNum'}; $row->{'Memo'}" });
$monetary_source_id = $newdb{'tables'}{'monetary_sources'}{'autoid'};
}
if (!$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'monetary_source_id'}) {
if (!defined $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'monetary_source_id'}) {
my $name;
$name = $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'name'};
if ($name eq 'Check') {
$name = 'Check #' . $row->{'CheckNum'};
}
addRow('monetary_sources',
{ 'monetary_type_id' => $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'monetary_type'}{'id'},
'name' => $name,
'comment' => "Payment: $row->{'PaymentID'}; Type: $row->{'PaymentType'}; Check: $row->{'CheckNum'}; $row->{'Memo'}" });
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'monetary_source_id'}
= $newdb{'tables'}{'monetary_sources'}{'autoid'};
}
my $payment_acct = $newdb{'lookup'}{'payment_type'}{$row->{'PaymentType'}}{'account'};
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'monetary_source_id'}
= $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'monetary_source_id'};
}
addRow('ledger_entries',
{ 'monetary_source_id' => $monetary_source_id,
'transaction_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'tx'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{$payment_acct}{'ledger'},
'credit_ledger_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ledger'},
'amount' => $row->{'PaymentAmount'},
'comment' => "Receipt: $row->{'ReceiptNum'}; Payment: $row->{'PaymentID'}; Charge: $row->{'ChargeID'}" });
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'debit_ledger_id'}
= $newdb{'lookup'}{'account'}{$newdb{'lookup'}{'payment'}{
$row->{'PaymentID'}}{'account_name'}
}{'ledger_id'};
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}
= { 'entry' => $newdb{'tables'}{'ledger_entries'}{'autoid'} };
# Sitelink splits one physical payment into multiple "payments" to match each charge
# This is kludgy, but for our cases at least, brings those pseudo-payments back into
# a single one. It presumes that there is only one PaymentType per receipt.
if (!$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'}) {
addRow('ledger_entries',
{ 'monetary_source_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'monetary_source_id'},
'transaction_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{'tx'},
'debit_ledger_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'debit_ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{'A/R'}{'ledger_id'},
'amount' => 0,
'comment' => "Receipt: $row->{'ReceiptNum'}; " });
# Reconcile Payment to the Charge. Since tracking is due to
# the A/R account (Lease Account in this case), credit/debit
# is from the perspective of that account. Namely, the charge
# was the debit to the A/R, and the payment was the credit.
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'}
= $newdb{'tables'}{'ledger_entries'}{'autoid'};
addRow('statement_entries',
{ 'type' => 'PAYMENT',
'statement_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'customer_statement_id'},
'ledger_entry_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'},
'amount' => 0 });
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'statement_entry_id'}
= $newdb{'tables'}{'statement_entries'}{'autoid'};
}
$newdb{'tables'}{'ledger_entries'}{'rows'}[
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'}
]{'amount'} += $row->{'PaymentAmount'};
$newdb{'tables'}{'ledger_entries'}{'rows'}[
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'}
]{'comment'} .= 'P:'.$row->{'PaymentID'} . '->C:' . $row->{'ChargeID'} . '; ';
$newdb{'tables'}{'statement_entries'}{'rows'}[
$newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'statement_entry_id'}
]{'amount'} += $row->{'PaymentAmount'};
addRow('statement_entries',
{ 'type' => 'PAYMENT',
'statement_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'lease_statement_id'},
'ledger_entry_id' => $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'},
'amount' => $row->{'PaymentAmount'} });
# OK, now that the receipt is reconciled, update
# payment to reference the true ledger_entry_id
$newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'ledger_entry_id'}
= $newdb{'lookup'}{'receipt'}{$row->{'ReceiptNum'}}{$row->{'PaymentType'}}{'ledger_entry_id'};
# Figure out how much of the charge can be reconciled
my $reconcile_amount = $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'amount'};
$reconcile_amount = $row->{'PaymentAmount'} if $row->{'PaymentAmount'} <= $reconcile_amount;
# Reconcile the A/R account. Since this is from the perspective
# of the A/R, charge is the debit, and payment is the credit
addRow('reconciliations',
{ 'debit_ledger_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'entry'},
'credit_ledger_entry_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'entry'},
'terminal_ledger_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'terminal'},
{ 'debit_ledger_entry_id' => $newdb{'lookup'}{'charge'}{$row->{'ChargeID'}}{'ledger_entry_id'},
'credit_ledger_entry_id' => $newdb{'lookup'}{'payment'}{$row->{'PaymentID'}}{'ledger_entry_id'},
'amount' => $reconcile_amount,
});
@@ -1033,11 +1088,12 @@ foreach $row (@{query($sdbh, $query)})
## Fake Data for Testing
my %fake =
('custid' => 2,
('customer_id' => 4,
'ledger_id' => 4,
'invoice' => [ { 'id' => 1000,
'date' => '2009-05-05',
'entry' => [ { 'id' => 2100,
'account' => 'Security Deposit',
'account_name' => 'Security Deposit',
'amount' => 10,
'tax' => 0 },
],
@@ -1046,7 +1102,7 @@ my %fake =
'date' => '2009-05-01',
'thru' => '2009-05-31',
'entry' => [ { 'id' => 2110,
'account' => 'Rent',
'account_name' => 'Rent',
'amount' => 100,
'tax' => 5 },
],
@@ -1054,7 +1110,7 @@ my %fake =
{ 'id' => 1002,
'date' => '2009-05-11',
'entry' => [ { 'id' => 2120,
'account' => 'Late Charge',
'account_name' => 'Late Charge',
'amount' => 25,
'tax' => 0 },
],
@@ -1115,105 +1171,137 @@ my %fake =
);
sub fakeTesting {
$newdb{'ids'}{'ledger'}{'Cash-Old'} =
$newdb{'lookup'}{'account'}{'Cash'}{'ledger_id'};
$newdb{'ids'}{'ledger'}{'Cash-Old'} =
$newdb{'lookup'}{'account'}{'Cash'}{'ledger'};
addRow('ledgers',
{ 'account_id' => $newdb{'lookup'}{'account'}{'Cash'}{'account_id'},
'open_stamp' => 'NOW()',
'sequence' => 2,
'comment' => 'Opened new ledger for testing' });
addRow('ledgers',
{ 'account_id' => $newdb{'lookup'}{'account'}{'Cash'}{'account'},
'open_stamp' => 'NOW()',
'sequence' => 2,
'comment' => 'Opened new ledger for testing' });
$newdb{'lookup'}{'account'}{'Cash'}{'ledger_id'} =
$newdb{'tables'}{'ledgers'}{'autoid'};
$newdb{'lookup'}{'account'}{'Cash'}{'ledger'} =
$newdb{'tables'}{'ledgers'}{'autoid'};
my $balance = 0;
foreach $row (@{$newdb{'tables'}{'ledger_entries'}{'rows'}}) {
next unless defined $row;
$balance += $row->{'amount'}
if $row->{'debit_ledger_id'} == $newdb{'ids'}{'ledger'}{'Cash-Old'};
$balance -= $row->{'amount'}
if $row->{'credit_ledger_id'} == $newdb{'ids'}{'ledger'}{'Cash-Old'};
}
my $balance = 0;
foreach $row (@{$newdb{'tables'}{'ledger_entries'}{'rows'}}) {
next unless defined $row;
$balance += $row->{'amount'}
if $row->{'debit_ledger_id'} == $newdb{'ids'}{'ledger'}{'Cash-Old'};
$balance -= $row->{'amount'}
if $row->{'credit_ledger_id'} == $newdb{'ids'}{'ledger'}{'Cash-Old'};
}
addRow('transactions',
{ 'stamp' => '2009-05-10' });
addRow('transactions',
{ 'stamp' => '2009-05-10' });
addRow('ledger_entries',
{ 'monetary_source_id' => $newdb{'ids'}{'monetary_source'}{'internal'},
'transaction_id' => $newdb{'tables'}{'transactions'}{'autoid'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{'Cash'}{'ledger'},
'credit_ledger_id' => $newdb{'ids'}{'ledger'}{'Cash-Old'},
'amount' => $balance,
'name' => "Close Out ($newdb{'ids'}{'ledger'}{'Cash-Old'} -> $newdb{'tables'}{'transactions'}{'autoid'})",
'comment' => "Carrying forward old ledger balance onto new ledger" });
addRow('ledger_entries',
{ 'monetary_source_id' => $newdb{'ids'}{'monetary_source'}{'internal'},
'transaction_id' => $newdb{'tables'}{'transactions'}{'autoid'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{'Cash'}{'ledger_id'},
'credit_ledger_id' => $newdb{'ids'}{'ledger'}{'Cash-Old'},
'amount' => $balance,
'name' => "Close Out ($newdb{'ids'}{'ledger'}{'Cash-Old'} -> $newdb{'tables'}{'transactions'}{'autoid'})",
'comment' => "Carrying forward old ledger balance onto new ledger" });
# NOTE: no tracking for the Cash account
$newdb{'tables'}{'ledgers'}{'rows'}[$newdb{'ids'}{'ledger'}{'Cash-Old'}]{'closed'} = 1;
$newdb{'tables'}{'ledgers'}{'rows'}[$newdb{'ids'}{'ledger'}{'Cash-Old'}]{'close_stamp'} = 'NOW()';
$newdb{'tables'}{'ledgers'}{'rows'}[$newdb{'ids'}{'ledger'}{'Cash-Old'}]{'closed'} = 1;
$newdb{'tables'}{'ledgers'}{'rows'}[$newdb{'ids'}{'ledger'}{'Cash-Old'}]{'close_stamp'} = 'NOW()';
foreach my $ir ('invoice', 'receipt') {
foreach my $tx (@{$fake{$ir}}) {
#print Dumper ${%$tx{'date'}};
#exit;
addRow('transactions',
{ 'id' => $tx->{'id'},
'stamp' => $tx->{'date'},
'through_date' => $tx->{'thru'},
'comment' => "Fake $ir" },
1);
foreach my $ir ('invoice', 'receipt') {
foreach my $tx (@{$fake{$ir}}) {
#print Dumper ${%$tx{'date'}};
#exit;
addRow('transactions',
{ 'id' => $tx->{'id'},
'stamp' => $tx->{'date'},
'through_date' => $tx->{'thru'},
'comment' => "Fake $ir" },
1);
foreach my $e (@{$tx->{'entry'}}) {
my $dr = ($ir eq 'invoice') ? 'A/R' : 'Cash';
my $cr = ($ir eq 'invoice') ? $e->{'account'} : 'A/R';
my $monetary_source_id;
foreach my $e (@{$tx->{'entry'}}) {
my $crdr = ($ir eq 'invoice') ? 'Invoice' : 'Receipt';
my $dr = ($ir eq 'invoice') ? 'A/R' : 'Cash';
$crdr = $dr;
my $cr = ($ir eq 'invoice') ? $e->{'account_name'} : 'A/R';
my $monetary_source_id;
if (defined $e->{'type'}) {
addRow('monetary_sources',
{ 'monetary_type_id' => $e->{'type'},
'name' => "Money of type " . $e->{'type'},
'comment' => "Fake Money For " . $e->{'id'} });
$monetary_source_id = $newdb{'tables'}{'monetary_sources'}{'autoid'};
}
else {
$monetary_source_id = $newdb{'ids'}{'monetary_source'}{'internal'};
}
if (defined $e->{'type'}) {
addRow('monetary_sources',
{ 'monetary_type_id' => $e->{'type'},
'name' => "Money of type " . $e->{'type'},
'comment' => "Fake Money For " . $e->{'id'} });
$monetary_source_id = $newdb{'tables'}{'monetary_sources'}{'autoid'};
}
else {
$monetary_source_id = $newdb{'ids'}{'monetary_source'}{'internal'};
}
addRow('ledger_entries',
{ 'id' => $e->{'id'},
'monetary_source_id' => $monetary_source_id,
'transaction_id' => $tx->{'id'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{$dr}{'ledger'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{$cr}{'ledger'},
'amount' => $e->{'amount'},
'comment' => "Fake $ir entry" },
1);
addRow('ledger_entries',
{ 'id' => $e->{'id'},
'monetary_source_id' => $monetary_source_id,
'transaction_id' => $tx->{'id'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{$crdr}{'ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{$cr}{'ledger_id'},
'customer_id' => $fake{'customer_id'},
'lease_id' => $fake{'lease_id'},
'amount' => $e->{'amount'},
'comment' => "Fake $ir entry" },
1);
foreach my $t (@{$e->{'track'}}) {
addRow('reconciliations',
{ 'debit_ledger_entry_id' => $t->{'debit'},
'credit_ledger_entry_id' => $e->{'id'},
'terminal_ledger_entry_id' => $t->{'debit'},
'amount' => $t->{'amount'}
});
}
# addRow('ledger_entries',
# { 'id' => $e->{'id'},
# 'monetary_source_id' => $monetary_source_id,
# 'transaction_id' => $tx->{'id'},
# 'debit_ledger_id' => $newdb{'lookup'}{'account'}{$dr}{'ledger_id'},
# 'credit_ledger_id' => $newdb{'lookup'}{'account'}{$crdr}{'ledger_id'},
# 'customer_id' => $fake{'customer_id'},
# 'lease_id' => $fake{'lease_id'},
# 'amount' => $e->{'amount'},
# 'comment' => "Fake $ir entry" },
# 1);
next unless $e->{'tax'};
foreach my $t (@{$e->{'track'}}) {
addRow('reconciliations',
{ 'debit_ledger_entry_id' => $t->{'debit'},
'credit_ledger_entry_id' => $e->{'id'},
'amount' => $t->{'amount'}
});
}
addRow('ledger_entries',
{ 'id' => $e->{'id'}+1,
'monetary_source_id' => $monetary_source_id,
'transaction_id' => $tx->{'id'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{$dr}{'ledger'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{'Tax'}{'ledger'},
'amount' => $e->{'tax'},
'comment' => "Fake Tax" },
1);
}
}
next unless $e->{'tax'};
addRow('ledger_entries',
{ 'id' => $e->{'id'}+1,
'monetary_source_id' => $monetary_source_id,
'transaction_id' => $tx->{'id'},
'debit_ledger_id' => $newdb{'lookup'}{'account'}{$crdr}{'ledger_id'},
'credit_ledger_id' => $newdb{'lookup'}{'account'}{'Tax'}{'ledger_id'},
'customer_id' => $fake{'customer_id'},
'lease_id' => $fake{'lease_id'},
'amount' => $e->{'amount'},
'comment' => "Fake Tax" },
1);
# addRow('ledger_entries',
# { 'id' => $e->{'id'}+1,
# 'monetary_source_id' => $monetary_source_id,
# 'transaction_id' => $tx->{'id'},
# 'debit_ledger_id' => $newdb{'lookup'}{'account'}{$dr}{'ledger_id'},
# 'credit_ledger_id' => $newdb{'lookup'}{'account'}{$crdr}{'ledger_id'},
# 'customer_id' => $fake{'customer_id'},
# 'lease_id' => $fake{'lease_id'},
# 'amount' => $e->{'tax'},
# 'comment' => "Fake Tax" },
# 1);
}
}
}
}
#fakeTesting();
$Data::Dumper::Sortkeys = 1;
print Dumper \%newdb;
# exit;

View File

@@ -305,7 +305,13 @@ class AppController extends Controller {
$id = 'id';
extract(array_intersect_key($fields, array_flip($special)));
foreach ($records AS &$record) {
if (!isset($record[$table]))
continue;
foreach (array_diff_key($fields, array_flip($special)) AS $field) {
if (!isset($record[$table][$id]) || !isset($record[$table][$field]))
continue;
// DEBUG PURPOSES ONLY!
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
$record[$table][$field] =
@@ -338,30 +344,40 @@ class AppController extends Controller {
}
function jqGridDataOutputRecords(&$params, &$model, &$records) {
$model_alias = $model->alias;
$id = 'jqGrid_id';
$id_field = 'jqGrid_id';
foreach ($records AS $record) {
echo " <row id='{$record[$id]}'>\n";
foreach ($params['fields'] AS $field) {
if (preg_match("/\./", $field)) {
list($tbl, $col) = explode(".", $field);
$data = $record[$tbl][$col];
}
else {
$data = $record[$model_alias][$field];
}
// be sure to put text data in CDATA
if (preg_match("/^\d*$/", $data))
echo " <cell>$data</cell>\n";
else
echo " <cell><![CDATA[$data]]></cell>\n";
}
echo " </row>\n";
$this->jqGridDataOutputRecord($params, $model, $record,
$record[$id_field], $params['fields']);
}
}
function jqGridDataOutputRecord(&$params, &$model, &$record, $id, $fields) {
echo " <row id='$id'>\n";
foreach ($fields AS $field) {
$this->jqGridDataOutputRecordField($params, $model, $record, $field);
}
echo " </row>\n";
}
function jqGridDataOutputRecordField(&$params, &$model, &$record, $field) {
if (preg_match("/\./", $field)) {
list($tbl, $col) = explode(".", $field);
$data = $record[$tbl][$col];
}
else {
$data = $record[$model->alias][$field];
}
$this->jqGridDataOutputRecordCell($params, $model, $record, $field, $data);
}
function jqGridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
// be sure to put text data in CDATA
if (preg_match("/^\d*$/", $data))
echo " <cell>$data</cell>\n";
else
echo " <cell><![CDATA[$data]]></cell>\n";
}
function jqGridDataFinalize(&$params) {
if ($params['debug']) {
$xml = ob_get_contents();

View File

@@ -78,6 +78,24 @@ class AppModel extends Model {
/**************************************************************************
**************************************************************************
**************************************************************************
* function: nameToID
* - Returns the ID of the named item
*/
function nameToID($name) {
$this->cacheQueries = true;
$item = $this->find('first', array
('recursive' => -1,
'conditions' => compact('name'),
));
$this->cacheQueries = false;
$item = current($item);
return $item['id'];
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -71,6 +71,7 @@ class LeasesController extends AppController {
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
$links['Lease'] = array('number');
$links['Unit'] = array('name');
$links['Customer'] = array('name');
return parent::jqGridRecordLinks($params, $model, $records, $links);
}
@@ -107,7 +108,6 @@ class LeasesController extends AppController {
array(// Models
'LeaseType',
'Unit',
'Account' => array('CurrentLedger'),
'Customer',
),
'conditions' => array(array('Lease.id' => $id)),
@@ -115,23 +115,15 @@ class LeasesController extends AppController {
)
);
// Summarize each ledger
$this->Lease->statsMerge($lease,
$this->Lease->stats($lease['Lease']['id']));
// Obtain the overall lease balance
$this->Lease->statsMerge($lease['Lease'],
array('stats' => $this->Lease->stats($id)));
$outstanding_balance = $lease['Lease']['stats']['Account']['Ledger']['balance'];
$outstanding_balance = $lease['Lease']['stats']['balance'];
// Determine the lease security deposit
$deposits = $this->Lease->findSecurityDeposits($lease['Lease']['id']);
$outstanding_deposit = $deposits['summary']['balance'];
// Move the Leder stats into our alias 'CurrentLedger'
$lease['Account']['CurrentLedger'] += $lease['Account']['Ledger'];
unset($lease['Account']['Ledger']);
// Prepare to render
$title = 'Lease: #' . $lease['Lease']['id'];
$this->set(compact('lease', 'title',

View File

@@ -25,6 +25,14 @@ class LedgerEntriesController extends AppController {
* to jqGrid.
*/
function jqGridDataSetup(&$params) {
parent::jqGridDataSetup($params);
if (isset($params['custom']['ar_account'])) {
$params['custom']['account_id'] =
$this->LedgerEntry->DebitLedger->Account->accountReceivableAccountID();
}
}
function jqGridDataTables(&$params, &$model) {
$link =
array(// Models
@@ -36,6 +44,16 @@ class LedgerEntriesController extends AppController {
array('fields' => array('id', 'name'),
),
'Customer' =>
array('fields' => array('id', 'name'),
),
'Lease' =>
array('fields' => array('id', 'number'),
'Unit' =>
array('fields' => array('id', 'name'),
),
),
);
if (isset($params['custom']['account_ftype'])) {
@@ -77,6 +95,19 @@ class LedgerEntriesController extends AppController {
);
}
if (isset($params['custom']['account_id'])) {
$account_id = $params['custom']['account_id'];
$link['Ledger'] =
array('fields' => array('id', 'sequence'),
'conditions' => ("Ledger.id = IF(DebitLedger.account_id = $account_id," .
" LedgerEntry.credit_ledger_id," .
" LedgerEntry.debit_ledger_id)"),
'Account' => array(
'fields' => array('id', 'name'),
),
);
}
if (isset($params['custom']['reconcile_id'])) {
$ftype = $params['custom']['account_ftype'];
$ftype = $this->LedgerEntry->DebitLedger->Account->fundamentalOpposite($ftype);
@@ -92,11 +123,14 @@ class LedgerEntriesController extends AppController {
$ledger_id = (isset($params['custom']['ledger_id'])
? $params['custom']['ledger_id']
: null);
$account_id = (isset($params['custom']['account_id'])
? $params['custom']['account_id']
: null);
$account_type = (isset($params['custom']['account_type'])
? $params['custom']['account_type']
: null);
return $model->ledgerContextFields2($ledger_id, $account_type);
return $model->ledgerContextFields2($ledger_id, $account_id, $account_type);
}
function jqGridDataConditions(&$params, &$model) {
@@ -118,20 +152,41 @@ class LedgerEntriesController extends AppController {
$conditions[] = array('Reconciliation.'.$ftype.'_ledger_entry_id' => $params['custom']['reconcile_id']);
}
if (isset($params['custom']['account_id'])) {
$conditions[] =
array('OR' =>
array(array('CreditAccount.id' => $params['custom']['account_id']),
array('DebitAccount.id' => $params['custom']['account_id'])));
}
if (isset($params['custom']['customer_id'])) {
$conditions[] =
array('Customer.id' => $params['custom']['customer_id']);
}
if (isset($params['custom']['lease_id'])) {
$conditions[] =
array('Lease.id' => $params['custom']['lease_id']);
}
if (isset($params['custom']['transaction_id'])) {
$conditions[] =
array('Transaction.id' => $params['custom']['transaction_id']);
}
return $conditions;
}
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
$links['Transaction'] = array('id');
$links['LedgerEntry'] = array('id');
if (isset($params['custom']['account_ftype']) || isset($params['custom']['ledger_id'])) {
$links['Account'] = array('controller' => 'accounts', 'name');
}
else {
$links['DebitAccount'] = array('controller' => 'accounts', 'name');
$links['CreditAccount'] = array('controller' => 'accounts', 'name');
}
$links['Account'] = array('controller' => 'accounts', 'name');
$links['DebitAccount'] = array('controller' => 'accounts', 'name');
$links['CreditAccount'] = array('controller' => 'accounts', 'name');
$links['MonetarySource'] = array('name');
$links['Customer'] = array('name');
$links['Lease'] = array('number');
$links['Unit'] = array('name');
return parent::jqGridRecordLinks($params, $model, $records, $links);
}
@@ -145,8 +200,39 @@ class LedgerEntriesController extends AppController {
function jqGridDataOrder(&$params, &$model, $index, $direction) {
/* if ($index === 'balance') */
/* return ($index .' '. $direction); */
$order = parent::jqGridDataOrder($params, $model, $index, $direction);
return parent::jqGridDataOrder($params, $model, $index, $direction);
if ($index === 'Transaction.stamp') {
$order[] = 'LedgerEntry.id ' . $direction;
}
return $order;
}
function jqGridRecordsPostProcess(&$params, &$model, &$records) {
parent::jqGridRecordsPostProcess($params, $model, $records);
$subtotal = 0;
foreach ($records AS &$record) {
$amount = (isset($record['LedgerEntry']['balance'])
? $record['LedgerEntry']['balance']
: $record['LedgerEntry']['amount']);
$record['LedgerEntry']['subtotal'] = ($subtotal += $amount);
continue;
// Experiment to minimize columns by putting the monetary source
// as the Account, when available
if ($record['MonetarySource']['name'])
$record['Account']['name'] = $record['MonetarySource']['name'];
}
}
function jqGridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
/* if ($field === 'CreditAccount.name') { */
/* $data .= '-OK'; */
/* } */
parent::jqGridDataOutputRecordCell($params, $model, $record, $field, $data);
}
@@ -167,6 +253,7 @@ class LedgerEntriesController extends AppController {
$entry = $this->LedgerEntry->find
('first',
array('contain' => array('MonetarySource.id',
'MonetarySource.name',
'MonetarySource.MonetaryType.id',
'Transaction.id',
'Transaction.stamp',
@@ -176,6 +263,9 @@ class LedgerEntriesController extends AppController {
'CreditLedger.id',
'CreditLedger.sequence',
'CreditLedger.account_id',
'Customer.id',
'Customer.name',
'Lease.id',
),
'fields' => array('LedgerEntry.id',
@@ -184,6 +274,7 @@ class LedgerEntriesController extends AppController {
'conditions' => array('LedgerEntry.id' => $id),
));
pr($entry);
// Because 'DebitLedger' and 'CreditLedger' both relate to 'Account',
// CakePHP will not include them in the LedgerEntry->find (or so it

View File

@@ -0,0 +1,116 @@
<?php
class StatementEntriesController extends AppController {
var $sidemenu_links = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* virtuals: jqGridData
* - With the application controller handling the jqGridData action,
* these virtual functions ensure that the correct data is passed
* to jqGrid.
*/
function jqGridDataTables(&$params, &$model) {
$link =
array(// Models
'LedgerEntry' =>
array('fields' => array('id'),
// Models
'Transaction' =>
array('fields' => array('id', 'stamp'),
),
'Ledger' =>
array('fields' => array('id', 'sequence'),
'conditions' => ("Ledger.id = IF(StatementEntry.type = 'CHARGE'," .
" LedgerEntry.credit_ledger_id," .
" LedgerEntry.debit_ledger_id)"),
// Models
'Account' => array('fields' => array('id', 'name'),
),
),
),
);
return array('link' => $link);
}
function jqGridDataFields(&$params, &$model) {
$fields = array('id', 'type', 'comment');
$fields[] = "IF(StatementEntry.type = 'CHARGE', StatementEntry.amount, NULL) AS 'charge'";
$fields[] = "IF(StatementEntry.type = 'PAYMENT', StatementEntry.amount, NULL) AS 'payment'";
$fields[] = "IF(StatementEntry.type = 'CHARGE', 1, -1) * StatementEntry.amount AS 'amount'";
return $fields;
}
function jqGridDataConditions(&$params, &$model) {
$conditions = parent::jqGridDataConditions($params, $model);
if (isset($params['custom']['statement_id'])) {
$conditions[] =
array('StatementEntry.statement_id' => $params['custom']['statement_id']);
}
return $conditions;
}
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
$links['Transaction'] = array('id');
$links['StatementEntry'] = array('id');
$links['Account'] = array('controller' => 'accounts', 'name');
$links['LedgerEntry'] = array('id');
return parent::jqGridRecordLinks($params, $model, $records, $links);
}
function jqGridRecordsPostProcess(&$params, &$model, &$records) {
parent::jqGridRecordsPostProcess($params, $model, $records);
$subtotal = 0;
foreach ($records AS &$record) {
$amount = $record['StatementEntry']['amount'];
$record['StatementEntry']['amount'] = $amount;
$record['StatementEntry']['subtotal'] = ($subtotal += $amount);
}
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: view
* - Displays information about a specific entry
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
}
// Get the StatementEntry and related fields
$entry = $this->StatementEntry->find
('first',
array('contain' => array(),
'conditions' => array('StatementEntry.id' => $id),
));
// Prepare to render.
$title = "Statement Entry #{$entry['StatementEntry']['id']}";
$this->set(compact('entry', 'title'));
}
}

View File

@@ -55,7 +55,7 @@ class UnitsController extends AppController {
$link = array
('link' =>
array(// Models
'UnitSize' => array('fields' => array('name')),
'UnitSize' => array('fields' => array('id', 'name')),
),
);
@@ -93,6 +93,11 @@ class UnitsController extends AppController {
return parent::jqGridDataOrder($params, $model, $index, $direction);
}
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
//$links['UnitSize'] = array('name');
$links['Unit'] = array('name', 'id');
return parent::jqGridRecordLinks($params, $model, $records, $links);
}
/**************************************************************************
**************************************************************************
@@ -121,7 +126,7 @@ class UnitsController extends AppController {
// Get the balance on each lease.
foreach ($unit['Lease'] AS &$lease) {
$stats = $this->Unit->Lease->stats($lease['id']);
$lease['balance'] = $stats['Account']['Ledger']['balance'];
$lease['balance'] = $stats['balance'];
}
$outstanding_balance = 0;
@@ -130,7 +135,7 @@ class UnitsController extends AppController {
// Figure out the outstanding balance of the current lease.
$stats = $this->Unit->stats($id);
$outstanding_balance =
$stats['CurrentLease']['Account']['Ledger']['balance'];
$stats['CurrentLease']['balance'];
// Figure out the total security deposit for the current lease.
$deposits = $this->Unit->Lease->findSecurityDeposits($unit['CurrentLease']['id']);

View File

@@ -82,37 +82,13 @@ class Account extends AppModel {
/**************************************************************************
**************************************************************************
**************************************************************************
* function: securityDepositAccountID
* - Returns the ID of the Security Deposit Account
* function: Account IDs
* - Returns the ID of the desired account
*/
function securityDepositAccountID() {
$this->cacheQueries = true;
$account = $this->find('first', array
('recursive' => -1,
'conditions' => array
(array('name' => 'Security Deposit')),
));
$this->cacheQueries = false;
return $account['Account']['id'];
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function:rentAccountID
* - Returns the ID of the Rent Account
*/
function rentAccountID() {
$this->cacheQueries = true;
$account = $this->find('first', array
('recursive' => -1,
'conditions' => array
(array('name' => 'Rent')),
));
$this->cacheQueries = false;
return $account['Account']['id'];
}
function securityDepositAccountID() { return $this->nameToID('Security Deposit'); }
function rentAccountID() { return $this->nameToID('Rent'); }
function accountReceivableAccountID() { return $this->nameToID('A/R'); }
/**************************************************************************
@@ -122,22 +98,19 @@ class Account extends AppModel {
* - Returns an array of ledger ids from the given account
*/
function ledgers($id, $all = false) {
$cachekey = $all ? 'all' : 'current';
if (isset($this->cache[$id]['ledgers'][$cachekey])) {
return $this->cache[$id]['ledgers'][$cachekey];
}
if ($all) {
$contain = array('Ledger' => array('fields' => array('Ledger.id')));
} else {
$contain = array('CurrentLedger' => array('fields' => array('CurrentLedger.id')));
}
$this->cacheQueries = true;
$account = $this->find('first', array
('contain' => $contain,
'fields' => array(),
'conditions' => array(array('Account.id' => $id)),
));
$this->cacheQueries = false;
if ($all) {
$ledger_ids = array();
@@ -148,14 +121,11 @@ class Account extends AppModel {
$ledger_ids = array($account['CurrentLedger']['id']);
}
// Save the ledgers in our cache for future reference
$this->cache[$id]['ledgers'][$cachekey] = $ledger_ids;
/* pr(array('function' => 'Account::ledgers', */
/* 'args' => compact('id', 'all'), */
/* 'return' => $this->cache[$id]['ledgers'][$cachekey])); */
/* 'return' => $ledger_ids)); */
return $this->cache[$id]['ledgers'][$cachekey];
return $ledger_ids;
}
@@ -234,7 +204,11 @@ class Account extends AppModel {
* (such as charges not paid).
*/
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null) {
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null, $cond = null) {
if (!isset($cond))
$cond = array();
$cond[] = array('Account.id' => $id);
foreach (($fundamental_type
? array($fundamental_type)
: array('debit', 'credit')) AS $fund) {
@@ -260,7 +234,7 @@ class Account extends AppModel {
'group' => ("LedgerEntry.id" .
" HAVING LedgerEntry.amount" .
" <> COALESCE(SUM(Reconciliation.amount),0)"),
'conditions' => array('Account.id' => $id),
'conditions' => $cond,
'fields' => array(),
));
$balance = 0;
@@ -290,7 +264,7 @@ class Account extends AppModel {
* whatever algorithm is simplest.
*/
function reconcileNewLedgerEntry($id, $fundamental_type, $amount) {
function reconcileNewLedgerEntry($id, $fundamental_type, $amount, $cond = null) {
$ofund = $this->fundamentalOpposite($fundamental_type);
$unreconciled = array($ofund => array('entry'=>array(), 'balance'=>0));
$applied = 0;
@@ -298,7 +272,7 @@ class Account extends AppModel {
// if there is no money in the entry, it can reconcile nothing
// don't bother wasting time sifting ledger entries.
if ($amount > 0) {
$unreconciled = $this->findUnreconciledLedgerEntries($id, $ofund);
$unreconciled = $this->findUnreconciledLedgerEntries($id, $ofund, $cond);
foreach ($unreconciled[$ofund]['entry'] AS $i => &$entry) {
// Determine if amount is sufficient to cover the entry

View File

@@ -8,7 +8,7 @@ class Customer extends AppModel {
);
var $belongsTo = array(
'Account',
'Statement',
'PrimaryContact' => array(
'className' => 'Contact',
),
@@ -20,11 +20,19 @@ class Customer extends AppModel {
'conditions' => 'CurrentLease.close_date IS NULL',
),
'Lease',
'Transaction',
'LedgerEntry',
// Cheat to get Account set as part of this class
'Account',
);
var $hasAndBelongsToMany = array(
'Contact',
'Transaction' => array(
'joinTable' => 'ledger_entries',
'foreignKey' => 'customer_id',
'associationForeignKey' => 'transaction_id',
),
);
@@ -36,13 +44,26 @@ class Customer extends AppModel {
*/
function accountId($id) {
$this->cacheQueries = true;
$customer = $this->find('first',
array('contain' => false,
'fields' => array('account_id'),
'conditions' => array(array('Customer.id' => $id))));
$item = $this->find('first',
array('contain' => false,
'fields' => array('account_id'),
'conditions' => compact('id')));
$this->cacheQueries = false;
return $customer['Customer']['account_id'];
$item = current($item);
return $item['account_id'];
}
function statementID($id) {
$this->cacheQueries = true;
$item = $this->find('first', array
('recursive' => -1,
'conditions' => compact('id'),
));
$this->cacheQueries = false;
$item = current($item);
return $item['statement_id'];
}
@@ -68,6 +89,7 @@ class Customer extends AppModel {
return $ids;
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -75,29 +97,10 @@ class Customer extends AppModel {
* - Returns an array of security deposit entries
*/
function findSecurityDeposits($id, $link = null) {
/* pr(array('function' => 'Customer::findSecurityDeposits', */
/* 'args' => compact('id', 'link'), */
/* )); */
$entries = $this->Account->findLedgerEntriesRelatedToAccount
($this->accountId($id),
return $this->Statement->findEntriesRelatedToAccount
($this->statementId($id),
$this->Account->securityDepositAccountID(),
true, null, $link);
foreach ($this->leaseIds($id) AS $lease_id) {
$ledger_entries = $this->Lease->findSecurityDeposits($lease_id, $link);
$this->statsMerge($entries['summary'], $ledger_entries['summary']);
$entries['Entries'] = array_merge($entries['Entries'],
$ledger_entries['Entries']);
}
/* pr(array('function' => 'Customer::findSecurityDeposits', */
/* 'args' => compact('id', 'link'), */
/* 'vars' => compact('customer'), */
/* 'return' => compact('entries'), */
/* )); */
return $entries;
null, $link);
}
@@ -110,22 +113,10 @@ class Customer extends AppModel {
*/
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null) {
$unreconciled = $this->Account->findUnreconciledLedgerEntries
($this->accountId($id), $fundamental_type);
foreach ($this->leaseIds($id) AS $lease_id) {
$unrec = $this->Lease->findUnreconciledLedgerEntries($lease_id,
$fundamental_type);
foreach (array_keys($unreconciled) AS $type) {
$left = &$unreconciled[$type];
$right = &$unrec[$type];
$left['entry'] = array_merge($left['entry'], $right['entry']);
$left['balance'] += $right['balance'];
}
}
($this->Account->accountReceivableAccountID(),
$fundamental_type,
array('LedgerEntry.customer_id' => $id));
return $unreconciled;
}
@@ -146,25 +137,11 @@ class Customer extends AppModel {
*/
function reconcileNewLedgerEntry($id, $fundamental_type, $amount) {
$reconciled = $this->Account->reconcileNewLedgerEntry
($this->accountId($id), $fundamental_type, $amount);
foreach ($this->leaseIds($id) AS $lease_id) {
foreach (array_keys($reconciled) AS $type) {
$rec = $this->Lease->reconcileNewLedgerEntry($lease_id,
$fundamental_type,
$reconciled[$type]['unapplied']);
$left = &$reconciled[$type];
$right = &$rec[$type];
$left['entry'] = array_merge($left['entry'], $right['entry']);
$left['balance'] += $right['balance'];
$left['applied'] += $right['applied'];
$left['unapplied'] = $right['unapplied'];
}
}
($this->Account->accountReceivableAccountID(),
$fundamental_type,
$amount,
array('LedgerEntry.customer_id' => $id));
return $reconciled;
}
@@ -189,7 +166,6 @@ class Customer extends AppModel {
'ContactEmail',
'ContactAddress',
),
'Account',
'Lease' =>
array('Unit' =>
array('order' => array('sort_order'),
@@ -201,22 +177,12 @@ class Customer extends AppModel {
'conditions' => array('Customer.id' => $id),
));
// Add the lease balance to each lease.
foreach ($customer['Lease'] AS &$lease) {
$stats = $this->Lease->stats($lease['id']);
$lease['balance'] = $stats['Account']['Ledger']['balance'];
}
// Figure out the outstanding balance of the current lease.
// Figure out the outstanding balance for this customer
$customer['stats'] = $this->stats($id);
// Figure out the total security deposit for the current lease.
$customer['deposits'] = $this->findSecurityDeposits($id);
// Add statistics into the customer account.
$customer['Account'] = array_merge($customer['Account'],
$customer['stats']['Account']['Ledger']);
return $customer;
}
@@ -228,34 +194,11 @@ class Customer extends AppModel {
* - Returns summary data from the requested customer.
*/
function stats($id = null) {
function stats($id = null, $cond = null, $link = null) {
if (!$id)
return null;
// Get the basic information necessary
$customer = $this->find('first',
array('contain' =>
array('Account' => array
('fields' => array('Account.id')),
'Lease' => array
('fields' => array('Lease.id'))
),
'conditions' => array
(array('Customer.id' => $id))));
// Get stats from the customer account, and each lease
$stats['Account'] = $this->Account->stats($customer['Account']['id']);
foreach ($customer['Lease'] AS $lease) {
$this->statsMerge($stats['Lease'], $this->Lease->stats($lease['id']));
}
// Merge the stats from both the customer specific account, as
// well as the leases. This will provide current customer standing.
$this->statsMerge($stats, $stats['Account']['Ledger']);
$this->statsMerge($stats, $stats['Lease']['Account']['Ledger']);
return $stats;
return $this->Statement->stats($this->statementID($id), $cond, $link);
}
}

View File

@@ -25,27 +25,37 @@ class Lease extends AppModel {
var $belongsTo = array(
'LeaseType',
'Unit',
'Account',
'Customer',
'Statement',
'LateSchedule',
);
var $hasMany = array(
'LedgerEntry',
// Cheat to get Account set as part of this class
'Account',
);
/**************************************************************************
**************************************************************************
**************************************************************************
* function: accountId
* - Returns the accountId of the given lease
* function: accessors
*/
function accountId($id) {
$this->cacheQueries = true;
$lease = $this->find('first', array
('recursive' => -1,
'fields' => array('account_id'),
'conditions' => array(array('id' => $id)),
));
$this->cacheQueries = false;
return $this->Account->invoiceAccountID();
}
return $lease['Lease']['account_id'];
function statementID($id) {
$this->cacheQueries = true;
$item = $this->find('first', array
('recursive' => -1,
'conditions' => compact('id'),
));
$this->cacheQueries = false;
$item = current($item);
return $item['statement_id'];
}
@@ -61,6 +71,10 @@ class Lease extends AppModel {
/* 'args' => compact('id', 'all', 'cond', 'link'), */
/* )); */
if (!isset($cond))
$cond = array();
$cond[] = array('LedgerEntry.lease_id' => $id);
$entries = $this->Account->findLedgerEntries($this->accountId($id),
$all, $cond, $link);
@@ -80,21 +94,10 @@ class Lease extends AppModel {
* - Returns an array of security deposit entries
*/
function findSecurityDeposits($id, $link = null) {
/* pr(array('function' => 'Lease::findSecurityDeposits', */
/* 'args' => compact('id', 'link'), */
/* )); */
$entries = $this->Account->findLedgerEntriesRelatedToAccount
($this->accountId($id),
return $this->Statement->findEntriesRelatedToAccount
($this->statementId($id),
$this->Account->securityDepositAccountID(),
true, null, $link);
/* pr(array('function' => 'Lease::findSecurityDeposits', */
/* 'args' => compact('id', 'link'), */
/* 'vars' => compact('lease'), */
/* 'return' => compact('entries'), */
/* )); */
return $entries;
null, $link);
}
@@ -108,7 +111,7 @@ class Lease extends AppModel {
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null) {
return $this->Account->findUnreconciledLedgerEntries
($this->accountId($id), $fundamental_type);
($this->accountId($id), $fundamental_type, array('LedgerEntry.lease_id' => $id));
}
@@ -128,7 +131,7 @@ class Lease extends AppModel {
function reconcileNewLedgerEntry($id, $fundamental_type, $amount) {
return $this->Account->reconcileNewLedgerEntry
($this->accountId($id), $fundamental_type, $amount);
($this->accountId($id), $fundamental_type, $amount, array('LedgerEntry.lease_id' => $id));
}
@@ -139,23 +142,11 @@ class Lease extends AppModel {
* - Returns summary data from the requested lease.
*/
function stats($id = null) {
function stats($id = null, $cond = null, $link = null) {
if (!$id)
return null;
// Find the associated account.
$lease = $this->find('first',
array('recursive' => -1,
'conditions' => array(array('Lease.id' => $id))));
// Pull the stats from the account.
$stats['Account'] = $this->Account->stats($lease['Lease']['account_id']);
// Place a summary of the stats (one lease account in this case)
// at the top level for easy summarized access.
$this->statsMerge($stats, $stats['Account']['Ledger']);
return $stats;
return $this->Statement->stats($this->statementID($id), $cond, $link);
}
}

View File

@@ -115,6 +115,9 @@ class Ledger extends AppModel {
* - Returns summary data from the requested ledger.
*/
function stats($id, $cond = null) {
if (!isset($cond))
$cond = array();
$cond[] = array('Ledger.id' => $id);
$stats = $this->find
('first', array
@@ -138,8 +141,7 @@ class Ledger extends AppModel {
) * IF(LedgerEntry.amount, LedgerEntry.amount, 0)
) AS balance",
"COUNT(LedgerEntry.id) AS entries"),
'conditions' => array(isset($cond) ? $cond : array(),
array('Ledger.id' => $id)),
'conditions' => $cond,
'group' => 'Ledger.id',
));

View File

@@ -11,6 +11,8 @@ class LedgerEntry extends AppModel {
var $belongsTo = array(
'MonetarySource',
'Transaction',
'Customer',
'Lease',
'DebitLedger' => array(
'className' => 'Ledger',
@@ -84,7 +86,7 @@ class LedgerEntry extends AppModel {
return $fields;
}
function ledgerContextFields2($ledger_id = null, $account_type = null) {
function ledgerContextFields2($ledger_id = null, $account_id = null, $account_type = null) {
$fields = array('id', 'name', 'comment', 'amount');
if (isset($ledger_id)) {
@@ -93,20 +95,29 @@ class LedgerEntry extends AppModel {
$fields[] = ("IF(LedgerEntry.credit_ledger_id = $ledger_id," .
" SUM(LedgerEntry.amount), NULL) AS credit");
if (isset($account_type)) {
if (in_array($account_type, array('ASSET', 'EXPENSE')))
$ledger_type = 'debit';
else
$ledger_type = 'credit';
$fields[] = ("(IF(LedgerEntry.{$ledger_type}_ledger_id = $ledger_id," .
if (isset($account_id) || isset($account_type)) {
$Account = new Account();
$account_ftype = $Account->fundamentalType($account_id ? $account_id : $account_type);
$fields[] = ("(IF(LedgerEntry.{$account_ftype}_ledger_id = $ledger_id," .
" 1, -1) * SUM(LedgerEntry.amount)) AS balance");
}
}
elseif (isset($account_id)) {
$fields[] = ("IF(DebitLedger.account_id = $account_id," .
" SUM(LedgerEntry.amount), NULL) AS debit");
$fields[] = ("IF(CreditLedger.account_id = $account_id," .
" SUM(LedgerEntry.amount), NULL) AS credit");
$Account = new Account();
$account_ftype = ucfirst($Account->fundamentalType($account_id));
$fields[] = ("(IF({$account_ftype}Ledger.account_id = $account_id," .
" 1, -1) * SUM(LedgerEntry.amount)) AS balance");
}
return $fields;
}
function ledgerContextConditions($ledger_id, $account_type) {
if (isset($ledger_id)) {
return array

123
site/models/statement.php Normal file
View File

@@ -0,0 +1,123 @@
<?php
class Statement extends AppModel {
var $hasMany = array(
'Lease',
'Customer',
'StatementEntry',
'ChargeStatementEntry' => array(
'className' => 'StatementEntry',
'conditions' => array('type' => 'CHARGE'),
),
'PaymentStatementEntry' => array(
'className' => 'StatementEntry',
'conditions' => array('type' => 'PAYMENT'),
),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* function: findStatementEntries
* - Returns an array of statement entries that belong to a given
* statement. There is extra work done... see the StatementEntry model.
*/
function findStatementEntries($id, $cond = null, $link = null) {
/* pr(array('function' => 'Statement::findStatementEntries', */
/* 'args' => compact('id', 'cond', 'link'), */
/* )); */
if (!isset($cond))
$cond = array();
$cond[] = array('Statement.id' => $id);
$entries = $this->find('all', array('link' => $link, 'conditions' => $cond));
/* pr(array('function' => 'Statement::findStatementEntries', */
/* 'args' => compact('id', 'cond', 'link'), */
/* 'return' => compact('entries'), */
/* )); */
return $entries;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: findEntriesRelatedToAccount
* - Returns an array of statement entries that belong to the given
* account, and are related to a specific account.
*/
function findEntriesRelatedToAccount($id, $rel_ids, $cond = null, $link = null) {
/* pr(array('function' => 'Statement::findEntriesRelatedToAccount', */
/* 'args' => compact('id', 'rel_ids', 'cond', 'link'), */
/* )); */
if (!isset($cond))
$cond = array();
if (!isset($link))
$link = array();
if (!is_array($rel_ids))
$rel_ids = array($rel_ids);
$link['StatementEntry'] = array('LedgerEntry' => array('Ledger' => array('Account')));
$cond[] = array('Account.id' => $rel_ids);
$entries = $this->findStatementEntries($id, $cond, $link);
$stats = $this->stats($id, $cond, $link);
$entries = array('Entries' => $entries,
'summary' => $stats);
/* pr(array('function' => 'Statement::findEntriesRelatedToAccount', */
/* 'args' => compact('id', 'relid', 'cond', 'link'), */
/* 'return' => compact('entries'), */
/* )); */
return $entries;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: stats
* - Returns summary data from the requested statement.
*/
function stats($id, $cond = null, $link = null) {
if (!isset($cond))
$cond = array();
if (!isset($link))
$link = array();
if (!isset($link['StatementEntry']))
$link['StatementEntry'] = array('fields' => array());
$cond[] = array('Statement.id' => $id);
$stats = $this->find
('first', array
('link' => $link,
'fields' =>
array("SUM(IF(StatementEntry.type = 'CHARGE',
StatementEntry.amount, NULL)) AS charges",
"SUM(IF(StatementEntry.type = 'PAYMENT',
StatementEntry.amount, NULL)) AS payments",
"SUM(IF(StatementEntry.type = 'CHARGE', 1, -1)
* IF(StatementEntry.amount, StatementEntry.amount, 0)
) AS balance",
"COUNT(StatementEntry.id) AS entries"),
'conditions' => $cond,
'group' => 'Statement.id',
));
// The fields are all tucked into the [0] index,
// and the rest of the array is useless (empty).
return $stats[0];
}
}
?>

View File

@@ -0,0 +1,9 @@
<?php
class StatementEntry extends AppModel {
var $belongsTo = array(
'Statement',
'LedgerEntry',
);
}

View File

@@ -63,12 +63,13 @@ echo $this->element('leases',
/**********************************************************************
* Account
* Customer Statement
*/
echo $this->element('accounts',
array('caption' => 'Account',
'accounts' => array($customer['Account'])));
echo $this->element('statement_entries',
array('caption' => 'Statement',
'statement_id' => $customer['Customer']['statement_id'],
));
/* End "detail supporting" div */

View File

@@ -143,8 +143,12 @@ foreach ($jqGridColumns AS &$col) {
}
// Set the default sort column
reset($jqGridColumns);
$sortname = current($jqGridColumns);
if (isset($sort_column)) {
$sortname = $jqGridColumns[$sort_column];
} else {
reset($jqGridColumns);
$sortname = current($jqGridColumns);
}
$sortname = $sortname['index'];
// Configure the grid setup, giving priority to user defined parameters
@@ -185,10 +189,14 @@ $jqGrid_setup = array_merge
jQuery(document).ready(function(){
currencyFormatter = function(el, cellval, opts) {
if (!cellval)
return;
$(el).html(fmtCurrency(cellval));
}
idFormatter = function(el, cellval, opts) {
if (!cellval)
return;
$(el).html('#'+cellval);
}

View File

@@ -1,5 +1,30 @@
<?php /* -*- mode:PHP -*- */
if (isset($account_ftype) || isset($ledger_id) || isset($account_id) || isset($ar_account)) {
$single_account = true;
} else {
$single_account = false;
}
if (isset($ledger_id) || isset($account_id) || isset($ar_account)) {
$single_amount = false;
} else {
$single_amount = true;
}
if (isset($reconcile_id)) {
$applied_amount = true;
} else {
$applied_amount = false;
}
if (isset($account_ftype)) {
$subtotal_amount = false;
} else {
$subtotal_amount = true;
}
// Define the table columns
$cols = array();
if (0) {
@@ -8,33 +33,42 @@ if (isset($notxgroup))
else
$cols['Transaction'] = array('index' => 'Transaction.id', 'formatter' => 'id');
} else {
$notxgroup = true;
$notxgroup = false;
$cols['Transaction'] = array('index' => 'Transaction.id', 'formatter' => 'id');
$cols['Entry'] = array('index' => 'LedgerEntry.id', 'formatter' => 'id');
}
$cols['Date'] = array('index' => 'Transaction.stamp', 'formatter' => 'date');
if (isset($account_ftype) || isset($ledger_id)) {
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'longname');
if ($single_account) {
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name');
}
else {
$cols['Debit Account'] = array('index' => 'DebitAccount.name', 'formatter' => 'longname');
$cols['Credit Account'] = array('index' => 'CreditAccount.name', 'formatter' => 'longname');
$cols['Debit Account'] = array('index' => 'DebitAccount.name', 'formatter' => 'name');
$cols['Credit Account'] = array('index' => 'CreditAccount.name', 'formatter' => 'name');
}
$cols['Source'] = array('index' => 'MonetarySource.name', 'formatter' => 'name');
$cols['Comment'] = array('index' => 'LedgerEntry.comment', 'formatter' => 'comment', 'width'=>150);
if (isset($ledger_id)) {
if ($single_amount) {
$cols['Amount'] = array('index' => 'LedgerEntry.amount', 'formatter' => 'currency');
}
else {
$cols['Debit'] = array('index' => 'debit', 'formatter' => 'currency');
$cols['Credit'] = array('index' => 'credit', 'formatter' => 'currency');
}
else {
$cols['Amount'] = array('index' => 'LedgerEntry.amount', 'formatter' => 'currency');
}
if (isset($reconcile_id)) {
if ($applied_amount) {
$cols['Applied'] = array('index' => "Reconciliation.amount", 'formatter' => 'currency');
}
$custom_post_data = compact('ledger_id', 'account_type', 'account_ftype', 'notxgroup');
if ($subtotal_amount) {
$cols['Sub-Total'] = array('index' => 'subtotal', 'formatter' => 'currency', 'sortable' => false);
}
$custom_post_data = compact('ledger_id', 'account_id', 'ar_account',
'account_type', 'account_ftype',
'customer_id', 'lease_id', 'transaction_id', 'notxgroup');
$jqGrid_options = array('jqGridColumns' => $cols,
'controller' => 'ledger_entries',
@@ -42,11 +76,6 @@ $jqGrid_options = array('jqGridColumns' => $cols,
$jqGrid_options += compact('grid_div_id', 'grid_id', 'caption', 'grid_setup', 'limit');
if (isset($ledger_id)) {
$jqGrid_options += array('action' => 'ledger',
'limit' => 50);
}
if (isset($ledger_entries)) {
$jqGrid_options += array('custom_ids' =>
array_map(create_function('$data',
@@ -54,6 +83,10 @@ if (isset($ledger_entries)) {
$ledger_entries),
'limit' => 10);
}
else {
$jqGrid_options += array('action' => 'ledger',
'limit' => 50);
}
if (isset($reconcile_id)) {
$custom_post_data += compact('reconcile_id');
@@ -61,5 +94,6 @@ if (isset($reconcile_id)) {
}
$jqGrid_options += compact('custom_post_data');
$jqGrid_options['sort_column'] = 'Date';
echo $this->element('jqGrid', $jqGrid_options);

View File

@@ -0,0 +1,50 @@
<?php /* -*- mode:PHP -*- */
if (0) {
$subtotal_amount = false;
} else {
$subtotal_amount = true;
}
// Define the table columns
$cols = array();
$cols['ID'] = array('index' => 'StatementEntry.id', 'formatter' => 'id');
$cols['Entry'] = array('index' => 'LedgerEntry.id', 'formatter' => 'id');
$cols['Date'] = array('index' => 'Transaction.stamp', 'formatter' => 'date');
//$cols['Type'] = array('index' => 'StatementEntry.type', 'formatter' => 'name');
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'longname');
//$cols['Comment'] = array('index' => 'StatementEntry.comment', 'formatter' => 'comment', 'width'=>150);
//$cols['Amount'] = array('index' => 'StatementEntry.amount', 'formatter' => 'currency');
$cols['Charge'] = array('index' => 'charge', 'formatter' => 'currency');
$cols['Payment'] = array('index' => 'payment', 'formatter' => 'currency');
if ($subtotal_amount) {
$cols['Sub-Total'] = array('index' => 'subtotal', 'formatter' => 'currency', 'sortable' => false);
}
$custom_post_data = compact('statement_id');
$jqGrid_options = array('jqGridColumns' => $cols,
'controller' => 'statement_entries',
);
$jqGrid_options += compact('grid_div_id', 'grid_id', 'caption', 'grid_setup', 'limit');
if (isset($statement_entries)) {
$jqGrid_options += array('custom_ids' =>
array_map(create_function('$data',
'return $data["id"];'),
$statement_entries),
'limit' => 10);
}
else {
$jqGrid_options += array('action' => 'statement',
'limit' => 50);
}
$jqGrid_options += compact('custom_post_data');
$jqGrid_options['sort_column'] = 'Date';
echo $this->element('jqGrid', $jqGrid_options);

View File

@@ -11,7 +11,6 @@ echo '<div class="lease view">' . "\n";
$lease_type = $lease['LeaseType'];
$customer = $lease['Customer'];
$account = $lease['Account'];
$unit = $lease['Unit'];
if (isset($lease['Lease']))
@@ -20,7 +19,7 @@ if (isset($lease['Lease']))
$rows = array(array('ID', $lease['id']),
array('Number', $lease['number']),
array('Lease Type', $lease_type['name']),
array('Unit', $html->link($unit['id'],
array('Unit', $html->link($unit['name'],
array('controller' => 'units',
'action' => 'view',
$unit['id']))),
@@ -36,10 +35,6 @@ $rows = array(array('ID', $lease['id']),
array('Notice Given', FormatHelper::date($lease['notice_given_date'], true)),
array('Notice Received', FormatHelper::date($lease['notice_received_date'], true)),
array('Closed', FormatHelper::date($lease['close_date'], true)),
array('Account', $html->link($account['name'],
array('controller' => 'accounts',
'action' => 'view',
$account['id']))),
array('Deposit', FormatHelper::currency($lease['deposit'])),
array('Rent', FormatHelper::currency($lease['amount'])),
array('Comment', $lease['comment']));
@@ -53,7 +48,7 @@ echo $this->element('table',
/**********************************************************************
* Account Info Box
* Lease Info Box
*/
echo '<div class="infobox">' . "\n";
@@ -80,15 +75,15 @@ echo '<div CLASS="detail supporting">' . "\n";
/**********************************************************************
* Current Ledger
* Lease Account History
*/
echo $this->element('ledger_entries',
array('caption' => "Current Ledger: (#{$account['id']}-{$account['CurrentLedger']['sequence']})",
'ledger_id' => $account['CurrentLedger']['id'],
'account_type' => $account['type'],
echo $this->element('statement_entries',
array('caption' => 'Statement',
'statement_id' => $lease['statement_id'],
));
/* End "detail supporting" div */
echo '</div>' . "\n";

View File

@@ -13,6 +13,8 @@ $transaction = $entry['Transaction'];
$debit_ledger = $entry['DebitLedger'];
$credit_ledger = $entry['CreditLedger'];
$source = $entry['MonetarySource'];
$customer = $entry['Customer'];
$lease = $entry['Lease'];
$entry = $entry['LedgerEntry'];
$rows = array(array('ID', $entry['id']),
@@ -21,8 +23,20 @@ $rows = array(array('ID', $entry['id']),
'action' => 'view',
$transaction['id']))),
array('Timestamp', FormatHelper::datetime($transaction['stamp'])),
array('Monetary Source', (isset($source['id'])
? $html->link('#'.$source['id'],
array('Customer', (isset($customer['name'])
? $html->link($customer['name'],
array('controller' => 'customers',
'action' => 'view',
$customer['id']))
: null)),
array('Lease', (isset($lease['id'])
? $html->link('#'.$lease['id'],
array('controller' => 'leases',
'action' => 'view',
$lease['id']))
: null)),
array('Monetary Source', (isset($source['name'])
? $html->link($source['name'],
array('controller' => 'monetary_sources',
'action' => 'view',
$source['id']))
@@ -67,12 +81,12 @@ echo $this->element('table',
echo '<div class="infobox">' . "\n";
$rows = array();
if ($debit_ledger['Account']['trackable']) {
$rows[] = array('Debit Amount Reconciled:', FormatHelper::currency($stats['debit_amount_reconciled']));
$rows[] = array('Debit Amount Remaining:', FormatHelper::currency($stats['debit_amount_remaining']));
$rows[] = array('Payments Received:', FormatHelper::currency($stats['debit_amount_reconciled']));
$rows[] = array('Amount Owing:', FormatHelper::currency($stats['debit_amount_remaining']));
}
if ($credit_ledger['Account']['trackable']) {
$rows[] = array('Credit Amount Reconciled:', FormatHelper::currency($stats['credit_amount_reconciled']));
$rows[] = array('Credit Amount Remaining:', FormatHelper::currency($stats['credit_amount_remaining']));
$rows[] = array('Charges Reconciled:', FormatHelper::currency($stats['credit_amount_reconciled']));
$rows[] = array('Unapplied Amount:', FormatHelper::currency($stats['credit_amount_remaining']));
}
echo $this->element('table',
array('class' => 'summary',
@@ -97,26 +111,25 @@ echo '<div CLASS="detail supporting">' . "\n";
* Reconciliation Ledger Entries
*/
echo $this->element('ledger_entries',
array('caption' => "Debit Applications",
'grid_div_id' => 'debit_reconciliation_ledger_entries',
//'ledger_id' => $debit_ledger['id'],
//'account_type' => $debit_ledger['Account']['type'],
'account_ftype' => 'debit',
'reconcile_id' => $entry['id'],
'ledger_entries' => $reconciled['debit']['entry'],
));
if ($debit_ledger['Account']['trackable']) {
echo $this->element('ledger_entries',
array('caption' => "Payments Received",
'grid_div_id' => 'debit_reconciliation_ledger_entries',
'account_ftype' => 'debit',
'reconcile_id' => $entry['id'],
//'ledger_entries' => $reconciled['debit']['entry'],
));
}
echo $this->element('ledger_entries',
array('caption' => "Credit Applications",
'grid_div_id' => 'credit_reconciliation_ledger_entries',
//'ledger_id' => $credit_ledger['id'],
//'account_type' => $credit_ledger['Account']['type'],
//'account_ftype' => 'debit', // Looking for debits to match this credit
'account_ftype' => 'credit',
'reconcile_id' => $entry['id'],
'ledger_entries' => $reconciled['credit']['entry'],
));
if ($credit_ledger['Account']['trackable']) {
echo $this->element('ledger_entries',
array('caption' => "Charges Paid",
'grid_div_id' => 'credit_reconciliation_ledger_entries',
'account_ftype' => 'credit',
'reconcile_id' => $entry['id'],
//'ledger_entries' => $reconciled['credit']['entry'],
));
}
/* End "detail supporting" div */

View File

@@ -54,7 +54,8 @@ echo '<div CLASS="detail supporting">' . "\n";
echo $this->element('ledger_entries',
array('caption' => 'Entries in Transaction',
'ledger_entries' => $transaction['LedgerEntry'],
//'ledger_entries' => $transaction['LedgerEntry'],
'transaction_id' => $transaction['Transaction']['id'],
'notxgroup' => true,
));

View File

@@ -57,16 +57,15 @@ echo $this->element('leases',
/**********************************************************************
* Ledger History
* Current Lease Statement History
*/
/* foreach($unit['Lease'] AS $lease) { */
/* pr($lease); */
/* $caption = 'Lease #'.$lease['number'].' (Tenant: '.$lease['Customer']['name'].')'; */
/* echo $this->element('lease', */
/* array('caption' => $caption, */
/* 'entries' => $lease['Customer']['Transaction'], */
/* 'ledger' => array('mix'=>1))); */
/* } */
echo $this->element('statement_entries',
array('caption' => ('Current Lease Statement (' .
$unit['CurrentLease']['Customer']['name'] .
')'),
'statement_id' => $unit['CurrentLease']['statement_id']
));
/* End "detail supporting" div */

View File

@@ -65,8 +65,10 @@ tr.evnrow { background: #f4f4f4; }
*/
table.detail { width : 60%;
float: left; }
table.detail td.field { width: 10em; }
float : left; }
table.detail td.field { width : 10em; }
table.item.detail td.value { white-space : normal; }
div.detail.supporting { clear : both;
padding-top: 1.5em; }