Compare commits

..

13 Commits

Author SHA1 Message Date
abijah
f01e62fc6e Extra notes and scratch SQL statements added during the 0.2.0 work, but added only now.
git-svn-id: file:///svn-source/pmgr/branches/v0.3.0_work@942 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 03:37:13 +00:00
abijah
9952673655 Branching for 0.3.0 work
git-svn-id: file:///svn-source/pmgr/branches/v0.3.0_work@941 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 03:30:17 +00:00
abijah
ccd1af6154 Merge in the v0.2.0 work
git-svn-id: file:///svn-source/pmgr/trunk@938 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 03:25:52 +00:00
abijah
ce633d816a Added bookkeeping notes, apparently on 1/14/10
git-svn-id: file:///svn-source/pmgr/trunk@937 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 03:16:34 +00:00
abijah
83bfb8d32d As the database has grown, the statement entry page query has finally ground to a halt. The query was kludged as simple as possible, and it now operates much quicker. A cleaner solution would be nice...
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@936 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 03:10:54 +00:00
abijah
28817cea38 Removed buttons from the print media
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@914 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-01-15 01:27:44 +00:00
abijah
3dca204ac6 Added the Deposit row to all tenders, not just those that have been deposited. This helps avoid confusion when looking at a non-deposited tender, since one may be trying to figure out whether or not it has been deposited and yet not remember if this is the appropriate screen.
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@900 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-12-09 18:02:00 +00:00
abijah
2fb2e6f5aa Update todo to reflect newly implemented features.
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@875 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-09 23:53:39 +00:00
abijah
44def81c81 Merge in from v0.1.0
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@874 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-09 23:51:45 +00:00
abijah
3b885e2686 Fixed the problem of client side lease selection breaking the automated rent invoicing tools.
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@872 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-09 23:17:46 +00:00
abijah
e162d35d56 Added a more automated mechanism for adding multiple rent charges to an invoice. Also included is a proration tool. This needs more work though, since it relies on server side data from the lease. Selecting a new lease on the client side will cause this change to fail, and so we'll need to add a column for charged-through. Finally, error messages for invoice and receipt were improved slightly to better explain the error.
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@871 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-09 22:48:37 +00:00
abijah
3b3ed7a264 Branch to add minor enhancements to v0.1.0
git-svn-id: file:///svn-source/pmgr/branches/v0.2.0_work@870 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-09 19:58:50 +00:00
abijah
9674812e78 Merge in from the v0.1.0 tag, which is a bit of a botch. The intention was to make the change to trunk, then re-label as v0.1.1. However, due to a mixup, this was put directly as the v0.1.0 tag. It isn't good, but the change is small enough we'll live with it this time.
git-svn-id: file:///svn-source/pmgr/trunk@864 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-02 15:54:00 +00:00
11 changed files with 480 additions and 10259 deletions

51
bookkeeping.notes Normal file
View File

@@ -0,0 +1,51 @@
Book Keeping Challenges / Issues
- Chart of Accounts is not sufficient
- One payment can go towards more than one charge
- One charge can be paid for by more than one payment
- Need to know: how much money does customer owe?
- Need to know: how much money has customer been charged for "Rent"?
- Need to know: how much money has customer paid towards "Rent" (nothing else)?
- Reverse a charge
To make charge reversal work, I'm presently issuing a credit note
(transaction) that has 3 ledger entries:
Debit charged account - Credit A/R
Debit A/R - Credit "Credit" account
Debit "Credit" account - Credit A/R
And 3 statement entries:
Reversal on charged account
Negative Disbursement on "Credit" account
Positive Disbursement on "Credit" account
Obviously, the two "Credit" account ledger entries cancel each other
out. However, the monies need to be reversed in the A/R account, and a
previous transaction will have already performed an A/R credit and so
the two A/R credits will create an imbalance in A/R unless we move
those funds to our "Credit" account. The "Credit" account statement
entries are needed to undo any previous disbursement to the charge
being reversed, and then to re-disburse those funds to a different
charge (or possibly just a Surplus entry if no other charges exist.)
Question
- What should be recorded with this charge reversal?
Charge of $5 for "Parking"
Charge of $6 for "Rent"
Payment of $6
Reverse the $5 "Parking" charge
- What should be recorded with this charge reversal?
Charge of $5 for "Parking"
Charge of $6 for "Rent"
Charge of $7 for "Pets"
Payment of $13
Reverse the $5 "Parking" charge
- What should be recorded with this charge reversal?
Charge of $5 for "Parking"
Charge of $6 for "Rent"
Charge of $7 for "Pets"
Payment of $18
Reverse the $5 "Parking" charge

File diff suppressed because it is too large Load Diff

View File

@@ -135,9 +135,7 @@ FROM pmgr_transactions T
-- E.account_id != T.account_id -- E.account_id != T.account_id
GROUP BY T.id GROUP BY T.id
HAVING HAVING
(T.type = 'INVOICE' AND Tamt <> T.amount) (T.amount <> IF(T.type IN ('INVOICE','TRANSFER','DEPOSIT','PAYMENT'), Tamt, Oamt))
OR
(T.type <> 'INVOICE' AND Oamt <> T.amount)
OR OR
(Tamt * -1 <> Oamt) (Tamt * -1 <> Oamt)
@@ -576,3 +574,105 @@ ORDER BY IF(U.id IS NOT NULL, 1,
IF (S.id IS NOT NULL, 3, 4))) ASC, IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC IF (G.id IS NOT NULL, G.rank, 0) ASC
; ;
-- ----------------------------------------------------
-- Income by Month
SELECT MONTH(SE.effective_date) AS mon, YEAR(SE.effective_date) AS yr,
SE.account_id AS acct, ROUND(SUM(SE.amount)) AS amt
FROM pmgr_statement_entries SE
WHERE SE.type = 'CHARGE'
AND SE.effective_date >= '2009-04-01' AND SE.effective_date <= NOW()
GROUP BY yr, mon, acct WITH ROLLUP
-- ----------------------------------------------------
-- Rent Income by Month
SELECT MONTH(SE.effective_date) AS mon, YEAR(SE.effective_date) AS yr,
ROUND(SUM(SE.amount)) AS amt
FROM pmgr_statement_entries SE
WHERE SE.type = 'CHARGE'
AND SE.effective_date >= '2009-04-01' AND SE.effective_date <= NOW()
AND SE.account_id = 13
GROUP BY yr, mon WITH ROLLUP
-- ----------------------------------------------------
-- Occupancy during given month
SELECT COUNT(L.id) FROM pmgr_leases L
WHERE L.movein_date < '2009-10-01'
AND (L.moveout_date IS NULL OR L.moveout_date > '2009-09-01')
-- ----------------------------------------------------
-- Move-ins by month
SELECT MONTH(L.movein_date) AS mon, YEAR(L.movein_date) AS yr, COUNT(L.id)
FROM pmgr_leases L
WHERE L.movein_date >= '2009-04-01'
GROUP BY yr, mon
-- ----------------------------------------------------
-- Move-outs by month
SELECT MONTH(L.moveout_date) AS mon, YEAR(L.moveout_date) AS yr, COUNT(L.id)
FROM pmgr_leases L
WHERE L.moveout_date >= '2009-04-01'
GROUP BY yr, mon
-- ----------------------------------------------------
-- Move-ins/Move-outs by month
SELECT
MONTH(L.movein_date) AS mon, YEAR(L.movein_date) AS yr,
IF(L.movein_date AS mon, YEAR(L.movein_date) AS yr,
FROM pmgr_leases L
WHERE L.movein_date >= '2009-04-01'
GROUP BY yr, mon
-- ----------------------------------------------------
-- Rent charged
SELECT SUM(SE.amount)
FROM pmgr_statement_entries SE
LEFT JOIN pmgr_accounts A ON A.id = SE.account_id
WHERE A.name = 'Rent'
-- AND SE.effective_date >= '2009-04-01'
-- AND SE.effective_date < '2009-12-01'
-- --------------------------------------------------------------
-- Merge two customers
SELECT * FROM pmgr_statement_entries WHERE customer_id = 65
;
UPDATE pmgr_leases SET customer_id=21 WHERE customer_id=65;
UPDATE pmgr_reservations SET customer_id=21 WHERE customer_id=65;
UPDATE pmgr_statement_entries SET customer_id=21 WHERE customer_id=65;
UPDATE pmgr_tenders SET customer_id=21 WHERE customer_id=65;
UPDATE pmgr_transactions SET customer_id=21 WHERE customer_id=65;
-- Make sure to update customer info afterwards
-- --------------------------------------------------------------
-- Determine income from a customer
SELECT NT.name AS 'type', SUM(LE.amount) AS 'total'
FROM pmgr_tenders N
LEFT JOIN pmgr_tender_types NT ON NT.id = N.tender_type_id
LEFT JOIN pmgr_ledger_entries LE ON LE.id = N.ledger_entry_id
LEFT JOIN pmgr_customers C ON C.id = N.customer_id
WHERE
N.customer_id = 49
AND N.nsf_ledger_entry_id IS NULL
AND (NT.tillable OR NT.auto_deposit)
GROUP BY NT.name WITH ROLLUP
-- --------------------------------------------------------------
-- Determine rent charges by month
SELECT MONTH(SE.effective_date) AS 'mon',
YEAR(SE.effective_date) AS 'yr',
DATE_FORMAT(SE.effective_date, "%m/1/%Y") AS 'date',
SUM(SE.amount) AS 'total'
FROM pmgr_accounts A
LEFT JOIN pmgr_statement_entries SE ON SE.account_id = A.id
WHERE
A.name = 'Rent'
AND SE.effective_date < NOW()
GROUP BY yr, mon -- WITH ROLLUP

View File

@@ -47,7 +47,17 @@ class StatementEntriesController extends AppController {
if (!empty($params['post']['custom']['statement_entry_id'])) { if (!empty($params['post']['custom']['statement_entry_id'])) {
$link['ChargeEntry'] = array(); $link['ChargeEntry'] = array();
$link['DisbursementEntry'] = array(); // This query actually represents a union...
// Unpaid Charge/Surplus: ChargeID - NULL; DisbursementID - NULL
// Paid Charge/Refund: ChargeID - NULL; DisbursementID - !NULL
// Disbursement/Reversal: ChargeID - !NULL; DisbursementID - NULL
// <EMPTY SET>: ChargeID - !NULL; DisbursementID - !NULL
//
// The query is really slow unless we add the `id` condition to the join.
// A cleaner query would be nice, but we must work within the Cake framework.
$link['DisbursementEntry'] = array('conditions' =>
'`DisbursementEntry`.`id` = '
. $params['post']['custom']['statement_entry_id']);
} }
return array('link' => $link); return array('link' => $link);

View File

@@ -48,24 +48,32 @@ function verifyRequest(formData, jqForm, options) {
if (formData[i]['name'] == "data[Customer][id]" && if (formData[i]['name'] == "data[Customer][id]" &&
!(formData[i]['value'] > 0)) { !(formData[i]['value'] > 0)) {
//$("#debug").append('<P>Missing Customer ID'); //$("#debug").append('<P>Missing Customer ID');
alert("Must select a customer first"); alert("Please select a customer first.");
return false; return false;
} }
if (formData[i]['name'] == "data[Transaction][stamp]" && if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') { formData[i]['value'] == '') {
//$("#debug").append('<P>Bad Stamp'); //$("#debug").append('<P>Bad Stamp');
alert("Must enter a valid date stamp"); if (formData[i]['value'] != '')
alert(formData[i]['value'] + " is not valid date stamp. Please correct it.");
else
alert("Please enter a valid date stamp first.");
return false; return false;
} }
// Terrible way to accomplish this... // Terrible way to accomplish this...
for (var j = 0; j < 20; ++j) { for (var j = 0; j < 20; ++j) {
if (formData[i]['name'] == "data[Entry]["+j+"][amount]" && if (formData[i]['name'] == "data[Entry]["+j+"][amount]") {
!(formData[i]['value'] > 0)) { var val = formData[i]['value'].replace(/\$/,'');
//$("#debug").append('<P>Bad Amount'); //$("#debug").append('<P>Bad Amount');
alert("Must enter a valid amount"); if (!(val > 0)) {
return false; if (formData[i]['value'] == '')
alert("Please enter an amount first.");
else
alert('"'+formData[i]['value']+'"' + " is not valid amount. Please correct it.");
return false;
}
} }
} }

View File

@@ -11,6 +11,7 @@ $cols['Signed'] = array('index' => 'Lease.lease_date', 'formatter' => 'dat
$cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date'); $cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date');
$cols['Move-Out'] = array('index' => 'Lease.moveout_date', 'formatter' => 'date'); $cols['Move-Out'] = array('index' => 'Lease.moveout_date', 'formatter' => 'date');
$cols['Closed'] = array('index' => 'Lease.close_date', 'formatter' => 'date'); $cols['Closed'] = array('index' => 'Lease.close_date', 'formatter' => 'date');
$cols['Charge-Thru'] = array('index' => 'Lease.charge_through_date', 'formatter' => 'date');
$cols['Paid-Thru'] = array('index' => 'Lease.paid_through_date', 'formatter' => 'date'); $cols['Paid-Thru'] = array('index' => 'Lease.paid_through_date', 'formatter' => 'date');
$cols['Status'] = array('index' => 'status', 'formatter' => 'longenum'); $cols['Status'] = array('index' => 'status', 'formatter' => 'longenum');
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency'); $cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
@@ -18,7 +19,7 @@ $cols['Comment'] = array('index' => 'Lease.comment', 'formatter' => 'com
if (!empty($this->params['action'])) { if (!empty($this->params['action'])) {
if ($this->params['action'] === 'closed') if ($this->params['action'] === 'closed')
$grid->invalidFields(array('Paid-Thru', 'Status')); $grid->invalidFields(array('Charge-Thru', 'Paid-Thru', 'Status'));
elseif ($this->params['action'] === 'active') elseif ($this->params['action'] === 'active')
$grid->invalidFields(array('Closed')); $grid->invalidFields(array('Closed'));
elseif ($this->params['action'] === 'delinquent') elseif ($this->params['action'] === 'delinquent')
@@ -32,4 +33,4 @@ $grid
->defaultFields(array('Lease')) ->defaultFields(array('Lease'))
->searchFields(array('Customer', 'Unit')) ->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null, ->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Signed', 'Status', 'Comment'))); array_diff(array_keys($cols), array('Signed', 'Charge-Thru', 'Status', 'Comment')));

View File

@@ -10,6 +10,7 @@ $customer = $lease['Customer'];
if (isset($lease['Lease'])) if (isset($lease['Lease']))
$lease = $lease['Lease']; $lease = $lease['Lease'];
//pr(compact('unit', 'customer', 'lease', 'movein'));
/********************************************************************** /**********************************************************************
********************************************************************** **********************************************************************
@@ -25,6 +26,8 @@ Configure::write('debug', '0');
<script type="text/javascript"><!-- <script type="text/javascript"><!--
var lease_charge_through;
// prepare the form when the DOM is ready // prepare the form when the DOM is ready
$(document).ready(function() { $(document).ready(function() {
var options = { var options = {
@@ -62,19 +65,27 @@ function verifyRequest(formData, jqForm, options) {
if (formData[i]['name'] == "data[Transaction][stamp]" && if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') { formData[i]['value'] == '') {
//$("#debug").append('<P>Bad Stamp'); //$("#debug").append('<P>Bad Stamp');
alert("Must enter a valid date stamp"); if (formData[i]['value'] != '')
alert(formData[i]['value'] + " is not valid date stamp. Please correct it.");
else
alert("Please enter a valid date stamp first.");
return false; return false;
} }
// Terrible way to accomplish this... // Terrible way to accomplish this...
/* for (var j = 0; j < 20; ++j) { */ for (var j = 0; j < 20; ++j) {
/* if (formData[i]['name'] == "data[Entry]["+j+"][amount]" && */ if (formData[i]['name'] == "data[Entry]["+j+"][amount]") {
/* !(formData[i]['value'] > 0)) { */ var val = formData[i]['value'].replace(/\$/,'');
/* //$("#debug").append('<P>Bad Amount'); */ //$("#debug").append('<P>Bad Amount');
/* alert("Must enter a valid amount"); */ if (!(val > 0)) {
/* return false; */ if (formData[i]['value'] == '')
/* } */ alert("Please enter an amount for Charge #"+j+", or remove the Charge completely.");
/* } */ else
alert('"'+formData[i]['value']+'"' + " is not a valid amount for Charge #"+j+". Please correct it.");
return false;
}
}
}
} }
//$("#debug").append('OK'); //$("#debug").append('OK');
@@ -142,6 +153,7 @@ function onRowSelect(grid_id, lease_id) {
$("#invoice-deposit").html($(grid_id).getCell(lease_id, 'Lease-deposit') $("#invoice-deposit").html($(grid_id).getCell(lease_id, 'Lease-deposit')
? $(grid_id).getCell(lease_id, 'Lease-deposit') ? $(grid_id).getCell(lease_id, 'Lease-deposit')
: '-'); : '-');
lease_charge_through = $(grid_id).getCell(lease_id, 'Lease-charge_through_date')
// Hide the "no lease" message and show the current lease // Hide the "no lease" message and show the current lease
$(".lease-selection-invalid").hide(); $(".lease-selection-invalid").hide();
@@ -167,6 +179,78 @@ function onGridState(grid_id, state) {
} }
} }
function setNextRent(id) {
var chg_thru;
$('.ChargeForm').each( function(i) {
if ($('.ChargeFormThroughDate', this).attr('id') == 'Entry'+id+'ThroughDate')
return;
if ($('.ChargeFormAccount option:selected', this).val() == <?php echo $rentAccount ?>
&& $('.ChargeFormThroughDate', this).val()) {
var dt = new Date($('.ChargeFormThroughDate', this).val());
//$('#debug').append('Rent in ' + i + '; date ' + dt + '<BR>');
if (chg_thru == null || dt > chg_thru)
chg_thru = dt;
}
});
if (!chg_thru)
chg_thru = new Date(lease_charge_through);
if (chg_thru < dateEOM(chg_thru)) {
// Add a charge to finish out the month
datepickerSet('Entry'+id+'EffectiveDate', dateTomorrow(chg_thru));
datepickerSet('Entry'+id+'ThroughDate', dateEOM(chg_thru));
} else {
// Add a whole month's charge for next month
datepickerSet('Entry'+id+'EffectiveDate', dateNextBOM(chg_thru));
datepickerSet('Entry'+id+'ThroughDate', dateNextEOM(chg_thru));
}
// Now add in the amount owed based on the calculated
// effective and through dates.
prorate(id);
}
function prorate(id) {
var edt = datepickerGet('Entry'+id+'EffectiveDate');
var tdt = datepickerGet('Entry'+id+'ThroughDate');
var rent = $('#invoice-rent').html().replace(/\$/,'');
// Reset the comment. It might wipe out a user comment,
// but it's probably low risk/concern
$('#Entry'+id+'Comment').val('');
if (edt == null || tdt == null) {
alert('Can only prorate with both effective and through dates');
rent = 0;
}
else if (edt > tdt) {
alert('Effective date is later than the Through date');
rent = 0;
}
else if (tdt.getMonth() == edt.getMonth() + 1 &&
edt.getDate() == tdt.getDate() + 1) {
// appears to be anniversary billing, one full cycle
}
else if (edt.getTime() == dateBOM(edt).getTime() &&
tdt.getTime() == dateEOM(edt).getTime()) {
// appears to be one full month
}
else {
var one_day=1000*60*60*24;
var days = Math.ceil((tdt.getTime()-edt.getTime()+1)/(one_day));
var dim =
((edt.getMonth() == tdt.getMonth())
? dateEOM(edt).getDate() // prorated within the month.
: 30); // prorated across months.
rent *= days / dim;
$('#Entry'+id+'Comment').val('Rent proration: '+days+'/'+dim+' days');
}
$('#Entry'+id+'Amount').val(fmtCurrency(rent));
}
function addChargeSource(flash) { function addChargeSource(flash) {
var id = $("#charge-entry-id").val(); var id = $("#charge-entry-id").val();
addDiv('charge-entry-id', 'charge', 'charges', flash, addDiv('charge-entry-id', 'charge', 'charges', flash,
@@ -178,26 +262,32 @@ function addChargeSource(flash) {
echo FormatHelper::phpVarToJavascript echo FormatHelper::phpVarToJavascript
($this->element('form_table', ($this->element('form_table',
array('id' => 'Entry%{id}Form', array('id' => 'Entry%{id}Form',
'class' => "item invoice ledger-entry entry", 'class' => "ChargeForm item invoice ledger-entry entry",
//'with_name_after' => ':', //'with_name_after' => ':',
'field_prefix' => 'Entry.%{id}', 'field_prefix' => 'Entry.%{id}',
'fields' => array 'fields' => array
("account_id" => array('name' => 'Account', ("account_id" => array('name' => 'Account',
'opts' => 'opts' =>
array('options' => $chargeAccounts, array('class' => 'ChargeFormAccount',
'options' => $chargeAccounts,
'value' => $defaultAccount, 'value' => $defaultAccount,
), ),
'between' => '<A HREF="#" ONCLICK="setNextRent(\'%{id}\'); return false;">Rent</A>',
), ),
"effective_date" => array('opts' => "effective_date" => array('opts' =>
array('type' => 'text'), array('class' => 'ChargeFormEffectiveDate',
'type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerBOM(\'TransactionStamp\',\'Entry%{id}EffectiveDate\'); return false;">BOM</A>', 'between' => '<A HREF="#" ONCLICK="datepickerBOM(\'TransactionStamp\',\'Entry%{id}EffectiveDate\'); return false;">BOM</A>',
), ),
"through_date" => array('opts' => "through_date" => array('opts' =>
array('type' => 'text'), array('class' => 'ChargeFormThroughDate',
'type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>', 'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>',
), ),
"amount" => array('opts' => array('class' => 'invoice amount')), "amount" => array('opts' => array('class' => 'ChargeFormAmount invoice amount'),
"comment" => array('opts' => array('size' => 50)), 'between' => '<A HREF="#" ONCLICK="prorate(\'%{id}\'); return false;">Prorate</A>',
),
"comment" => array('opts' => array('class' => 'ChargeFormComment', 'size' => 50)),
), ),
))) . "+\n"; ))) . "+\n";
?> ?>
@@ -233,7 +323,8 @@ if (empty($movein))
array('gridstate' => array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'), 'onGridState("#"+$(this).attr("id"), gridstate)'),
), ),
'exclude' => array('Closed'), 'include' => array('Charge-Thru'),
'exclude' => array('Closed', 'Paid-Thru'),
'action' => 'active', 'action' => 'active',
'nolinks' => true, 'nolinks' => true,
'limit' => 10, 'limit' => 10,
@@ -330,9 +421,34 @@ Configure::write('debug', '0');
$('tr td:nth-child('+col+'), tr th:nth-child('+col+')', this).remove(); $('tr td:nth-child('+col+'), tr th:nth-child('+col+')', this).remove();
}; };
function addHidden(id, fld, name) {
$('#Entry'+id+fld).after
('<input type="hidden"' +
' name="data[Entry]['+id+']['+name+']"' +
' value="' + $('#Entry'+id+fld).val() + '">');
}
$(document).ready(function(){ $(document).ready(function(){
datepicker('TransactionStamp'); datepicker('TransactionStamp');
<?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
$("#invoice-lease").html("<?php echo '#'.$lease['number']; ?>");
$("#invoice-unit").html("<?php echo $unit['name']; ?>");
$("#invoice-customer").html("<?php echo $customer['name']; ?>");
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['rent']); ?>");
$("#invoice-late").html("<?php echo FormatHelper::currency($defaultLate); ?>");
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['deposit']); ?>");
lease_charge_through = <?php
if ($lease['charge_through_date'])
echo 'new Date("'.date('m/d/Y', strtotime($lease['charge_through_date'])).'")';
elseif ($lease['paid_through_date'])
echo 'new Date("'.date('m/d/Y', strtotime($lease['paid_through_date'])).'")';
else
echo 'dateYesterday("'.date('m/d/Y', strtotime($lease['movein_date'])).'")';
?>;
<?php else: ?>
$("#lease-id").val(0); $("#lease-id").val(0);
$("#invoice-lease").html("INTERNAL ERROR"); $("#invoice-lease").html("INTERNAL ERROR");
$("#invoice-unit").html("INTERNAL ERROR"); $("#invoice-unit").html("INTERNAL ERROR");
@@ -340,6 +456,8 @@ Configure::write('debug', '0');
$("#invoice-rent").html("INTERNAL ERROR"); $("#invoice-rent").html("INTERNAL ERROR");
$("#invoice-late").html("INTERNAL ERROR"); $("#invoice-late").html("INTERNAL ERROR");
$("#invoice-deposit").html("INTERNAL ERROR"); $("#invoice-deposit").html("INTERNAL ERROR");
<?php endif; ?>
<?php if (empty($movein)): ?> <?php if (empty($movein)): ?>
@@ -356,7 +474,7 @@ Configure::write('debug', '0');
$('#TransactionStamp').after $('#TransactionStamp').after
('<input type="hidden"' + ('<input type="hidden"' +
' name="data[Transaction][stamp]"' + ' name="data[Transaction][stamp]"' +
' value="<?php echo date('m/d/Y', $movein['time']); ?>">'); ' value="' + $("#TransactionStamp").val() + '">');
$("#TransactionComment").val('Move-In Charges'); $("#TransactionComment").val('Move-In Charges');
<?php if ($movein['deposit'] != 0): ?> <?php if ($movein['deposit'] != 0): ?>
@@ -364,61 +482,28 @@ Configure::write('debug', '0');
$('#Entry'+id+'Form').removeCol(2); $('#Entry'+id+'Form').removeCol(2);
$('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true); $('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true);
$('#Entry'+id+'EffectiveDate').val("<?php echo date('m/d/Y', $movein['effective_time']); ?>"); $('#Entry'+id+'EffectiveDate').val("<?php echo date('m/d/Y', $movein['effective_time']); ?>");
$('#Entry'+id+'EffectiveDate').after addHidden(id, 'EffectiveDate', 'effective_date');
('<input type="hidden"' +
' name="data[Entry]['+id+'][effective_date]"' +
' value="<?php echo date('m/d/Y', $movein['effective_time']); ?>">');
$('#Entry'+id+'AccountId').val(<?php echo $securityDepositAccount; ?>); $('#Entry'+id+'AccountId').val(<?php echo $securityDepositAccount; ?>);
$('#Entry'+id+'AccountId').after addHidden(id, 'AccountId', 'account_id');
('<input type="hidden"' +
' name="data[Entry]['+id+'][account_id]"' +
' value="<?php echo $securityDepositAccount; ?>">');
$('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['deposit']); ?>"); $('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['deposit']); ?>");
$('#Entry'+id+'Amount').after addHidden(id, 'Amount', 'amount');
('<input type="hidden"' +
' name="data[Entry]['+id+'][amount]"' +
' value="<?php echo FormatHelper::currency($movein['deposit']); ?>">');
//$('#Entry'+id+'Comment').val('Move-In Security Deposit');
$('#Entry'+id+'Comment').removeAttr('disabled'); $('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?> <?php endif; ?>
id = addChargeSource(false); id = addChargeSource(false);
$('#Entry'+id+'Form').removeCol(2); $('#Entry'+id+'Form').removeCol(2);
$('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true); $('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true);
$('#Entry'+id+'EffectiveDate').val("<?php echo date('m/d/Y', $movein['effective_time']); ?>"); setNextRent(id);
$('#Entry'+id+'EffectiveDate').after addHidden(id, 'EffectiveDate', 'effective_date');
('<input type="hidden"' + addHidden(id, 'ThroughDate', 'through_date');
' name="data[Entry]['+id+'][effective_date]"' + addHidden(id, 'AccountId', 'account_id');
' value="<?php echo date('m/d/Y', $movein['effective_time']); ?>">'); addHidden(id, 'Amount', 'amount');
$('#Entry'+id+'ThroughDate').val("<?php echo date('m/d/Y', $movein['through_time']); ?>");
$('#Entry'+id+'ThroughDate').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][through_date]"' +
' value="<?php echo date('m/d/Y', $movein['through_time']); ?>">');
$('#Entry'+id+'AccountId').val(<?php echo $rentAccount; ?>);
$('#Entry'+id+'AccountId').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][account_id]"' +
' value="<?php echo $rentAccount; ?>">');
$('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['prorated_rent']); ?>");
$('#Entry'+id+'Amount').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][amount]"' +
' value="<?php echo FormatHelper::currency($movein['prorated_rent']); ?>">');
$('#Entry'+id+'Comment').val("<?php echo($movein['prorated'] ? 'Move-In Rent (Prorated)' : ''); ?>");
$('#Entry'+id+'Comment').removeAttr('disabled'); $('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?> <?php endif; ?>
<?php if (isset($lease['id'])): ?> <?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
$("#invoice-lease").html("<?php echo '#'.$lease['number']; ?>");
$("#invoice-unit").html("<?php echo $unit['name']; ?>");
$("#invoice-customer").html("<?php echo $customer['name']; ?>");
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['rent']); ?>");
$("#invoice-late").html("<?php echo FormatHelper::currency($defaultLate); ?>");
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['deposit']); ?>");
onGridState(null, 'hidden'); onGridState(null, 'hidden');
<?php else: ?> <?php else: ?>
onGridState(null, 'visible'); onGridState(null, 'visible');

View File

@@ -33,11 +33,13 @@ for ($i=1; $i<=4; ++$i)
if (!empty($ttype["data{$i}_name"])) if (!empty($ttype["data{$i}_name"]))
$rows[] = array($ttype["data{$i}_name"], $tender["data{$i}"]); $rows[] = array($ttype["data{$i}_name"], $tender["data{$i}"]);
if (!empty($tender['deposit_transaction_id'])) $rows[] = array('Deposit',
$rows[] = array('Deposit', $html->link('#'.$tender['deposit_transaction_id'], empty($tender['deposit_transaction_id'])
array('controller' => 'transactions', ? "-"
'action' => 'deposit_slip', : $html->link('#'.$tender['deposit_transaction_id'],
$tender['deposit_transaction_id']))); array('controller' => 'transactions',
'action' => 'deposit_slip',
$tender['deposit_transaction_id'])));
if (!empty($tender['nsf_transaction_id'])) if (!empty($tender['nsf_transaction_id']))
$rows[] = array('NSF', $html->link('#'.$tender['nsf_transaction_id'], $rows[] = array('NSF', $html->link('#'.$tender['nsf_transaction_id'],

View File

@@ -16,6 +16,14 @@ div#debug-kit-toolbar
{ display: none; } { display: none; }
/************************************************************
* Form inputs
*/
/* The "page N / M" input box... make it look like normal text */
input[type='button'], input[type='submit'], input[type='reset']
{ display: none; }
/************************************************************ /************************************************************
* Grid display * Grid display
*/ */

View File

@@ -67,7 +67,17 @@ function dump(element, limit, depth) {
if (props.length == 0) if (props.length == 0)
return ''; return '';
return pad + '<ol><li>' + props.join("</li>\n" + pad + pad1 + "<li>") + "</li>\n" + pad + "</ol>"; if (typeof dump.dumpid == 'undefined')
dump.dumpid = 0;
++dump.dumpid;
return (pad
+ '<A HREF="#" ONCLICK="$(\'#dumpid-'+dump.dumpid+'\').toggle(); return false;">(hide members)</A><BR>'
+ '<ol id="dumpid-'+dump.dumpid+'" STYLE="padding-top:0; margin-top:0;">'
+ '<li>'
+ props.join("</li>\n" + pad + pad1 + '<li id="dumpid-'+dump.dumpid+'">')
+ "</li>\n"
+ pad + "</ol>");
} }
function dump_window(element, limit) { function dump_window(element, limit) {
@@ -158,70 +168,103 @@ function datepicker(id) {
} }
} }
function datepickerGet(id) {
function datepickerNow(id, usetime) { if (id == null)
var now = new Date();
if ($("#"+id).datepicker != null) {
// datepicker seems to squash the time portion,
// so we have to pass in a copy of now instead.
$("#"+id).datepicker('setDate', new Date(now));
}
else {
$("#"+id).val(((now.getMonth()+1) < 10 ? '0' : '')
+ (now.getMonth()+1) + '/'
+ (now.getDate() < 10 ? '0' : '')
+ now.getDate() + '/'
+ now.getFullYear());
}
if (usetime == null)
usetime = true;
$("#"+id).val($("#"+id).val() +
(usetime
? (' '
+ (now.getHours() < 10 ? '0' : '')
+ now.getHours() + ':'
+ (now.getMinutes() < 10 ? '0' : '')
+ now.getMinutes())
: ''));
}
function datepickerSet(fromid, id, a, b) {
var dt;
if (fromid == null)
dt = new Date(); dt = new Date();
else { else {
if ($("#"+id).datepicker != null) if ($("#"+id).datepicker != null && $("#"+id).datepicker('getDate') != null)
dt = new Date($("#"+fromid).datepicker('getDate')); dt = new Date($("#"+id).datepicker('getDate'));
else else if ($("#"+id).val())
dt = new Date($("#"+fromid).val()); dt = new Date($("#"+id).val());
else
dt = null;
} }
if (a != null) return dt;
dt.setDate(a); }
if (b != null)
dt.setDate(b);
if ($("#"+id).datepicker != null) function datepickerStr(id) {
$("#"+id).datepicker('setDate', dt); return dateStr(datepickerGet(id));
}
function datepickerSet(id, dt_or_str, usetime) {
if ($("#"+id).datepicker != null && $("#"+id).datepicker('getDate') != null) {
// datepicker seems to squash the time portion,
// so we have to pass in a copy of dt instead.
$("#"+id).datepicker('setDate', new Date(dt_or_str));
if (usetime)
$("#"+id).val($("#"+id).val() + ' ' + timeStr(dt_or_str));
}
else { else {
$("#"+id).val(((dt.getMonth()+1) < 10 ? '0' : '') $("#"+id).val(dateStr(dt_or_str), usetime);
+ (dt.getMonth()+1) + '/'
+ (dt.getDate() < 10 ? '0' : '')
+ dt.getDate() + '/'
+ dt.getFullYear());
} }
} }
function datepickerBOM(fromid, id) { function datepickerNow(id, usetime) {
datepickerSet(fromid, id, 1); datepickerSet(id, new Date(), usetime == null ? true : usetime);
} }
function datepickerEOM(fromid, id) { function dateStr(dt_or_str, usetime) {
datepickerSet(fromid, id, 32, 0); var dt = new Date(dt_or_str);
return (((dt.getMonth()+1) < 10 ? '0' : '')
+ (dt.getMonth()+1) + '/'
+ (dt.getDate() < 10 ? '0' : '')
+ dt.getDate() + '/'
+ dt.getFullYear()
+ (usetime ? ' ' + timeStr(dt) : ''));
} }
function timeStr(dt_or_str) {
var dt = new Date(dt_or_str);
return ((dt.getHours() < 10 ? '0' : '')
+ dt.getHours() + ':'
+ (dt.getMinutes() < 10 ? '0' : '')
+ dt.getMinutes());
}
function dateAdd(dt_or_str, a, b, m, d) {
var dt = new Date(dt_or_str);
if (m != null) {
dt.setDate(1);
dt.setMonth(dt.getMonth() + m);
//$('#debug').append('set month ('+m+') ' + (dt.getMonth() + m) + '= ' + dt + '<BR>');
}
if (d != null) {
dt.setDate(dt.getDate() + d);
//$('#debug').append('set day ('+d+') ' + (dt.getDate() + d) + '= ' + dt + '<BR>');
}
if (a != null) {
dt.setDate(a);
//$('#debug').append('set date ('+a+') = ' + dt + '<BR>');
}
if (b != null) {
dt.setDate(b);
//$('#debug').append('set date ('+b+') = ' + dt + '<BR>');
}
return dt;
}
function dateYesterday(dt) { return dateAdd(dt,null,null,null,-1); }
function dateTomorrow(dt) { return dateAdd(dt,null,null,null,1); }
function dateBOM(dt) { return dateAdd(dt,1); }
function dateNextBOM(dt) { return dateAdd(dt,1,null,1); }
function dateEOM(dt) { return dateAdd(dt,32,0); }
function dateNextEOM(dt) { return dateAdd(dt,32,0,1); }
function datepickerBOM(fromid, id)
{ datepickerSet(id, dateBOM(datepickerGet(fromid))); }
function datepickerEOM(fromid, id)
{ datepickerSet(id, dateEOM(datepickerGet(fromid))); }
function datepickerNextBOM(fromid, id)
{ datepickerSet(id, dateNextBOM(datepickerGet(fromid))); }
function datepickerNextEOM(fromid, id)
{ datepickerSet(id, dateNextEOM(datepickerGet(fromid))); }
// REVISIT <AP>: 20090617 // REVISIT <AP>: 20090617
// I would rather use XML to pass from JS to PHP, but at the // I would rather use XML to pass from JS to PHP, but at the

View File

@@ -1,36 +1,20 @@
When performing a move-in, the receipt page is broken Change the summary text "Balance Owed" to "Customer Credit"
when trying to enter a concession. javascript complains about or something similar when there is a negative balance owed.
an invalid value, and the page is not submitted.
- Allegedly. I believe Shirley's browser was acting up
on her, and based on the logs, it seems that indeed
what ultimately worked just fine for a concession entry
was really the exact same page that was stuck. While
on the phone it was evident that here browser was
doing a javascript wig-out, and it wasn't related to
a slow internet connection.
Shrink the width of the detail view box so that the detail
and summary both fit on the same page on the Acer Netbook.
Remove Date from Ledger Entries on the Transaction page
(presuming that the Date is taken directly from the
Transaction and that all Ledger dates are all the same)
Add Deposit Slip # to the title bar when viewing deposit
Reversing a rent charge is not considered as part of the Reversing a rent charge is not considered as part of the
"charged-through" date on the lease. Consequently, the "charged-through" date on the lease. Consequently, the
reversal itself ensures the charge is fully "paid", and reversal itself ensures the charge is fully "paid", and
the "paid-through" date is also out of whack. the "paid-through" date is also out of whack.
Add invoice rent helpers
- monthly proration tool
- select from/to dates, and hit "prorate"
- charge through date
- enter charge through date, and the invoice
will automatically have charges for each month
from the current charge-through date to the
new charge-through date.
- charge N months
- enter number of months, and the invoice
will automatically have charges for each month
from the current charge-through date for N months
- next rent
- same as, or instead of, "charge N months", where
N is 1
Add NSF Fee to the NSF entry page (It's hardcoded right now Add NSF Fee to the NSF entry page (It's hardcoded right now
in Transaction to $35). in Transaction to $35).
@@ -48,13 +32,6 @@ be closed and no more charges are possible. The other option
would just be a checkbox to say "close lease (no more charges)", would just be a checkbox to say "close lease (no more charges)",
or let them clear it and have them close the lease manually. or let them clear it and have them close the lease manually.
Invoice
- Have some sort of rent-proration tool
- Have Rent automatically populate the Effective/Through
as well as rent (pro-rating if necessary). The dates
should take into account the customer charge through
date, as well as any other rents on the invoice.
Allow waiving a complete charge, even if it already has payments Allow waiving a complete charge, even if it already has payments
applied (at the moment, we just can waive the charge balance). applied (at the moment, we just can waive the charge balance).
@@ -221,3 +198,37 @@ Unit Size has no controller. Either remove the link from the
units grid, or implement the controller. units grid, or implement the controller.
When performing a move-in, the receipt page is broken
when trying to enter a concession. javascript complains about
an invalid value, and the page is not submitted.
- Allegedly. I believe Shirley's browser was acting up
on her, and based on the logs, it seems that indeed
what ultimately worked just fine for a concession entry
was really the exact same page that was stuck. While
on the phone it was evident that here browser was
doing a javascript wig-out, and it wasn't related to
a slow internet connection.
Add invoice rent helpers
- monthly proration tool
- select from/to dates, and hit "prorate"
- charge through date
- enter charge through date, and the invoice
will automatically have charges for each month
from the current charge-through date to the
new charge-through date.
- charge N months
- enter number of months, and the invoice
will automatically have charges for each month
from the current charge-through date for N months
- next rent
- same as, or instead of, "charge N months", where
N is 1
Invoice
- Have some sort of rent-proration tool
- Have Rent automatically populate the Effective/Through
as well as rent (pro-rating if necessary). The dates
should take into account the customer charge through
date, as well as any other rents on the invoice.