Compare commits

...

410 Commits

Author SHA1 Message Date
Abijah
bda18fc78a Changed field last_key to key_last
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1047 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-04 00:47:16 +00:00
Abijah
d903fcb9e3 Added bigger limit options to the customer list for receipts
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1046 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-04 00:30:49 +00:00
Abijah
01a6984a53 Added timestamp when the lock last had a keychange.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1045 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 15:54:35 +00:00
Abijah
30fdc10648 Changed quantity to not show up if just 1. Set field order for edit to match view
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1044 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 07:29:06 +00:00
Abijah
87d6d93493 Fixed bug causing crash if locks in use exceeds the number of locks that are supposed to exist
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1043 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 07:22:06 +00:00
Abijah
11a9ca903b Added ability to lock unlock any unit, and to track that based on the actual locks that are on it, not the lock status.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1042 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 07:08:29 +00:00
Abijah
0d59351341 Changed the lock screen to look a bit less clunky
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1041 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 06:44:57 +00:00
Abijah
13f62edbd7 Added ability to delete a lock
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1040 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 06:33:56 +00:00
Abijah
ec0363325c Added more lock functionality, and fixed a couple bugs
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1039 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 06:04:00 +00:00
Abijah
e08afdd8b1 First pass at implementing a new lock tracking mechnism. Not complete, but the basics seem to work
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1038 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 03:25:29 +00:00
Abijah
8249ecc5cd Fixed defect found from visual inspection
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1037 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-03 03:05:03 +00:00
Abijah
f50db1a34b Added ability to get a customer's running balance. It's quite flaky, doesn't tolerate having a grid with sub-pages, is actually incorrect for at least some customers (not sure why), but it helps answer a fundamental question for most customers. If I had a better solution, I would surely go for it.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1036 97e9348a-65ac-dc4b-aefc-98561f571b83
2014-03-02 18:26:01 +00:00
Abijah
f85481c7ec Removed the Quickbooks Invoice/Credits, since I created a line item in quickbooks for the credits and enter the whole thing in one shot.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1035 97e9348a-65ac-dc4b-aefc-98561f571b83
2013-12-05 21:30:24 +00:00
Abijah
75c635a5ea Added customer ID to customer grid
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1034 97e9348a-65ac-dc4b-aefc-98561f571b83
2013-12-05 02:09:40 +00:00
Abijah
4cc81c2ebc Added ability to re-open a lease
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1033 97e9348a-65ac-dc4b-aefc-98561f571b83
2013-12-05 02:00:51 +00:00
Abijah
20df22a002 Changed sort order on the deposit slip, since date received is not useful to a bank teller.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1032 97e9348a-65ac-dc4b-aefc-98561f571b83
2013-12-05 01:36:44 +00:00
Abijah
49a379d799 Changed column widths, spurred by the deposit slips not showing the item numbers fully, while giving too much room to Type
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1031 97e9348a-65ac-dc4b-aefc-98561f571b83
2013-12-05 01:31:25 +00:00
Abijah
98d9849914 Merge in the hosted_migration_20130215 branch to the v0.3_work branch
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1030 97e9348a-65ac-dc4b-aefc-98561f571b83
2013-12-05 01:24:21 +00:00
abijah
20284046c3 Fixed bug charging customers again when there is not charge through date.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1019 97e9348a-65ac-dc4b-aefc-98561f571b83
2012-11-17 18:20:48 +00:00
abijah
99a98cbc7d Added some minor view tweaks
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1018 97e9348a-65ac-dc4b-aefc-98561f571b83
2012-11-17 18:18:36 +00:00
abijah
fc9226594c Added customer link on the receipts page
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1017 97e9348a-65ac-dc4b-aefc-98561f571b83
2012-08-07 00:14:54 +00:00
abijah
352bdbbf49 Fixed non-backward compatible jqGrid issue caused during upgrade from 3.8.x to 4.0.0 (grid.postext.js module is no longer supported and is now a plugin)
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1016 97e9348a-65ac-dc4b-aefc-98561f571b83
2012-08-07 00:11:03 +00:00
abijah
11fbdf0701 Upgraded to jqGrid 4.4.0
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1015 97e9348a-65ac-dc4b-aefc-98561f571b83
2012-08-06 17:57:49 +00:00
abijah
2519f4c8a7 Added support for account name and number on the deposit slips
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1014 97e9348a-65ac-dc4b-aefc-98561f571b83
2012-08-06 17:33:21 +00:00
abijah
b6ed57c02c Checking in changes from some time ago, changing the reports screen to give direct Quickbooks invoice and credits info.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1013 97e9348a-65ac-dc4b-aefc-98561f571b83
2012-06-14 01:32:44 +00:00
abijah
4dffa540a0 Fixed a long standing bug preventing proper display of the customer-contact relationship fields.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1010 97e9348a-65ac-dc4b-aefc-98561f571b83
2011-05-11 19:19:08 +00:00
abijah
3d1c4d2492 Added income / expense reports that produce results suitable for entry into quickbooks as per the current paradigm
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1009 97e9348a-65ac-dc4b-aefc-98561f571b83
2011-03-30 16:57:28 +00:00
abijah
c4f6f76edb Fixed a bug with 2 digit years
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1003 97e9348a-65ac-dc4b-aefc-98561f571b83
2011-01-08 01:26:04 +00:00
abijah
d95045cb15 Modified the grid search to support standard date formats, with a bit of a kludge by applying it to fields that end with _date or stamp.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1002 97e9348a-65ac-dc4b-aefc-98561f571b83
2011-01-08 00:56:15 +00:00
abijah
0c95431128 Changed lease status to LATE after the customer is actually late, instead of when late charges start to apply.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1001 97e9348a-65ac-dc4b-aefc-98561f571b83
2011-01-08 00:53:40 +00:00
abijah
c76ba261d8 Fixed a bug with customer merge. Common contacts were being deleted when selected as a source contact to keep.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@1000 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-12 21:48:42 +00:00
abijah
954f0d7968 Removed the debug aid of sub-totaling statement entries. I'll add the right solution someday...
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@998 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 22:19:55 +00:00
abijah
920dba3a4d Modified a couple reports to have url control over the period
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@997 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 22:05:24 +00:00
abijah
fff2e84fb1 Updated to include total leases / past leases
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@996 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 21:43:34 +00:00
abijah
11aacd5803 Modified customer merge functionality to leave everything from the destination customer in-tact, and simply add on contacts from the source customer, if requested. This simplifies things significantly, and also the paradigm shift of starting the operation from the destination customer allows us to merge multiple customers into one with ease (no need to dig around for each source customer before clicking merge)
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@995 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 20:52:00 +00:00
abijah
34844760e8 Added the front end code to perform a customer merge. Seems to work, although I don't fully trust it yet. Now that implementation is done, I realize I don't care for the interface. Really, the destination customer should keep its primary contact and all other contacts. The user should only be given the choice of adding zero to all contacts from the source customer. A change in primary contact could always be handled after the merge.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@994 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 19:36:39 +00:00
abijah
b1113e826f First pass at a customer merge function. Preliminary tests seem to be successful.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@993 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 16:29:06 +00:00
abijah
112a128492 Minor change to the display and sort order of unit sizes
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@992 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 13:38:38 +00:00
abijah
d96145530c Minor update to support the 'IN' search type, avoid wrapping floating point in CDATA, and to support the grid request for multiple pages.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@991 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-07-02 13:27:35 +00:00
abijah
a602fce3ab Added override function for counting the results. This is needed because the 'Unpaid Charges' report was returning a crazy large number of entries. Although I know this quick and dirty hack works for that report, I haven't checked or tested to see if this might cause issues in other areas.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@985 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-04-14 04:24:13 +00:00
abijah
6849c2caae Added possible fix for this problem with sandbox/devbox themes that use a font size so large, it creates usability issues.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@984 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-04-14 03:34:01 +00:00
abijah
b83c870eed Merge in bugfix from v0.2_work
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@982 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-04-02 13:08:41 +00:00
abijah
11b54588ff Changed the invoice page to redirect back to the customer view, which is typically more of interest than the lease view
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@980 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-04-02 12:24:34 +00:00
abijah
214aa4d348 Yet another bug from haste... let's hope this one fixes it.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@979 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-31 20:10:21 +00:00
abijah
f281295084 Fixed copy/paste bug introduced at the last minute on the prior checkin.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@978 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-31 20:07:29 +00:00
abijah
68cbca5e28 Added outstanding charges and outstanding credits to the customer page, and reorded fields in order of presumed importance. Removed items from Unit/Lease which really shouldn't have been there. They were added for convenience, but the redundancy was confusing. Added a couple report links to make it easy to see outstanding charges and collected rents.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@977 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-31 19:49:56 +00:00
abijah
4892143c0c On move-out, redirecting back to the customer instead of the closed lease
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@976 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-31 19:45:45 +00:00
abijah
1be8df7a75 Fixed a sorting issue (depending on point of view). When sorting by date, or effective date, I find it useful to have the next order of sort be entry ID, so they can be viewed in the order actually entered. Ideally, we'll get to a 4 date system: charge-from date, charge-to date, effective date (whatever date the user feels is the right date for the transaction), and _actual_ date, which is the true and correct entry date/time and _not_ user settable. The names of each may need to be different, but that's where we need to head, in which case, we would sort on actual date instead of entry-id.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@975 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-30 16:02:43 +00:00
abijah
285c682b1e Added ability to see the customer when listing transactions
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@974 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-30 15:57:54 +00:00
abijah
3acdec1458 Merge in from v0.2.3, a housekeeping release
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@970 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 04:38:59 +00:00
abijah
e0b41ca4f7 Trivial release for housekeeping only
git-svn-id: file:///svn-source/pmgr/tags/v0.2.3@968 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 04:27:12 +00:00
abijah
780c614c78 Brought all notes to a top level directory, and got rid of the VSS database sql file. It has moved to its own repository: /svn/vss
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@967 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 04:24:38 +00:00
abijah
f49a23b2fd Brought all notes to a top level directory, and got rid of the VSS database sql file. It has moved to its own repository: /svn/vss
git-svn-id: file:///svn-source/pmgr/branches/v0.2_work@967 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 04:24:38 +00:00
abijah
07461f4419 Merge in v0.2.2 fixes
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@966 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 04:05:00 +00:00
abijah
48631cffee Fixed a bug that was causing some lease charge_through_date fields to be NULL, which in turn caused additional charges to be added in error when assessing charges. The problem was that we were looking for statement entry charges that were not followed by other statement entries the next month. The intention was to locate rent charges that were not matched by a rent charge the following month, but we were looking for any type of statement entry. The presently visible problem was with a disbursement the next month on Lease #21, leaving NO last charge, not even just the wrong date. However, the issue could even be as simple as a Cleaning charge the next month, so we now filter not only for charges, but rent charges.
git-svn-id: file:///svn-source/pmgr/branches/v0.2_work@963 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 03:48:03 +00:00
abijah
68e6dc2d20 Fixed the monthly charges report to only reflect income accounts (not things like security deposits). Also, by restricting to charges, the report was neglecting things like reversals, leaving the totals skewed. Thefore, the 'CHARGES' restriction was removed and replaced with the much more appropriate chargeDisbursementFields() function, which dumps fields that tabulate correctly.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@962 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 02:21:57 +00:00
abijah
2f2a4642fb Changed the monthly charge report to limit itself to 11 months (plus the current month), and to sort in reverse order, keeping the most relevant month at the top.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@961 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 02:02:42 +00:00
abijah
2602a6fa7c Added a lease up report
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@960 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 01:51:32 +00:00
abijah
2489b67542 Forgot to add the report views for the last two checkins :-/
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@959 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 01:31:05 +00:00
abijah
821ffc4726 Added Monthly Charges report. Also, added a new area to the menu specifically for reports.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@958 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-12 00:38:34 +00:00
abijah
7770f13bf3 Added a Unit overview action. It's a bit quick and dirty, but it's intended for admins only.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@957 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-11 23:40:47 +00:00
abijah
0a594bb5a9 Merge in db changes from the v0.2.0 release
git-svn-id: file:///svn-source/pmgr/branches/v0.2_work@947 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 18:44:56 +00:00
abijah
b3d43d754b Fixed a bug with customer lease counts after editing the customer.
git-svn-id: file:///svn-source/pmgr/branches/v0.2_work@946 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 18:35:09 +00:00
abijah
a47d5d54b4 Fixed bug which was kicking us out of the dev/sandbox when editing a customer. Actually, seems like more of a workaround for a CakePHP bug, but it's not certain.
git-svn-id: file:///svn-source/pmgr/branches/v0.2_work@945 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 18:05:37 +00:00
abijah
b6e2b781ef Renamed the work branch, since it will be used for bugfix revs as well.
git-svn-id: file:///svn-source/pmgr/branches/v0.3_work@944 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 18:04:47 +00:00
abijah
8f5c3031fc Renamed the work branch, since it will be used for bugfix revs as well.
git-svn-id: file:///svn-source/pmgr/branches/v0.2_work@943 97e9348a-65ac-dc4b-aefc-98561f571b83
2010-03-02 18:03:11 +00:00
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
03da3afb98 More things to do based on how it's been going at VSS
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@873 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-09 23:46:18 +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
cron
3b5aa78a47 property_manager database backup as of 2009_10_09_0113
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@869 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-09 08:13:46 +00:00
cron
721faa129b property_manager database backup as of 2009_10_08_0117
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@868 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-08 08:18:30 +00:00
cron
78806de606 property_manager database backup as of 2009_10_06_0124
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@867 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-06 08:24:25 +00:00
cron
d4ea5eea1f property_manager database backup as of 2009_10_03_0123
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@866 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-03 08:24:03 +00:00
cron
9213c1c21d property_manager database backup as of 2009_10_02_0905
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@865 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-02 16:06:14 +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
abijah
8bda7c2cb0 Added the updateLeaseCount call to the customer update function. Most of the time it will not be necessary, but the purpose of update() is to ensure the customer info is current, so we're obligated to call it.
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@863 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-02 15:40:54 +00:00
cron
375d63485c property_manager database backup as of 2009_10_02_0116
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@862 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-02 08:16:34 +00:00
cron
26045a3db7 property_manager database backup as of 2009_10_01_0103
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@861 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-10-01 08:03:28 +00:00
cron
04ac012754 property_manager database backup as of 2009_09_29_0120
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@860 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-29 08:20:23 +00:00
cron
e6f662f0a1 property_manager database backup as of 2009_09_26_0113
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@859 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-26 08:13:58 +00:00
cron
04b3c06cda property_manager database backup as of 2009_09_25_0129
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@858 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-25 08:30:15 +00:00
cron
24da6d75b5 property_manager database backup as of 2009_09_24_0120
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@857 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-24 08:20:57 +00:00
cron
542ae17afd property_manager database backup as of 2009_09_23_0114
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@856 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-23 08:14:54 +00:00
cron
97fffaa610 property_manager database backup as of 2009_09_20_0118
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@855 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-20 08:18:46 +00:00
cron
3eb5139b62 property_manager database backup as of 2009_09_19_0125
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@854 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-19 08:26:07 +00:00
cron
5245393a04 property_manager database backup as of 2009_09_18_0104
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@853 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-18 08:04:33 +00:00
cron
e59df1dffb property_manager database backup as of 2009_09_16_0122
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@852 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-16 08:23:11 +00:00
cron
61da97974b property_manager database backup as of 2009_09_15_0112
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@851 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 08:12:24 +00:00
cron
6482cfd4cc property_manager database backup as of 2009_09_14_1953
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@850 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 02:53:36 +00:00
abijah
c3e51a7a6b Tagging first official release: v0.1.0
git-svn-id: file:///svn-source/pmgr/tags/v0.1.0@849 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 02:47:55 +00:00
abijah
de069ef186 Updated the todo items
git-svn-id: file:///svn-source/pmgr/trunk@848 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 02:42:32 +00:00
abijah
5047abba6a Merge in from pre_0.1 branch
git-svn-id: file:///svn-source/pmgr/trunk@847 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 02:38:28 +00:00
abijah
4e8426fd79 Move the Charge Assessment link to the operations area, and updated the Transaction Destroy link to the admin menu and gave it a reasonable redirect instead of the view not found message (since it's no longer a dev function
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@846 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 02:32:56 +00:00
abijah
6630cdfcd6 Part of the final effort to bring the information current, ready to be live.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@845 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 02:30:20 +00:00
abijah
48d332f40f Part of the final effort to bring the information current, ready to be live.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@844 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-15 02:30:05 +00:00
abijah
3ede96dad9 Fixed the map titles on IE.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@843 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-14 17:03:56 +00:00
abijah
3e3dff31a8 I believe the bug Shirley has been seeing is finally fixed. The problem is that an extra comma at the end of a javascript object literal blows up in IE7. FF and IE8 both handle it fine, which is why we hadn't noticed. Hopefully, this change includes all areas which had the extra comma.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@842 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-07 17:04:34 +00:00
abijah
3642724b5e ajax logging is not working on site. The log message is now added as part of the post. However, it is added by using jQuery, so it may not work. Consequently, there is a default value to help narrow down the problem.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@841 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-07 05:30:08 +00:00
abijah
0ad68f4d6a Added util function to allow us to capture client side logging, and utilize it in the invoice view to find out why the app is not working on site. Also, since everything depends so heavily on jQuery, added an internal error if jQuery fails to load.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@840 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-06 15:32:41 +00:00
abijah
2628edfbdd Merge in single site support for both the sandbox and a development box as well.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@839 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-06 04:32:55 +00:00
abijah
740bcbedc0 Integrated sandbox functionality directly into the application so that there is no need for two independent applications for both the normal and sandbox version.
git-svn-id: file:///svn-source/pmgr/branches/single_site_sandbox_20090905@838 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-06 04:28:29 +00:00
abijah
2f3046294d Missed the transaction controller change as part of r835. Also, added check to see that customer/unit have been selected at movein.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@837 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-06 04:25:27 +00:00
abijah
7a2034aea0 D:\bin\svnbranch.pl: Branch from /branches/pre_0.1_work_20090819 to /branches/single_site_sandbox_20090905
git-svn-id: file:///svn-source/pmgr/branches/single_site_sandbox_20090905@836 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-06 04:16:52 +00:00
abijah
bb4046e1da Changes to allow invoices and receipts to work without ajax, since it may be the ajaxForm that is creating problems for Shirley on-site. Added debug prints to the invoice page as well, to get feedback on what exactly is breaking.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@835 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-05 15:15:24 +00:00
abijah
f717713842 Moved out Cathy Conway
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@834 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-03 18:20:51 +00:00
abijah
5008452089 Added separation to request logging
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@833 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-01 04:48:38 +00:00
abijah
68a1397ad6 Added request log mechanism
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@832 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-09-01 04:43:24 +00:00
abijah
ef64644536 Added move in/out selection verification before submit
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@831 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-31 15:10:45 +00:00
abijah
72ea84ad88 Modified the internal error to capture to the log.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@830 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-31 14:43:03 +00:00
abijah
0f3aa42f57 Last tweak for now to size reduction.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@829 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-30 15:28:13 +00:00
abijah
fb23b7ffaa Another minor tweak, so the formatter functions don't fall directly into the first grid area (but just above).
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@828 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-30 15:23:12 +00:00
abijah
b731ee6165 Reduced the amount of data sent to the client.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@827 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-30 15:19:39 +00:00
abijah
34dcbd8b43 Made all grids the same width, which is much more pleasing than when they were variable. This width is a bit too large for 800x600, but has been tested at 1024x768 with no problem. It works great on the Acer netbook.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@826 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 21:29:23 +00:00
abijah
87a2ea5cd6 Decided the Creation menu isn't worth it at the moment, and moved New Deposit back into the Actions menu. Removed Add Customer, since this can and probably will happen directly from the Move-In page. Created an entirely separate Sandbox menu area, since it is of particular interest to the customer.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@825 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 20:59:29 +00:00
abijah
6492cd8b22 Removed the Add Deposit link from the actions menu. It is easy to find after Navigating to Deposits.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@824 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 20:46:33 +00:00
abijah
f6a18cbb6c Thought margin would be picked up from the previous ui-jqgrid-title rules, but apparently not.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@823 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 20:31:44 +00:00
abijah
7198d7e6f4 Changes to have the software function without the presence of jquery-ui (which may not be complete). Also, brought the jquery libraries to the server, instead of using them as hosted from google. Some browser configurations may have an issue with what they deem to be cross site scripting.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@822 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 20:27:12 +00:00
abijah
d79077e279 Removed the debug prints, and got back to the original r5 of hoverintent, except for my change to handle mouseenter and mouseleave
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@821 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 18:43:48 +00:00
abijah
cea9332ac6 Using version r5 of hoverIntent. It doesn't work as an event like the original code did, so I had to doctor it up a bit. It works OK with firefox, but not with IE. I have a possible patch to apply after I check this in.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@820 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 18:14:18 +00:00
abijah
bf8aaea041 Modified the dump function, and fixed several places that needed to declare variables using var. Changed the pmgr.jquery.js file to jquery.hoverIntent.js. Fixed a bug causing no ordered lists, since padding and margin were set to 0 for all elements.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@819 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-29 17:24:06 +00:00
abijah
63704682fa Keeping actions for now
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@818 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 22:19:07 +00:00
abijah
63de5641a0 Temporary fix for last minute bug
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@817 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 22:11:18 +00:00
abijah
5f6a9ed53f Fixed the http/https problem
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@816 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 21:44:39 +00:00
abijah
328d0f8f51 Modified the rebuild_sandbox action to redirect instead of dumping debug output.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@815 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 21:38:23 +00:00
abijah
aee6832374 Fixed the sandbox/unsandbox URLs. I'd like to make this a route... I'll look into it.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@814 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 21:22:50 +00:00
abijah
63e22ec9bf Added more sandbox functionality, including a script to generate the sandbox on the fly from the absolute latest data.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@813 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 21:06:20 +00:00
abijah
fde8923814 Added a utility controller, for calling actions that really aren't related to any other controller (we've been using accounts up to this point).
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@809 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 20:46:10 +00:00
abijah
696017a82a Fixed cut/paste bug
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@808 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 20:45:11 +00:00
abijah
7bcee943a5 Theme work, and a sandbox function for a consistent point to check whether we're sandboxed or not.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@807 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 19:57:30 +00:00
abijah
0c9b945f7b Added pre-submit data verification for invoice and receipt. The checking is pretty thin, but it's a start. I don't want to do more, as I'm sure there are lots of data validation tools out there and would prefer to go that route.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@806 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 18:22:13 +00:00
abijah
5b5707df5e Fixed a bug with deposit, which prevented update to the deposited tenders. Added INTERNAL_ERROR when an error occurs. Since the module and callers make no effort to roll back changes when an error occurs, it's probably best to just halt. We may need to remove some of these checks, especially in the verifyTransaction function, which is intended to catch errors before they create a problem in the database.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@805 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 16:41:17 +00:00
abijah
c21cdcd9a2 Added server request vars, mostly to include the referer. Added timestamps and tweaked formatting slightly.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@804 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 16:34:01 +00:00
abijah
a79adbce2d Moved the creation actions into the CONTROLLER menu. Minor cleanup of deposit_slip. Minor tweaking to views.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@803 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 16:32:21 +00:00
abijah
a3b376544c Replaced the hardcoded 'level' checks, and incorporated (as a first pass) the new permission mechanism
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@802 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 07:11:14 +00:00
abijah
43c957baa2 Added users and groups and a couple basic options (dev & admin) for testing. Since dev/admin is now a database option, the special routing mechanism has been removed.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@801 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 04:47:33 +00:00
abijah
a66024c889 Fixed the build script; updated users schema to no longer hold password information and to not require contact information; added a set of users and groups for VSS
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@800 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 04:25:53 +00:00
abijah
aed090fbe2 Added rollup sql code to bring the current database up to speed with the option / permission changes.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@799 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 04:03:19 +00:00
abijah
7904372dff Added support for permissions. Next is to implement some.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@798 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 03:32:07 +00:00
abijah
1d4dcbd2b0 Made changes to the database and added models to support options. Next is permissions
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@797 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-28 01:42:29 +00:00
abijah
f5f09421c1 Changed submenu ordering
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@795 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-27 17:27:07 +00:00
abijah
4d525f6ac9 Moved the list of account types into the admin area
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@793 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 20:21:59 +00:00
abijah
0b773cfc35 Removed the Balance column from vacant and unavailable grids, since they should always be zero.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@792 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 20:16:11 +00:00
abijah
387e08da06 Changed the default sort order for Transaction to be DESC, like with StatementEntry and LedgerEntry
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@791 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 20:15:28 +00:00
abijah
5ef877f64b Removed the legacy (and unused) field current_lease_id from the units table
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@790 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 20:08:19 +00:00
abijah
c889e4f4e1 Changed the default Leases view to be current leases instead of all
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@789 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 20:04:39 +00:00
abijah
b938b5f028 The previous checkin was _supposed_ to be just the jqGrid.ctp file, but an accidental keystroke checked in the work that was intended for this checkin. This would have been the addition of unit counts, as well as occupancy and vacancy, to the unit_sizes grid. Since that has already been checked in, this is just the cleanup.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@788 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 19:58:46 +00:00
abijah
1e34cc1de8 Added a percentage formatting type to jqGrid.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@787 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 19:51:06 +00:00
abijah
80fe5ca4de Added changes to allow for being hosted on a secure server, as well as a sandboxed version.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@786 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 18:55:41 +00:00
abijah
fbd716634a Added password protection for any access other than localhost or local subnet. I'll remove the domain checks at some point, as we always want an authenticated user for at least determining user settings, if nothing else.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@785 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-26 18:18:31 +00:00
abijah
046cf5fe63 Added the ability to list unit sizes appropriate for a specific need. Since some of the code was taken from Account, I tidied up that model just a bit as well.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@784 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 17:07:28 +00:00
abijah
2fd2dc603c Modified the unit types to have boolean flags to indicate their properties
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@783 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 16:26:28 +00:00
abijah
439e9a3de6 Implemented the UnitSize controller and view. I would like to add controller navigation links for 1bd, 2bd, 3bd, and so on. Also, we need to make the number of available units part of the grid. It will require breaking a separate CountTables function, since we'll need to join with Units, but it shouldn't be a big deal. Whether or not we include occupancy percentage, or leave that to a report is undecided.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@782 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 15:56:42 +00:00
abijah
caee1c90a1 Removed the unecessary code, now that it has been checked in.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@781 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 06:26:53 +00:00
abijah
08486fc101 Work to try and ensure that the most useful menu is shown by default on each page.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@780 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 06:25:37 +00:00
abijah
0758865aae Changed to ensure that the grid view menu items do not show up at all, unless the user is an admin
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@779 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 06:24:27 +00:00
abijah
85b189a50e Updated status of a few units.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@778 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 06:18:27 +00:00
abijah
3ff5967415 Moved all controllers to the new addGridViewSideMenuLinks virtual function.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@777 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 02:37:01 +00:00
abijah
b2a85a5197 Added lock/unlock links directly on the unit page. Also, found the grid view links seem to be needed even when not already navigating a grid. Without them, the user must go first through the top level navigation link, then to the specific grid subset. It's a bit painful, and so I decided to add them back in. To facilitate this, instead of repeatedly changing each controller whenever we change our minds, I added a new virtual function to that app. I'll change the remaining controllers on the next checkin.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@776 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 02:29:29 +00:00
abijah
f8cdea8872 Renamed the Operations menu area to Actions
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@775 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 01:26:52 +00:00
abijah
c3ad1b0ea1 Fixed problems with the sizing of the sidemenu, as well as the animation problem (an issue caused by the lack of clear parent container sizing, since the parent was just a table cell). This is actually much cleaner, allowing us to ignore #sidecolumn in the sidemenu.css file, and simplifies jQuery accordion work as well (thus no jitter). Added a mechanism to dump javascript in a consistent place, when generated from elements included by the layout (namely, our sidemenu element). Finally, added a new event called hoverintent, since the mouseover feature works very poorly with the accordion module when animation is in use.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@774 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 01:24:23 +00:00
abijah
56bec8d05c Fixed a problem where the operations menu was showing up at inappropriate times (a problem we already solved, but accidentally left commented out on an earlier checkin). Also, since the sitemap is a top level operation that is not based on gridView, enabled the site operations menu explicitly from within the maps controller.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@773 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 01:18:53 +00:00
abijah
b89750a4ef Moved Edit as the final menu item of each set, when present.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@772 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 01:14:34 +00:00
abijah
20309fba39 Modified move_out to present a grid of leases, so the user can make a selection just as with move-in, invoices, receipts, etc.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@771 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 01:09:47 +00:00
abijah
241028603b Changed the default grid size for ledger_entries
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@770 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-25 01:06:57 +00:00
abijah
8663c25806 Added some lease operations to the customer menu. If there is only one current lease, this works great, and if there are multiple, it works as if it were performed from the top level, ignoring the fact that the user clicked the operation from the customer page.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@769 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 21:49:40 +00:00
abijah
03d947a069 Added top level operations into the sidemenu
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@768 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 21:48:09 +00:00
abijah
294aabbb29 Removed the lease/customer link from invoice/receipt
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@767 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 20:25:09 +00:00
abijah
94188e3f92 Fixed bug caused by removal of the ID column from the grid.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@766 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 20:12:20 +00:00
abijah
c261735197 Added automated disabling of admin and development menu items (at least the ones that are explicitly added to those sections of the menu).
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@765 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 20:03:05 +00:00
abijah
63c95da9f3 Changed the cookie name from the default of CAKEPHP.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@764 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 19:38:30 +00:00
abijah
ae1dccfb14 Updated help messages to reflect the requirements around first/last/company_name and display_name. Actually, the messages don't make any mention of company_name, but it can be used for display_name as well.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@763 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 19:37:19 +00:00
abijah
9bc699bf51 Modified contact grids to use display_name, and the contact model to take company name into account if no other fields will work for display name.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@762 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 19:17:55 +00:00
abijah
7a1aa536fa Modified display_name to be required, and gave a display name to a couple anonymous contacts.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@761 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 18:49:15 +00:00
abijah
de9a4acd5d Added ability to create a new customer directly from the move in operation.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@760 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 18:44:30 +00:00
abijah
bd4610abb3 Added unit area to the grid display; removed the hyperlink to unit size (which is not yet implemented), and added an overlocked report.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@759 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 08:20:28 +00:00
abijah
60ec105fca Removed old experimental code
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@758 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 08:01:00 +00:00
abijah
67a0c07bc6 Marked off some completed todo items.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@757 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 07:57:37 +00:00
abijah
fc332bef0e Changed wording slightly to fit on one line.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@756 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 07:44:03 +00:00
abijah
92668bcca1 Removed all the test data for Abijah as a contact.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@755 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 07:43:36 +00:00
abijah
73eeba04fe As with last checkin for customer, we now have special coloration for required fields, as well as blank required fields.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@754 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-24 06:53:51 +00:00
abijah
a1bab966ed Added descriptive text to the customer entry page, as well as work to associate labels with the inputs and set their class dynamically, to flag missing required fields.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@753 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 23:12:04 +00:00
abijah
ee9ff354b2 Added functionality to pre-activate a specific area/subarea of the menu.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@752 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 20:23:44 +00:00
abijah
a9410b1351 Moved 'New Deposit' to the correct menu section
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@751 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 20:23:13 +00:00
abijah
5ad28c809b Fixed the relationship field for customer and contact grids.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@750 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 19:23:49 +00:00
abijah
89d7f22e4a Small tweak to prevent the render error when looking at a debug grid query.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@749 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 19:23:12 +00:00
abijah
11be0ff9cb Modified the menu to use the accordion widget, which is slick and allows it to match the current theme.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@745 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 18:30:17 +00:00
abijah
65c3f28484 Removed the sitelink script, which is of no use since the database now contains additional data. Modified the build script to rebuild the database from the last saved data set.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@743 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 14:39:15 +00:00
abijah
4e1ffd14b4 Fixed the links and sorting for the contacts grid
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@741 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 04:16:43 +00:00
abijah
2d3b962fe1 Removing, or at least phasing out the ledger name field. Account name is always needed and nearby, so ledger name is just confusing.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@740 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 01:08:30 +00:00
abijah
1d921358a8 Changed statement/ledger entries to defaultly sort by date in descending order. For small lists, ascending order is more logical, but for larger lists, this buries the most relevant items at the very back.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@739 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 01:02:28 +00:00
abijah
9a819c72a8 Tidied up where we show transaction ids vs. statement/ledger entry ids
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@738 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 00:54:22 +00:00
abijah
24e208bf17 More cleanup to hide ID from the user except where ID is intended to be the externally visible identification method (like transactions and ledger/statement entries).
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@737 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 00:38:18 +00:00
abijah
86b0c14eda Eliminated the ID field from the grids, wherever feasible.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@736 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 00:16:04 +00:00
abijah
da88975fed More work on tidying up the menu items for usability.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@735 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-23 00:02:53 +00:00
abijah
f545502162 Changed how sidemenu links work, so that order of execution doesn't have to control ordering of the list.
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@734 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-22 22:47:41 +00:00
abijah
513182a6d5 Trunk is now very close to our initial v0.1 offering. Branching to add some final changes before releasing
git-svn-id: file:///svn-source/pmgr/branches/pre_0.1_work_20090819@733 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-20 04:08:06 +00:00
abijah
7b76fd8f0a Pseudo merge-in, which is a wholesale copy from the branch directly to trunk. This is fine since trunk has always been empty up to this point.
git-svn-id: file:///svn-source/pmgr/trunk@732 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 21:09:19 +00:00
abijah
63bb788fdf Apparently these directories were not branched, just created separately on trunk and branch. trunk was entirely empty anyway, so its no problem to just obliterate these.
git-svn-id: file:///svn-source/pmgr/trunk@730 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:56:52 +00:00
abijah
d8760cf2b6 Updated property_manager.sql with property_manager_2009_08_19_1330.sql
Created:  Wed Aug 19 13:43:16 2009
	Modified: Wed Aug 19 13:30:11 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@729 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:54 +00:00
abijah
feb15cac49 Updated property_manager.sql with property_manager_2009_08_19_1326.sql
Created:  Wed Aug 19 13:43:16 2009
	Modified: Wed Aug 19 13:26:45 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@728 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:51 +00:00
abijah
40047d89d8 Updated property_manager.sql with property_manager_2009_08_19_1253.sql
Created:  Wed Aug 19 13:43:16 2009
	Modified: Wed Aug 19 12:53:49 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@727 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:48 +00:00
abijah
94cc553723 Updated property_manager.sql with property_manager_2009_08_19_1250.sql
Created:  Wed Aug 19 13:43:16 2009
	Modified: Wed Aug 19 12:50:23 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@726 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:45 +00:00
abijah
166a4f44d9 Updated property_manager.sql with property_manager_2009_08_19_1232_removed_orphaned_double_entries.sql
Created:  Wed Aug 19 13:43:16 2009
	Modified: Wed Aug 19 12:32:25 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@725 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:42 +00:00
abijah
633a019fc5 Updated property_manager.sql with property_manager_2009_08_18_0037_most_stable_as_of_200908180943.needs_check_fix.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Tue Aug 18 00:37:50 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@724 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:39 +00:00
abijah
bddcca8d9e Updated property_manager.sql with property_manager_2009_08_17_2245.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 22:45:57 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@723 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:36 +00:00
abijah
6e6f7f4f43 Updated property_manager.sql with property_manager_2009_08_17_2229.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 22:29:09 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@722 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:33 +00:00
abijah
64ce95e404 Updated property_manager.sql with property_manager_2009_08_17_2220.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 22:20:46 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@721 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:30 +00:00
abijah
55bcdca935 Updated property_manager.sql with property_manager_2009_08_17_2200.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 22:00:22 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@720 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:27 +00:00
abijah
6f035c2052 Updated property_manager.sql with property_manager_2009_08_17_2152.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 21:52:25 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@719 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:23 +00:00
abijah
538c8077d2 Updated property_manager.sql with property_manager_2009_08_17_2131.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 21:31:55 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@718 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:20 +00:00
abijah
e37e40f355 Updated property_manager.sql with property_manager_2009_08_17_2100.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 21:00:55 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@717 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:17 +00:00
abijah
9fca2e7d4f Updated property_manager.sql with property_manager_2009_08_17_2042.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 20:42:08 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@716 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:14 +00:00
abijah
5c7df5f2eb Updated property_manager.sql with property_manager_2009_08_17_2036.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 20:36:42 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@715 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:11 +00:00
abijah
e0e7fcfc51 Updated property_manager.sql with property_manager_2009_08_17_1921.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 19:21:47 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@714 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:08 +00:00
abijah
8ce654d22d Updated property_manager.sql with property_manager_2009_08_17_1917.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 19:17:59 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@713 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:05 +00:00
abijah
6cd45236d9 Updated property_manager.sql with property_manager_2009_08_17_1847.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 18:47:43 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@712 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:49:02 +00:00
abijah
009503bf7b Updated property_manager.sql with property_manager_2009_08_17_1844.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 18:44:58 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@711 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:59 +00:00
abijah
4f652eb9a1 Updated property_manager.sql with property_manager_2009_08_17_1815.sql
Created:  Wed Aug 19 13:43:07 2009
	Modified: Mon Aug 17 18:15:21 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@710 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:56 +00:00
abijah
0b9061794e Updated property_manager.sql with property_manager_2009_08_17_1648.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 16:48:02 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@709 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:53 +00:00
abijah
1055a00476 Updated property_manager.sql with property_manager_2009_08_17_1646_auto_deposit_ach.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 16:46:13 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@708 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:50 +00:00
abijah
4f758b5480 Updated property_manager.sql with property_manager_2009_08_17_1536_deposit_ledger_entry_id.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 15:36:28 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@707 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:47 +00:00
abijah
ec2ea2a60e Updated property_manager.sql with property_manager_2009_08_17_1320_tender_type_update.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 13:20:56 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@706 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:44 +00:00
abijah
196a7ae6e6 Updated property_manager.sql with property_manager_2009_08_17_0954.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 09:54:04 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@705 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:41 +00:00
abijah
24ad1ef49c Updated property_manager.sql with property_manager_2009_08_17_0229.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 02:29:46 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@704 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:38 +00:00
abijah
019b59fdbc Updated property_manager.sql with property_manager_2009_08_17_0146.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:46:46 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@703 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:35 +00:00
abijah
8892583db4 Updated property_manager.sql with property_manager_2009_08_17_0141.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:41:10 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@702 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:31 +00:00
abijah
ab840075c2 Updated property_manager.sql with property_manager_2009_08_17_0133.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:33:39 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@701 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:28 +00:00
abijah
10fe7bf230 Updated property_manager.sql with property_manager_2009_08_17_0131.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:31:32 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@700 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:25 +00:00
abijah
5bcd424055 Updated property_manager.sql with property_manager_2009_08_17_0124.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:24:03 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@699 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:22 +00:00
abijah
7cb0381060 Updated property_manager.sql with property_manager_2009_08_17_0117.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:17:59 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@698 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:19 +00:00
abijah
935920a38a Updated property_manager.sql with property_manager_2009_08_17_0108.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:08:27 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@697 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:16 +00:00
abijah
df3bbb698e Updated property_manager.sql with property_manager_2009_08_17_0106.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 01:06:16 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@696 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:13 +00:00
abijah
a2c1779454 Updated property_manager.sql with property_manager_2009_08_17_0023.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 00:23:12 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@695 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:10 +00:00
abijah
7a50d02a44 Updated property_manager.sql with property_manager_2009_08_17_0022.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Mon Aug 17 00:22:31 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@694 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:07 +00:00
abijah
22edc5a524 Updated property_manager.sql with property_manager_2009_08_16_2357.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 23:57:42 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@693 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:04 +00:00
abijah
bc33f3cb2c Updated property_manager.sql with property_manager_2009_08_16_2351.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 23:51:53 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@692 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:48:01 +00:00
abijah
e3a606ebf0 Updated property_manager.sql with property_manager_2009_08_16_2349.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 23:49:52 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@691 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:58 +00:00
abijah
8e91eadf53 Updated property_manager.sql with property_manager_2009_08_16_2325.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 23:25:27 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@690 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:55 +00:00
abijah
7e665af8be Updated property_manager.sql with property_manager_2009_08_16_2316.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 23:16:28 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@689 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:51 +00:00
abijah
2727812144 Updated property_manager.sql with property_manager_2009_08_16_2256.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 22:56:34 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@688 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:48 +00:00
abijah
dd7135df49 Updated property_manager.sql with property_manager_2009_08_16_2155_harmon_moveout_and_credit.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 21:55:45 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@687 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:45 +00:00
abijah
0297266a34 Updated property_manager.sql with property_manager_2009_08_16_2126_hawk_reversal_and_moveout.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 21:26:59 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@686 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:42 +00:00
abijah
3b1e06bade Updated property_manager.sql with property_manager_2009_08_16_2057.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 20:57:52 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@685 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:39 +00:00
abijah
ce54ed2341 Updated property_manager.sql with property_manager_2009_08_16_2050.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 20:50:10 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@684 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:36 +00:00
abijah
b4097850dd Updated property_manager.sql with property_manager_2009_08_16_2023_small-movein-date-fix.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 20:23:24 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@683 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:33 +00:00
abijah
ac23a1be18 Updated property_manager.sql with property_manager_2009_08_16_2015.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 20:15:27 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@682 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:30 +00:00
abijah
88d468d20c Updated property_manager.sql with property_manager_2009_08_16_2009.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 20:09:42 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@681 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:27 +00:00
abijah
bb9ce64657 Updated property_manager.sql with property_manager_2009_08_16_1820_brandner_credit_note.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 18:20:31 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@680 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:24 +00:00
abijah
77a01a16c4 Updated property_manager.sql with property_manager_2009_08_16_1811.sql
Created:  Wed Aug 19 13:42:58 2009
	Modified: Sun Aug 16 18:11:31 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@679 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:21 +00:00
abijah
d26b6e99bd Updated property_manager.sql with property_manager_2009_08_15_0945_refund.sql
Created:  Wed Aug 19 13:42:21 2009
	Modified: Sat Aug 15 09:45:41 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@678 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:18 +00:00
abijah
3096759738 Updated property_manager.sql with property_manager_2009_08_14_2223_datefix.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 22:23:05 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@677 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:15 +00:00
abijah
011481be2d Updated property_manager.sql with property_manager_2009_08_14_2221_brandner_restart.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 22:21:16 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@676 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:12 +00:00
abijah
21e11298eb Updated property_manager.sql with property_manager_2009_08_14_2200_brandner_pre-move.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 22:00:24 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@675 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:09 +00:00
abijah
8b93f6ad91 Updated property_manager.sql with property_manager_2009_08_14_2154_brander_fix.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 21:56:59 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@674 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:06 +00:00
abijah
9b9c6d8f29 Updated property_manager.sql with property_manager_2009_08_14_2153.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 21:53:01 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@673 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:03 +00:00
abijah
44cda10211 Updated property_manager.sql with property_manager_2009_08_14_2145_brander_fix.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 21:47:50 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@672 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:47:00 +00:00
abijah
0a62c8a816 Updated property_manager.sql with property_manager_2009_08_14_2140.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 21:40:23 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@671 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:57 +00:00
abijah
c23d4c6209 Updated property_manager.sql with property_manager_2009_08_14_2125.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 21:25:29 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@670 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:53 +00:00
abijah
9923ccc6c3 Updated property_manager.sql with property_manager_2009_08_14_2122.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Fri Aug 14 21:22:50 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@669 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:50 +00:00
abijah
c4d4c3c989 Updated property_manager.sql with property_manager_2009_08_13_1526.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Thu Aug 13 15:26:32 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@668 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:47 +00:00
abijah
b94c8e56b4 Updated property_manager.sql with property_manager_2009_08_12_1702.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 17:02:49 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@667 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:44 +00:00
abijah
bde335f68c Updated property_manager.sql with property_manager_2009_08_12_1648.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 16:48:04 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@666 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:41 +00:00
abijah
515046efd6 Updated property_manager.sql with property_manager_2009_08_12_0555.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 05:55:27 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@665 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:38 +00:00
abijah
8c334f236d Updated property_manager.sql with property_manager_2009_08_12_0534.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 05:34:42 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@664 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:35 +00:00
abijah
18848db6b1 Updated property_manager.sql with property_manager_2009_08_12_0513.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 05:13:57 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@663 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:32 +00:00
abijah
e4d20cc849 Updated property_manager.sql with property_manager_2009_08_12_0509.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 05:09:47 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@662 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:29 +00:00
abijah
355af40ed5 Updated property_manager.sql with property_manager_2009_08_12_0456.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 04:56:51 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@661 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:26 +00:00
abijah
9f1a6b8087 Updated property_manager.sql with property_manager_2009_08_12_0441.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 04:41:30 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@660 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:23 +00:00
abijah
77de94df54 Updated property_manager.sql with property_manager_2009_08_12_0414.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 04:14:51 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@659 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:20 +00:00
abijah
00a306355a Updated property_manager.sql with property_manager_2009_08_12_0408.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 04:08:30 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@658 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:17 +00:00
abijah
f7c2493f99 Updated property_manager.sql with property_manager_2009_08_12_0405.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 04:05:08 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@657 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:14 +00:00
abijah
2bc2fb951b Updated property_manager.sql with property_manager_2009_08_12_0347.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 03:47:04 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@656 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:11 +00:00
abijah
cc86bb99c1 Updated property_manager.sql with property_manager_2009_08_12_0340.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 03:40:58 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@655 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:08 +00:00
abijah
eebb7c7c94 Updated property_manager.sql with property_manager_2009_08_12_0309.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 03:09:33 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@654 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:05 +00:00
abijah
88a1a62087 Updated property_manager.sql with property_manager_2009_08_12_0246.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 02:46:26 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@653 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:46:02 +00:00
abijah
29c157475b Updated property_manager.sql with property_manager_2009_08_12_0220.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 02:20:16 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@652 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:59 +00:00
abijah
237e744002 Updated property_manager.sql with property_manager_2009_08_12_0157.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 01:57:49 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@651 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:56 +00:00
abijah
6c38b08700 Updated property_manager.sql with property_manager_2009_08_12_0029.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 00:29:39 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@650 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:52 +00:00
abijah
29bb08adca Updated property_manager.sql with property_manager_2009_08_12_0009.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Wed Aug 12 00:09:20 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@649 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:49 +00:00
abijah
ca69698693 Updated property_manager.sql with property_manager_2009_08_11_2337.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 23:37:48 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@648 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:46 +00:00
abijah
9274bb9b0c Updated property_manager.sql with property_manager_2009_08_11_2127.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 21:27:09 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@647 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:43 +00:00
abijah
32ea8734e1 Updated property_manager.sql with property_manager_2009_08_11_1644.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 16:44:30 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@646 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:40 +00:00
abijah
5bb240708f Updated property_manager.sql with property_manager_2009_08_11_1634.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 16:34:10 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@645 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:37 +00:00
abijah
3e366d3dad Updated property_manager.sql with property_manager_2009_08_11_1625.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 16:25:27 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@644 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:34 +00:00
abijah
0de2931f66 Updated property_manager.sql with property_manager_2009_08_11_1557.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 15:57:23 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@643 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:31 +00:00
abijah
966dc495e2 Updated property_manager.sql with property_manager_2009_08_11_1548.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 15:48:12 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@642 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:28 +00:00
abijah
df869ef70a Updated property_manager.sql with property_manager_2009_08_11_1541.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 15:41:30 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@641 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:25 +00:00
abijah
8dcf5956fe Updated property_manager.sql with property_manager_2009_08_11_1528.sql
Created:  Wed Aug 19 13:42:23 2009
	Modified: Tue Aug 11 15:28:37 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@640 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:22 +00:00
abijah
654e79803f Updated property_manager.sql with property_manager_2009_08_11_1518.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 15:18:42 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@639 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:19 +00:00
abijah
dcbff5a956 Updated property_manager.sql with property_manager_2009_08_11_1503.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 15:04:00 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@638 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:16 +00:00
abijah
b1fb5e29db Updated property_manager.sql with property_manager_2009_08_11_1459.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 14:59:38 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@637 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:13 +00:00
abijah
a6c3b612ba Updated property_manager.sql with property_manager_2009_08_11_1456.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 14:56:54 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@636 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:09 +00:00
abijah
ee9ae2079c Updated property_manager.sql with property_manager_2009_08_11_1400.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 14:00:14 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@635 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:06 +00:00
abijah
58495d5607 Updated property_manager.sql with property_manager_2009_08_11_1341.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 13:41:07 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@634 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:03 +00:00
abijah
ebcc494e36 Updated property_manager.sql with property_manager_2009_08_11_1336.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 13:36:50 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@633 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:45:00 +00:00
abijah
835853c51c Updated property_manager.sql with property_manager_2009_08_11_1304.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 13:04:49 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@632 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:57 +00:00
abijah
622eca3f1a Updated property_manager.sql with property_manager_2009_08_11_1302.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 13:02:09 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@631 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:54 +00:00
abijah
65b132ac8e Updated property_manager.sql with property_manager_2009_08_11_1250.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 12:50:46 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@630 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:51 +00:00
abijah
410e588e97 Updated property_manager.sql with property_manager_2009_08_11_1244.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 12:44:27 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@629 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:48 +00:00
abijah
9aba878ee6 Updated property_manager.sql with property_manager_2009_08_11_1216.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 12:16:56 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@628 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:44 +00:00
abijah
bd90424080 Updated property_manager.sql with property_manager_2009_08_11_1203.sql
Created:  Wed Aug 19 13:42:22 2009
	Modified: Tue Aug 11 12:03:51 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@627 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:41 +00:00
abijah
a939b0839b Updated property_manager.sql with property_manager_2009_08_11_1154.sql
Created:  Wed Aug 19 13:42:21 2009
	Modified: Tue Aug 11 11:54:28 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@626 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:38 +00:00
abijah
2d8c536f33 Updated property_manager.sql with property_manager_2009_08_11_1153.sql
Created:  Wed Aug 19 13:42:21 2009
	Modified: Tue Aug 11 11:53:39 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@625 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:44:35 +00:00
abijah
2d51340a56 Updated property_manager.sql with property_manager_2009_08_11_1145.sql
Created:  Wed Aug 19 13:38:12 2009
	Modified: Tue Aug 11 11:45:48 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@624 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:39:56 +00:00
abijah
98c4a66f2f Updated property_manager.sql with property_manager_2009_08_11_1138.sql
Created:  Wed Aug 19 13:38:12 2009
	Modified: Tue Aug 11 11:38:29 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@623 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:39:52 +00:00
abijah
29b829d3af Updated property_manager.sql with property_manager_2009_08_11_1127.sql
Created:  Wed Aug 19 13:38:12 2009
	Modified: Tue Aug 11 11:27:31 2009


git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@622 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:39:48 +00:00
abijah
d0aa3799fa Added some more development sql commands.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@621 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-19 20:33:39 +00:00
abijah
5e78d32ec4 More cleanup of lingering jqgrid remnants
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@620 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 15:48:59 +00:00
abijah
a76421c858 Upgraded to jqGrid 3.5.2, which has a couple bugfixes. Fixed a bug in our code preventing the grid query from being shown when in development mode.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@619 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 15:33:45 +00:00
abijah
28086651e5 Removed the development function for fixing the ACH deposit items.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@618 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 07:17:21 +00:00
abijah
da80c3623e Added another todo item
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@617 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 07:16:04 +00:00
abijah
309512dde0 Added tooltips to the sitemap. At some point, we hope to incorporate a jquery plugin for nicer presentation, but this gets the basics.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@616 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 06:41:49 +00:00
abijah
8b1d3c9830 disabled logging when assessing late charges
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@615 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 04:00:17 +00:00
abijah
31265104e1 Modified the grid such that the account is right next to the dollar amount. It was too distracting for the eyes to have to span columns putting charges and amounts together.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@614 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 03:59:51 +00:00
abijah
c719d11df2 Fixed special routing to support a top level url.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@613 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 03:58:24 +00:00
abijah
e6d65a5212 Fixed bug in the age() function that was preventing the ' ago' text. Of course, there are places it may not be desired, so I added a param to control the suffix.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@612 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 01:33:38 +00:00
abijah
e21233954a Added comment field back in (not sure when/why/how it went missing).
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@611 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 01:32:28 +00:00
abijah
d36cfd9653 Disabled logging again
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@610 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-18 01:32:09 +00:00
abijah
d141f61055 Added a column to Tender that identifies the exact ledger entry which was used to deposit the tender. It was necessary due to the kludgy way that I've set ACH items to auto-deposit, which uses a ledger entry that has nothing to do with the transaction account. This would probably allow us to eliminate the deposit_transaction_id, but I'd like to break as little as possible at the moment. I'll come back and clean this up in the future. Also, fixed a stupid bug that was causing major database thrash whenever a transaction was entered without a customer id. I could have fixed the Customer::update() function, but it was designed to accept null so that we could update all the customers, something definitely useful while developing.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@609 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 23:55:51 +00:00
abijah
4b8dc3da02 Added an assert whenever we lookup an account that doesn't exist.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@608 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 23:51:09 +00:00
abijah
709689b15b First pass at making ACH items auto-deposit. Things are really set up for a separate deposit transaction though, and I should just bite the bullet and do that instead. I don't want them to show up as Deposits though, but perhaps it would be easiest just to make a new type 'AUTO_DEPOSIT' or something.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@607 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 21:16:16 +00:00
abijah
3eb989e03c Added a grid load error indication, since it was lost when we disabled the debug output.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@606 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 18:41:17 +00:00
abijah
eb019dd9e5 Fixed a bug when transitioning to a move-in receipt, and changed the invoice/receipt grids to only contain current customers / active leases. A non-current customer or closed lease can still have a receipt/invoice, the user will just have to go directly to the customer / lease first. OK, so I just checked and that's not true. Perhaps it should be...
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@605 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 17:23:50 +00:00
abijah
719373e534 Captured a couple more todo items
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@604 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 17:07:24 +00:00
abijah
1c5d97f06d Modified the customer update() function to update all customers if passed null. This would not be a typcial scenario, but it useful at the moment during development.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@603 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 06:32:32 +00:00
abijah
589168440c Fixed a bug with charge through / paid through, which was not taking into account reversed charges. I fear there are other conditions not being accounted for, not only here but throughout. One at a time for now...
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@602 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 06:31:42 +00:00
abijah
73c5a20158 Eliminated (at least temporarily) the single ledger entry view, redirecting to the double entry view instead.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@601 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 06:30:01 +00:00
abijah
a44654ec01 Hopeful fix for the bug affecting customer security deposit balance. It was introduced when we added the Customer Credit account, since Security Deposit no longer _directly_ pays charges like it used to. Now, it's converted to customer credit, and _that_ account is the one that pays. The security deposit situation is a bit shaky, but seems to be working again.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@600 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 05:48:54 +00:00
abijah
7a331d5f4f Fixed bug when fetching data for editing a customer (the details function was deleted sometime back and might be worth putting back in). Also, added a tiny helper feature to update cached items while things are still somewhat unstable. Any time customer edit is clicked, the customer (and associated leases) will all be updated. This should allow an easy customer workaround in case there is a bug in the field.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@599 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 05:43:01 +00:00
abijah
daf9fe9391 Added confirmation page, and more importantly date and comment settings, when reversing a charge.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@598 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 05:37:29 +00:00
abijah
d8767cfb73 Added code to make jqGrid development aware
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@597 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 03:44:09 +00:00
abijah
64792e6fe2 Merge in support for jqGrid 3.5 (plus a change to layout.css after the merge).
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@596 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 03:39:29 +00:00
abijah
424276eeb4 Fixed the test for delinquency from 15 days (used while debugging) to 10 days
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@595 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 03:38:07 +00:00
abijah
377a4cc88c Turned off debugging code that was left on.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@594 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 02:52:47 +00:00
abijah
170f660528 Merge in from surplus_account_20090815 r592
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@593 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 02:22:54 +00:00
abijah
90ecbda541 Several minor changes including a couple minor bugfixes.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@592 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-17 02:15:02 +00:00
abijah
4afe0bd77b Added logic to prevent a double entry where the credit and debit record in the exact same ledger. There is no known reason why we would need to record such an entry, even though it would not be incorrect to do so.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@591 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 23:41:44 +00:00
abijah
8440a7c833 Checkin a support function that is needed by the Transaction model since several checkins ago.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@590 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 22:51:08 +00:00
abijah
00d509f23d Minor formatting issue for the Transaction.type enums
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@589 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 22:48:00 +00:00
abijah
080c82fc10 More bug fixes, especially around reversals of charges that have been paid from something other than customer money (such as waivers). I suspect it still will not work correctly for concession, depending on your point of view. Either concession should not count as customer credit, since they never paid that money, or it should since they were told they would get $X off, and upon charge reversal, they no longer get the credit. It seems they would only get the credit when reversing a mistaken charge, in which case, the user can manually provide a new concession.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@588 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 22:35:02 +00:00
abijah
1b02be19f0 Adjusted to match the naming in the database
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@587 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 22:31:06 +00:00
abijah
366d59a5e6 Added a customer credit account.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@586 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 19:16:42 +00:00
abijah
2634cf824a Another checkin screwup where we accidentally specified ledger.php instead of ledger_entry.php
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@585 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 19:14:37 +00:00
abijah
1429fe720b Added mechanism to lookup the NSF tender from the bounce transaction.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@584 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 19:00:45 +00:00
abijah
754cdb8522 Fixed bug with NSF, which was failing to locate the nsf_entry_id. To resolve this, I added the original data into the return structure for each item, instead of just the created IDs. Also, added NsfTender to the Transaction model to locate which Tender an NSF transaction relates to.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@583 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 18:59:16 +00:00
abijah
a1a68f3209 Updated SQL scratchpad
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@582 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 16:48:44 +00:00
abijah
8843d24baa Added SQL scratchpad
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@581 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 16:37:54 +00:00
abijah
892618db36 I need to check again in the morning, but it seem like this is finally what we need for reversals. Of course, we're still using A/P as a temporary solution. If we do indeed move forward with this sort of solution (dedicated customer credit account), then we'll have to create a new account fairly soon.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@580 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 09:31:19 +00:00
abijah
3decfff33b Fixed is_bool / is_boolean bug
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@579 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 06:12:46 +00:00
abijah
945221d565 Changed reversals to create an explicit credit BEFORE assigning credits to outstanding charges. This ensures that charges are paid from the customer surplus account and we don't end up with bizarre disbursements, like having Rent paid from Damage or whatever the reversed charge was.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@578 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 05:17:09 +00:00
abijah
a968d7abe6 Changed the explicit receipt amount to be driven from stats instead of the assignCredits return value. This is in anticipation of creating an explicit credit directly, without even calling assignCredits. I'll do that for reversal on the next checkin.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@577 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 04:43:34 +00:00
abijah
8b6b8884f7 More good progress on reversals. There is still an issue where after reversing, a disbursement can be applied to a new charge from the old charge account, instead of the surplus account. I'll work on that next.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@576 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 03:56:36 +00:00
abijah
14805190fc Added back in the logic to simply update an existing explicit credit instead of creating an additional one. At the moment, I can't think of a scenario for this other than when reversing charges, which is still broken. So, until I make progress on that, it's not even clear this changes is needed, let alone whether it works.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@575 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 02:22:45 +00:00
abijah
a1bdecfcaa More tweaks to the addTransaction algorithm, working on a solid plan for customer surplus
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@574 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 02:04:13 +00:00
abijah
4896834a96 Added the account back into the grid, since an invoice could have charges across several accounts.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@573 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 01:06:14 +00:00
abijah
a9c3c40053 Bug fix for matching ledger entry to double entry
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@572 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 00:49:21 +00:00
abijah
4125d7ba16 Quick and dirty hack to get double entries to show again.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@571 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-16 00:45:11 +00:00
abijah
26d9b1bc38 Modified the charges list on the receipt page to have the query performed directly as part of returning the grid data, instead of an intermediary call to get the unreconciled entries first. This not only ensures consistent data, but is quicker, cleaner, and fixes the customer balance bug that seems to have been introduced as part of the change to how customer surplus is handled (although it could have been resolved using the old technique just as well).
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@570 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-15 23:04:57 +00:00
abijah
f30e536e47 Modified to automatically calculate the crdr field, if not specified
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@569 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-15 20:43:00 +00:00
abijah
96a030e340 First pass changes for a dedicated customer credit account. This checkin is just refactoring.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@568 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-15 19:50:31 +00:00
abijah
460e9a2e64 Branch to experiment with keeping all customer surplus items in a dedicated liability account.
git-svn-id: file:///svn-source/pmgr/branches/surplus_account_20090815@567 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-15 19:48:30 +00:00
abijah
6e63365604 A couple bugfixes and some more tweaks to how reversals are handled.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@566 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-15 16:47:55 +00:00
abijah
4f85dc243e Getting closer on the reversal issue. There is definitely more testing to do, and some tweaks as well, but this may be approximately what we will finally settle on.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@565 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-15 03:11:16 +00:00
abijah
30f755cf42 Fixed negative numbers
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@564 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-15 01:22:16 +00:00
abijah
170ba466de Cleaned up several places regarding redirect and rendering during development for debug purposes. Also, added a link to the intended redirect target when we've rendered instead. These changes haven't been tested, hopefully they are benign.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@563 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:49:42 +00:00
abijah
d2d1bb3fc4 Change to how reversals are handled. In the process, I've tried to solidify _exactly_ what addTransaction will do, since it was becoming a house of cards of sorts. It was using special logic to decide things like whether to add ledger entries, statement entries, or both, whether to assignCredits afterwards, whether the generated receipt was to be considered a credit, and so on. Consequently, modifications to any calling function (addInvoice, addWaiver, etc) would often require addTransaction modifications, which would turn around and break all of the other calling functions. So, that embedded logic has been removed from addTransaction, and the rules of what addTransaction should do are now defined by the callers. This change is DEFINTELY not complete, as it probably has several bugs, and it DOES NOT YET WORK for reversals. I need a clean baseline to move forward from though, and this checkin approximates where we need to go.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@562 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:31:56 +00:00
abijah
d024d333d2 Moved the INTERNAL_ERROR calls to use the class function instead of the global one.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@561 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:21:21 +00:00
abijah
778bb43895 Modified INTERNAL_ERROR to support inclusion of the blank layout, since all the javascript is lost otherwise. This should only matter for development. Also, fixed a bug with rendering when redirect is called but headers have already been output.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@560 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:10:16 +00:00
abijah
41321481c7 Minor tweak to grid caption and display of the entry id instead of the transaction id.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@559 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:07:50 +00:00
abijah
fe9f6ce949 Allow the dollar sign in the input box, since it will get stripped off later anyway.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@558 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:07:02 +00:00
abijah
f81bfdecc2 Fixed the currency function to always return in dollar amounts, and never in just cents, as the core currency function does.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@557 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:06:17 +00:00
abijah
8dd6fc957d Fixed url generation since it was not propogating the admin/dev routing items. Also modified the invoice at move in to exclude the customer list, and to transition directly to the receipt page afterwards.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@556 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:05:36 +00:00
abijah
d92acf12de Dropped the security level for viewing statement and ledger entries
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@555 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:01:25 +00:00
abijah
43d1d2ccf5 Fixed bug with statement entry counts when statement_entry_id is set
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@554 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 21:00:21 +00:00
abijah
c06399cf86 Added support for deleting (destroying) a transaction. This is strictly development/super-admin type functionality.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@553 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 20:58:50 +00:00
abijah
d1187f9bdd Added the http request to the internal error box, since it will be necessary to help track down any reported errors.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@552 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 18:13:12 +00:00
abijah
b7a77757f9 Fixed a couple URL problems, including redirect, which was previously entirely unable to utilize our AppHelper for the url generation. Added a couple menu items into the Admin section. Changed debug to be OFF for any route other than the 'dev' one.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@551 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-14 18:11:33 +00:00
abijah
5f199d97fe Fixed the datetime bug
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@550 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 22:23:45 +00:00
abijah
fc292e3366 Moved paid-through from the detail box, which is semi-static information, to the info box, which holds data that changes with time (i.e. the so called pertinent information).
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@549 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 22:09:27 +00:00
abijah
94e300a129 Modified the formatted date/age results to be span encapsulated for later css formatting.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@548 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 22:08:43 +00:00
abijah
791b2d8ab1 Got rid of LATE as a unit status, as it did not represent an physical condition. The logic was moved to Lease, where it is a much better fit. The sitemap still presents LATE units, as it is a useful view, but the underlying logic is driven from Lease, not Unit. This checkin also includes a small feature change to how late charges are assessed, as well as a menu item to kick off the charge assessments (both accidentally wedged in to this changeset).
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@547 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 20:55:19 +00:00
abijah
091920d80a Changed the default of the debug flag when generating grid data. The original intention was to have it debug by default, so that debugging would be on if the url were manually typed in. That has never been needed though, and this change not only results in cleaner logic, it makes sure we have no issues with routing.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@546 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 20:07:49 +00:00
abijah
1511986ed0 Changed the custom route variables, so that the dev route could set the admin flag and not screw up the routing. The AppController now checks the routing params to set the dev/admin flags.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@545 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 16:43:07 +00:00
abijah
1e88e1fce2 Added admin and development routes, which should help while in transition to user security.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@544 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 16:09:45 +00:00
abijah
a2014a916e Added cached fields for charged_through and paid_through dates of a lease. Also, added the ability to dynamically determine whether a unit is late or not. In reality, we really need this to be part of the lease, not one of the status types for unit. The sitemap, however, is driven from unit information, so it's not clear whether we should move that information or not.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@543 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-13 02:37:37 +00:00
abijah
bd52030984 Changed naming to match that on the lease page
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@542 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-12 23:16:36 +00:00
abijah
f23726783e Fixed bug causing a $0.00 security deposit charge on the move-in invoice
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@541 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-12 23:16:17 +00:00
abijah
1d27b4dcb5 Many bug fixes, found while entering real facility data. Most are quite minor, although there was a functionality change to assignCredits, to support concessions without assigning them to anything other than rent. I've found that there is a glaring problem with charge reversals, which don't work correctly with the collected report. Of course, we're deleting prior disbursements, which obviously needs to be rectified.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@540 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-12 09:37:49 +00:00
abijah
e74f8987d9 Made viewing the deposit slip the default action when viewing the list of deposit transactions.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@539 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 18:25:40 +00:00
abijah
9c55a047a8 Implemented very crude attempt at security privleges. This is not really intended to be security, just a quick and dirty mechanism to avoid prying eyes. More robust security is left to future implementation.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@538 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 18:22:21 +00:00
abijah
6f2038f7b0 Added ability to customize the action on grid links
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@537 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 17:30:12 +00:00
abijah
ec22f4b003 Removed the Signed column from the leases grid unless requested
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@536 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 17:04:21 +00:00
abijah
70629e360b Added the Batch Number to ACH entries. This is the unique number of each initiated batch, and is what would show up on a bank statement or used by the bank to track down an ACH transaction.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@535 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 16:22:09 +00:00
abijah
fc4e812d67 More tweaking with grids that need to be reloaded immediately after page load. Fixed a bug with the statement_entry balance field, as there were two of them.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@534 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 15:56:40 +00:00
abijah
b6ee958c35 Marked off several to-do items
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@533 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 15:21:50 +00:00
abijah
f82df229f2 Modified the statement entries grid, as well as the underlying controller, to support a couple new fields, 'applied' and 'balance'.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@532 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 07:27:56 +00:00
abijah
96c499786c Finally have a (slightly kludgy) fix for keeping the 'collected' grid from being rendered before ready.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@531 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 07:24:52 +00:00
abijah
52e0181bfb Fixed bug with display on the bank deposit page, caused by reusing a class name in the edit tender page.
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@530 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 07:21:34 +00:00
abijah
b65c5c1dbf Added ability to rename columns on a case by case basis
git-svn-id: file:///svn-source/pmgr/branches/yafr_20090716@529 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-08-11 07:15:04 +00:00
Abijah
562ffc9e4b Created directory structure
git-svn-id: file:///svn-source/pmgr/trunk@1 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-05-27 04:16:20 +00:00
162 changed files with 9540 additions and 4438 deletions

View File

@@ -1,3 +0,0 @@
@echo off
%~dp0\scripts\sitelink2pmgr.pl %~dp0\db\schema.sql %~dp0db\vss.mdb %*
echo Done!

View File

@@ -25,9 +25,9 @@
-- REVISIT <AP>: 20090511
-- By not specifying the database, the script can
-- make the determination of which one to use.
-- DROP DATABASE IF EXISTS `property_manager`;
-- CREATE DATABASE `property_manager`;
-- USE `property_manager`;
DROP DATABASE IF EXISTS `property_manager`;
CREATE DATABASE `property_manager`;
USE `property_manager`;
-- ######################################################################
@@ -241,7 +241,7 @@ CREATE TABLE `pmgr_contacts_methods` (
-- ######################################################################
-- ######################################################################
-- ##
-- ## GROUPS
-- ## GROUPS / USERS
-- ##
@@ -256,59 +256,15 @@ CREATE TABLE `pmgr_groups` (
-- code may not be userful
`code` VARCHAR(12) NOT NULL, -- User style "id"
`name` VARCHAR(80) NOT NULL,
-- Lower ranks are given higher priority
`rank` SMALLINT UNSIGNED NOT NULL DEFAULT 100,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_group_options
DROP TABLE IF EXISTS `pmgr_group_options`;
CREATE TABLE `pmgr_group_options` (
`group_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(50) NOT NULL,
`value` VARCHAR(255) NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`group_id`, `name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_group_permissions
DROP TABLE IF EXISTS `pmgr_group_permissions`;
CREATE TABLE `pmgr_group_permissions` (
`group_id` INT(10) UNSIGNED NOT NULL,
`name` CHAR(30) NOT NULL,
`access` ENUM('ALLOWED',
'DENIED',
'FORCED')
NOT NULL DEFAULT 'ALLOWED',
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`group_id`, `name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ##
-- ## USERS
-- ##
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
@@ -318,14 +274,10 @@ DROP TABLE IF EXISTS `pmgr_users`;
CREATE TABLE `pmgr_users` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`code` VARCHAR(12) NOT NULL, -- User style "id"
-- Login details. Passwords are not yet used (and so NULL).
`login` VARCHAR(30) NOT NULL,
`salt` CHAR(12) DEFAULT NULL,
`passhash` VARCHAR(255) DEFAULT NULL,
`login` VARCHAR(30) NOT NULL,
-- Contact information for this user
`contact_id` INT(10) UNSIGNED NOT NULL,
`contact_id` INT(10) UNSIGNED DEFAULT NULL,
-- Specific comments
`comment` VARCHAR(255) DEFAULT NULL,
@@ -334,18 +286,208 @@ CREATE TABLE `pmgr_users` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ##
-- ## OPTIONS
-- ##
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_options
DROP TABLE IF EXISTS `pmgr_options`;
CREATE TABLE `pmgr_options` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
UNIQUE KEY `name_key` (`name`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_option_values
DROP TABLE IF EXISTS `pmgr_option_values`;
CREATE TABLE `pmgr_option_values` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`option_id` INT(10) UNSIGNED NOT NULL,
`value` VARCHAR(255) NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_default_options
DROP TABLE IF EXISTS `pmgr_default_options`;
CREATE TABLE `pmgr_default_options` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`option_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_group_options
DROP TABLE IF EXISTS `pmgr_group_options`;
CREATE TABLE `pmgr_group_options` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`group_id` INT(10) UNSIGNED NOT NULL,
`option_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
KEY `group_key` (`group_id`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_user_options
DROP TABLE IF EXISTS `pmgr_user_options`;
CREATE TABLE `pmgr_user_options` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(50) NOT NULL,
`value` VARCHAR(255) NOT NULL,
`option_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
KEY `user_key` (`user_id`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
PRIMARY KEY (`user_id`, `name`)
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_site_options
DROP TABLE IF EXISTS `pmgr_site_options`;
CREATE TABLE `pmgr_site_options` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`site_id` INT(10) UNSIGNED NOT NULL,
`option_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
KEY `site_key` (`site_id`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ##
-- ## PERMISSIONS
-- ##
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_permissions
DROP TABLE IF EXISTS `pmgr_permissions`;
CREATE TABLE `pmgr_permissions` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
UNIQUE KEY `name_key` (`name`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_permission_values
DROP TABLE IF EXISTS `pmgr_permission_values`;
CREATE TABLE `pmgr_permission_values` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`permission_id` INT(10) UNSIGNED NOT NULL,
`access` ENUM('ALLOW',
'DENY')
NOT NULL DEFAULT 'DENY',
`level` SMALLINT UNSIGNED DEFAULT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_default_permissions
DROP TABLE IF EXISTS `pmgr_default_permissions`;
CREATE TABLE `pmgr_default_permissions` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`permission_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_group_permissions
DROP TABLE IF EXISTS `pmgr_group_permissions`;
CREATE TABLE `pmgr_group_permissions` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`group_id` INT(10) UNSIGNED NOT NULL,
`permission_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
KEY `group_key` (`group_id`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_user_permissions
DROP TABLE IF EXISTS `pmgr_user_permissions`;
CREATE TABLE `pmgr_user_permissions` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT(10) UNSIGNED NOT NULL,
`permission_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
KEY `user_key` (`user_id`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_site_permissions
DROP TABLE IF EXISTS `pmgr_site_permissions`;
CREATE TABLE `pmgr_site_permissions` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`site_id` INT(10) UNSIGNED NOT NULL,
`permission_value_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
KEY `site_key` (`site_id`),
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
@@ -380,46 +522,6 @@ CREATE TABLE `pmgr_sites` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_site_options
DROP TABLE IF EXISTS `pmgr_site_options`;
CREATE TABLE `pmgr_site_options` (
`site_id` INT(10) UNSIGNED NOT NULL,
`name` VARCHAR(50) NOT NULL,
`value` VARCHAR(255) NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`site_id`, `name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_site_memberships
--
-- Which users are allowed to access which sites,
-- and under which set of group permissions (possibly multiple)
-- SELECT U.id, P.name, MAX(P.access)
-- FROM pmgr_users U
-- LEFT JOIN pmgr_site_membership M ON M.user_id = U.id
-- LEFT JOIN pmgr_groups G ON G.id = M.group_id
-- LEFT JOIN pmgr_group_permissions P ON P.group_id = G.id
-- GROUP BY U.id, P.name
DROP TABLE IF EXISTS `pmgr_site_memberships`;
CREATE TABLE `pmgr_site_memberships` (
`site_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(10) UNSIGNED NOT NULL,
`group_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`site_id`, `user_id`, `group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_site_areas
@@ -437,6 +539,38 @@ CREATE TABLE `pmgr_site_areas` (
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ######################################################################
-- ##
-- ## MEMBERSHIPS
-- ##
-- ----------------------------------------------------------------------
-- ----------------------------------------------------------------------
-- TABLE pmgr_memberships
--
-- Which users are allowed to access which sites,
-- and under which set of group permissions (possibly multiple)
DROP TABLE IF EXISTS `pmgr_memberships`;
CREATE TABLE `pmgr_memberships` (
`site_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(10) UNSIGNED NOT NULL,
`group_id` INT(10) UNSIGNED NOT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`site_id`, `user_id`, `group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ######################################################################
-- ######################################################################
-- ######################################################################
@@ -471,13 +605,10 @@ CREATE TABLE `pmgr_units` (
'DIRTY',
'VACANT',
'OCCUPIED',
'LATE', -- NOT SURE
'LOCKED',
'LIENED')
NOT NULL DEFAULT 'VACANT',
`current_lease_id` INT(10) UNSIGNED DEFAULT NULL,
`sort_order` MEDIUMINT UNSIGNED NOT NULL,
`walk_order` MEDIUMINT UNSIGNED NOT NULL,
@@ -725,6 +856,9 @@ CREATE TABLE `pmgr_leases` (
`notice_received_date` DATE DEFAULT NULL,
`close_date` DATE DEFAULT NULL,
`charge_through_date` DATE DEFAULT NULL,
`paid_through_date` DATE DEFAULT NULL,
`deposit` FLOAT(12,2) DEFAULT NULL,
`rent` FLOAT(12,2) DEFAULT NULL,
@@ -872,47 +1006,46 @@ CREATE TABLE `pmgr_accounts` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
LOCK TABLES `pmgr_accounts` WRITE;
INSERT INTO `pmgr_accounts` (`type`, `name`, `level`)
VALUES
('EQUITY', 'Equity', 1),
('LIABILITY', 'Loan', 1);
INSERT INTO `pmgr_accounts` (`type`, `name`)
VALUES
('ASSET', 'A/R' ),
-- REVISIT <AP>: 20090710 : We don't really need NSF, as it
-- will always run a zero balance. However, it will help
-- us identify how serious the NSF situation is.
('LIABILITY', 'A/P' ),
('LIABILITY', 'Credit' );
INSERT INTO `pmgr_accounts` (`type`, `name`, `receipts`)
VALUES
('ASSET', 'Cash', 1),
('ASSET', 'Check', 1),
('ASSET', 'Money Order', 1),
('ASSET', 'ACH', 1),
('EXPENSE', 'Concession', 1);
INSERT INTO `pmgr_accounts` (`type`, `name`)
VALUES
('ASSET', 'NSF' ),
('LIABILITY', 'A/P' );
INSERT INTO `pmgr_accounts` (`type`, `name`, `receipts`, `refunds`)
VALUES
('ASSET', 'Cash', 1, 0),
('ASSET', 'Check', 1, 0),
('ASSET', 'Money Order', 1, 0),
('ASSET', 'ACH', 1, 0),
('ASSET', 'Closing', 0, 0), -- REVISIT <AP>: Temporary
('EXPENSE', 'Concession', 1, 0),
('EXPENSE', 'Waiver', 0, 0);
INSERT INTO `pmgr_accounts` (`type`, `name`, `refunds`, `deposits`)
VALUES
-- REVISIT <AP>: 20090710 : We probably don't really want petty cash depositable.
-- This is just for testing our deposit code
('ASSET', 'Petty Cash', 1, 1);
('EXPENSE', 'Waiver' ),
('EXPENSE', 'Bad Debt' );
INSERT INTO `pmgr_accounts` (`type`, `name`, `invoices`)
VALUES
('LIABILITY', 'Tax', 1),
('LIABILITY', 'Tax', 0),
('LIABILITY', 'Security Deposit', 1),
('INCOME', 'Rent', 1),
('INCOME', 'Late Charge', 1),
('INCOME', 'NSF Charge', 1),
('INCOME', 'Cleaning', 1),
('INCOME', 'Damage', 1);
INSERT INTO `pmgr_accounts` (`type`, `name`, `deposits`, `refunds`)
VALUES
('ASSET', 'Bank', 1, 1);
INSERT INTO `pmgr_accounts` (`type`, `name`)
VALUES
('EXPENSE', 'Bad Debt' ),
('EXPENSE', 'Maintenance' );
INSERT INTO `pmgr_accounts` (`type`, `name`, `refunds`)
VALUES
('ASSET', 'Petty Cash', 1);
INSERT INTO `pmgr_accounts` (`type`, `name`, `level`, `deposits`, `refunds`)
VALUES
('ASSET', 'Bank', 6, 1, 1);
INSERT INTO `pmgr_accounts` (`type`, `name`, `level`)
VALUES
('ASSET', 'Closing', 6),
('LIABILITY', 'Loan', 1),
('EQUITY', 'Equity', 1);
UNLOCK TABLES;
@@ -970,6 +1103,8 @@ CREATE TABLE `pmgr_transactions` (
'CREDIT_NOTE', -- Inverse of Sales Invoice
'PAYMENT', -- Actual payment
'DEPOSIT',
'AUTO_DEPOSIT', -- Fundamentally same as DEPOSIT
'WITHDRAWAL',
'CLOSE', -- Essentially an internal (not accounting) transaction
-- 'CREDIT',
-- 'REFUND',
@@ -1119,6 +1254,9 @@ CREATE TABLE `pmgr_statement_entries` (
-- Allow the disbursement to reconcile against the charge
`charge_entry_id` INT(10) UNSIGNED DEFAULT NULL,
-- The transaction that reversed this charge, if any
`reverse_transaction_id` INT(10) UNSIGNED DEFAULT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
@@ -1143,6 +1281,9 @@ CREATE TABLE `pmgr_tender_types` (
-- include credit cards, debit cards, and ACH transfers.
`tillable` TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
-- Should these items be deposited automatically?
`auto_deposit` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0,
-- Names of the 4 data fields (or NULL if not used)
-- Not the most robust of solutions, especially since
-- it requires (or strongly implicates) that all fields
@@ -1166,6 +1307,10 @@ CREATE TABLE `pmgr_tender_types` (
-- account, either distinct or non-distinct from others
`account_id` INT(10) UNSIGNED NOT NULL,
-- Which account should these items be deposited in?
-- This may or may not actually be used for all types
-- but will likely get used for auto deposit items.
`deposit_account_id` INT(10) UNSIGNED DEFAULT NULL,
`comment` VARCHAR(255) DEFAULT NULL,
@@ -1215,6 +1360,8 @@ CREATE TABLE `pmgr_tenders` (
`ledger_entry_id` INT(10) UNSIGNED NOT NULL,
-- The ledger entry if this tender is marked NSF
`nsf_ledger_entry_id` INT(10) UNSIGNED DEFAULT NULL,
-- The ledger entry if this actual deposit transaction
`deposit_ledger_entry_id` INT(10) UNSIGNED DEFAULT NULL,
-- The deposit transaction that included these monies
`deposit_transaction_id` INT(10) UNSIGNED DEFAULT NULL,
-- The NSF transaction coming back from the bank.

View File

@@ -1,68 +0,0 @@
N - GATE
N - ACH / CREDIT CARD PROCESSING
Y - CREDIT CARD ENTRY
Y - ACH ENTRY
P - INVENTORY TRACKING / POS
Y - UNIT TYPES
Y - UNIT SIZES
Y - UNITS
Y - MOVE IN / OUT
Y - UNIT TRANSFERS
Y - LEASE TRACKING (PDF Generation)
Y - LETTERS (PDF Generation)
Y - REMINDERS
Y - MULTIPLE LATE RENT SCHEDULES (Tenant A vs Tenant B)
Y - ACCOUNTING (assign charges to accounts)
Y - DETAILED REPORTING (HTML & PDF)
Y - SITE MAP; HOT CLICKABLE
P - PROSPECTIVE TENANTS
Y - MARKETING
P - RESERVATIONS
P - MOVE OUT NOTICES
P - MULTI-SITE (One database, multiple sites)
Y - GENERATE GEOGRAPHIC MAP OF CUSTOMERS USING GOOGLE!
- Major advantage here... MapPoint only choice with competitors
Y - WEB BASED
Y - CUSTOMER VIEW / MANAGER VIEW
Y - CUSTOMERS CAN CREATE ACCOUNTS, VIEW HISTORY
Y - CUSTOMERS CAN SIGN UP FOR AUTO PAY
----------------------------------------------------------------------
----------------------------------------------------------------------
Operations to be functional
'X' marks functionality sufficiently completed
X - Create Customer ID/Account
X - Add Contact information to Customer
X - Move Customer into Unit
? - Enter Rent Concessions given
X - Asses Rent Charges
X - Asses Late Charges
X - Asses Security Deposits
X - Receive and record Checks
X - Receive and record Money Orders
X - Receive and record Cash
X - Receive and record ACH Deposits
? - Reverse rent charges (early moveout on prepaid occupancy)
X - Handle NSF checks
X - Assess NSF Fees
X - Determine Lease Paid-Through status
- Report: List of customers overdue
X - Flag unit as overlocked
X - Flag unit as evicting
X - Flag unit as normal status
X - Flag unit as dirty
- Enter notes when communicating with Customer
X - Accept pre-payments
X - Record Customer Move-Out from Unit
X - Record utilization of Security Deposit
X - Record issuing of a refund
- Record Deposit into Petty Cash
- Record Payment from Petty Cash to expenses
X - Record Petty Cash to refund.
X - Write Off Bad Debt
X - Perform a Deposit
X - Close the Books (nightly / weekly, etc)
X - Determine Rents Collected for a given period.

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,20 @@
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
</IfModule>
RewriteEngine on
RewriteRule ^$ webroot/ [L]
# Need this prevent a 400 error without trailing /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) webroot/$1 [L]
</IfModule>
# Need to make sure directories can't be listed, since the rewrite
# rule excludes rewriting when an actual directory is requested
Options -Indexes
# Provide a mechanism for user authentication
AuthType Basic
AuthName "Valley Storage"
AuthUserFile "/home/perki2/valley_storage.pmgr.htpasswd"
Require valid-user

View File

@@ -35,52 +35,458 @@
* @subpackage cake.app
*/
class AppController extends Controller {
var $uses = array('Option', 'Permission');
var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid');
var $components = array('DebugKit.Toolbar');
//var $components = array('DebugKit.Toolbar');
function sideMenuLinks() {
return array(
array('name' => 'Common', 'header' => true),
array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)),
array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')),
array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index')),
array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')),
array('name' => 'Accounts', 'url' => array('controller' => 'accounts', 'action' => 'index')),
array('name' => 'Deposits', 'url' => array('controller' => 'transactions', 'action' => 'deposit')),
array('name' => 'Debug', 'header' => true),
array('name' => 'Un-Nuke', 'url' => '#', 'htmlAttributes' =>
array('onclick' => '$(".pr-section").show(); return false;')),
array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index')),
array('name' => 'Ledgers', 'url' => array('controller' => 'ledgers', 'action' => 'index')),
//array('name' => 'New Ledgers', 'url' => array('controller' => 'accounts', 'action' => 'newledger')),
//array('name' => 'RESET DATA', 'url' => array('controller' => 'accounts', 'action' => 'reset_data')),
);
var $sidemenu = array('areas' => array('SITE' => false, 'REPORT' => false, 'CONTROLLER' => false, 'ACTION' => false, 'SANDBOX' => false));
var $std_area = 10;
var $admin_area = 20;
var $dev_area = 30;
var $op_area = 40;
var $new_area = 50;
function __construct() {
$this->params['dev'] = false;
$this->params['admin'] = false;
parent::__construct();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: dev/admin()
* - Indicates if the user has dev/admin access
*/
function dev() { return !empty($this->params['dev']); }
function admin() { return !empty($this->params['admin']); }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuAreaVerify
* - Verifies the validity of the sidemenu area/subarea/priority,
* and ensures the class member is set to appropriately handle it.
*/
function sideMenuAreaVerify(&$area, $subarea, $priority = null) {
$area = strtoupper($area);
if (!array_key_exists($area, $this->sidemenu['areas']))
$this->INTERNAL_ERROR("Sidemenu link '{$area}': Unknown");
if ($area == 'SITE')
$name = 'Navigation';
elseif ($area == 'CONTROLLER')
$name = Inflector::humanize($this->params['controller']);
elseif ($area == 'ACTION')
$name = Inflector::humanize(Inflector::singularize($this->params['controller']));
elseif ($area == 'REPORT')
$name = 'Reports';
elseif ($area == 'SANDBOX')
$name = 'Sandbox';
if (empty($this->sidemenu['areas'][$area]))
$this->sidemenu['areas'][$area]
= array('enable' => true, 'name' => $name, 'subareas' => array());
if (empty($subarea))
return;
$subname = $name;
if ($subarea == $this->std_area)
$subname .= '';
elseif ($subarea == $this->op_area)
//$subname .= '-Ops';
$subname = 'Actions';
elseif ($subarea == $this->new_area)
//$subname .= '-New';
$subname = 'Creation';
elseif ($subarea == $this->admin_area)
$subname .= '-Admin';
elseif ($subarea == $this->dev_area)
$subname .= '-Dev';
else
$subname .= '-' . $subarea;
if (empty($this->sidemenu['areas'][$area]['subareas'][$subarea]))
$this->sidemenu['areas'][$area]['subareas'][$subarea]
= array('enable' => true, 'name' => $subname, 'priorities' => array());
if (empty($priority))
return;
if (empty($this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority]))
$this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority]
= array();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuAreaName
* - Sets the name of the sidemenu area/subarea
*/
function sideMenuAreaName($name, $area, $subarea = null) {
$this->sideMenuAreaVerify($area, $subarea);
if (empty($subarea))
$this->sidemenu['areas'][$area]['name'] = $name;
else
$this->sidemenu['areas'][$area]['subareas'][$subarea]['name'] = $name;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuAreaActivate
* - Sets the selected area/subarea to be active when the
* page is first loaded.
*/
function sideMenuAreaActivate($area, $subarea = null) {
$this->sidemenu['active'] = compact('area', 'subarea');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuEnable
* - Enables/Disables an area or subarea of the sidemenu
*/
function sideMenuEnable($area, $subarea = null, $enable = true) {
$this->sideMenuAreaVerify($area, $subarea);
if (isset($subarea))
$this->sidemenu['areas'][$area]['subareas'][$subarea]['enable'] = $enable;
else
$this->sidemenu['areas'][$area]['enable'] = $enable;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addSideMenuLink
* - Adds another link to the sidemenu area/subarea/priority
*/
function addSideMenuLink($name, $url, $extra, $area, $subarea = null, $priority = 10) {
if (empty($subarea))
$subarea = $this->std_area;
$this->sideMenuAreaVerify($area, $subarea);
$this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority][]
= array('name' => $name, 'url' => $url) + (empty($extra) ? array() : $extra);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addDefaultSideMenuLinks
* - Adds the standard links present on all generated pages
*/
function addDefaultSideMenuLinks() {
$this->addSideMenuLink('Site Map',
array('controller' => 'maps', 'action' => 'view', 1), null,
'SITE');
$this->addSideMenuLink('Unit Sizes',
array('controller' => 'unit_sizes', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Units',
array('controller' => 'units', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Locks',
array('controller' => 'locks', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Leases',
array('controller' => 'leases', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Customers',
array('controller' => 'customers', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Deposits',
array('controller' => 'transactions', 'action' => 'deposit'), null,
'SITE');
$this->addSideMenuLink('Accounts',
array('controller' => 'accounts', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Contacts',
array('controller' => 'contacts', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Ledgers',
array('controller' => 'ledgers', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Tenders',
array('controller' => 'tenders', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Transactions',
array('controller' => 'transactions', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Ldgr Entries',
array('controller' => 'ledger_entries', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Stmt Entries',
array('controller' => 'statement_entries', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Un-Nuke',
'#', array('htmlAttributes' =>
array('onclick' => '$(".pr-section").show(); return false;')),
'SITE', $this->dev_area);
$this->addSideMenuLink('New Ledgers',
array('controller' => 'accounts', 'action' => 'newledger'), null,
'SITE', $this->dev_area);
//array('name' => 'RESET DATA', array('controller' => 'accounts', 'action' => 'reset_data'));
$this->addSideMenuLink('New Receipt',
array('controller' => 'customers', 'action' => 'receipt'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('New Invoice',
array('controller' => 'leases', 'action' => 'invoice'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('Move-In',
array('controller' => 'customers', 'action' => 'move_in'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('Move-Out',
array('controller' => 'leases', 'action' => 'move_out'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('New Deposit',
array('controller' => 'tenders', 'action' => 'deposit'), null,
'SITE', $this->op_area);
if ($this->admin())
$this->addSideMenuLink('Assess Charges',
array('controller' => 'leases', 'action' => 'assess_all'), null,
'SITE', $this->op_area);
if ($this->admin()) {
$acct = new Account;
$this->addSideMenuLink('Collected Rent',
array('controller' => 'accounts',
'action' => 'collected',
$acct->rentAccountID()), null,
'REPORT');
$this->addSideMenuLink('Unpaid Charges',
array('controller' => 'statement_entries', 'action' => 'unpaid'), null,
'REPORT');
$this->addSideMenuLink('Unit Summary',
array('controller' => 'units', 'action' => 'overview'), null,
'REPORT');
$this->addSideMenuLink('Lease Up',
array('controller' => 'leases', 'action' => 'overview'), null,
'REPORT');
/* $this->addSideMenuLink('Monthly Income', */
/* array('controller' => 'statement_entries', 'action' => 'incomebymonth'), null, */
/* 'REPORT'); */
/* $this->addSideMenuLink('Monthly Expenses', */
/* array('controller' => 'statement_entries', 'action' => 'expensebymonth'), null, */
/* 'REPORT'); */
/* $this->addSideMenuLink('Quickbook Invoice', */
/* array('controller' => 'statement_entries', 'action' => 'incomebymonth', 4, 1), null, */
/* 'REPORT'); */
/* $this->addSideMenuLink('Quickbook Credits', */
/* array('controller' => 'statement_entries', 'action' => 'expensebymonth', 4, 0), null, */
/* 'REPORT'); */
$this->addSideMenuLink('Monthly Income',
array('controller' => 'statement_entries', 'action' => 'netbymonth'), null,
'REPORT');
}
else {
$this->sideMenuEnable('REPORT', null, false);
}
$url_components = array('plugin', 'controller', 'action', 'named');
if (devbox()) {
/* $sources = ConnectionManager::sourceList(); */
/* $db = ConnectionManager::getDataSource($sources[0])->config['database']; */
/* $this->sideMenuAreaName($db, 'SANDBOX', $this->std_area); */
$this->sideMenuAreaName('DevBox', 'SANDBOX', $this->std_area);
$this->addSideMenuLink('Rebuild DevBox',
array('controller' => 'util', 'action' => 'rebuild_devbox'), null,
'SANDBOX');
}
elseif (sandbox()) {
$this->addSideMenuLink('Rebuild Sandbox',
array('controller' => 'util', 'action' => 'rebuild_sandbox'), null,
'SANDBOX');
$this->addSideMenuLink('Leave Sandbox',
array('sand_route' => false)
+ array_intersect_key($this->params, array_flip($url_components))
+ $this->params['pass'],
null, 'SANDBOX');
}
else {
$this->addSideMenuLink('Enter Sandbox',
array('sand_route' => true)
+ array_intersect_key($this->params, array_flip($url_components))
+ $this->params['pass'],
null, 'SANDBOX');
}
// REVISIT <AP>: 20090824
// Depending on preference, we may put this into the gridView
// function, making the links available only when navigating.
$this->addGridViewSideMenuLinks();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* virtual: addGridViewSideMenuLinks
* - Adds the grid view specific navigation links, if overridden.
*/
function addGridViewSideMenuLinks() {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* hook: beforeFilter
* - Called just before the action function
*/
function beforeFilter() {
$this->params['user'] = $this->Permission->User->currentUser();
$this->params['admin'] = $this->Option->enabled('admin');
$this->params['dev'] = devbox();
if ($this->dev() && !$this->Option->enabled('dev'))
$this->redirect("/");
if (!$this->dev())
Configure::write('debug', '0');
$this->addDefaultSideMenuLinks();
//$this->sideMenuEnable('SITE', $this->op_area, false);
foreach ($this->sidemenu['areas'] AS $area_name => $area) {
if (!$this->dev())
$this->sideMenuEnable($area_name, $this->dev_area, false);
if (!$this->admin())
$this->sideMenuEnable($area_name, $this->admin_area, false);
}
$this->authorize("controller.{$this->params['controller']}");
$this->authorize("action.{$this->params['controller']}.{$this->params['action']}");
$this->log('----------------------------------------------------------------------', 'request');
$this->log('----------------------------------------------------------------------', 'request');
$this->log($this->params, 'request');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* hook: beforeRender
* - Called just before rendering the page
*/
function beforeRender() {
$this->set('sidemenu', $this->sideMenuLinks());
// Stupid Cake... our constructor sets admin/dev,
// but cake stomps it somewhere along the way
// after constructing the CakeError controller.
if ($this->name === 'CakeError') {
$this->params['dev'] = false;
$this->params['admin'] = false;
}
foreach ($this->sidemenu['areas'] AS $aname => &$area) {
if (empty($area['enable']))
$area = array();
if (empty($area['subareas']))
continue;
ksort($area['subareas']);
foreach ($area['subareas'] AS $sname => &$subarea) {
if (empty($subarea['enable']))
$subarea = array();
if (empty($subarea['priorities']))
continue;
ksort($subarea['priorities']);
foreach ($subarea['priorities'] AS $pname => &$priority) {
if (empty($priority))
unset($subarea['priorities'][$pname]);
}
unset($priority);
if (empty($subarea['priorities']))
unset($area['subareas'][$sname]);
}
unset($subarea);
if (empty($area['subareas']))
unset($this->sidemenu['areas'][$aname]);
}
unset($area);
// Activate a default section (unless already specified)
foreach (array_reverse(array_diff_key($this->sidemenu['areas'], array('SANDBOX'=>1))) AS $area_name => $area) {
if (empty($area))
continue;
if (empty($this->sidemenu['active']) ||
empty($this->sidemenu['areas'][$this->sidemenu['active']['area']]))
$this->sideMenuAreaActivate($area_name);
}
// If generating reports, don't display the controller menu.
// Each report comes from a controller, but there is no need
// to present the controller actions, so remove that section
// from the menu.
if ($this->sidemenu['active']['area'] == 'REPORT')
$this->sideMenuEnable('CONTROLLER', null, false);
//pr($this->sidemenu);
$this->set('sidemenu', $this->sidemenu);
}
function reset_data() {
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
$script = $_SERVER['DOCUMENT_ROOT'] . '/pmgr/build.cmd';
echo "<P>" . date('r') . "\n";
//echo "<P>Script: $script" . "\n";
$db = & $this->Account->getDataSource();
$script .= ' "' . $db->config['database'] . '"';
$script .= ' "' . $db->config['login'] . '"';
$script .= ' "' . $db->config['password'] . '"';
$handle = popen($script . ' 2>&1', 'r');
//echo "<P>Handle: $handle; " . gettype($handle) . "\n";
echo "<P><PRE>\n";
while (($read = fread($handle, 2096))) {
echo $read;
/**************************************************************************
**************************************************************************
**************************************************************************
* override: redirect
*/
function redirect($url, $status = null, $exit = true) {
// OK, since the controller will not be able to
// utilize our overriden url function in AppHelper,
// we'll have to do it manually here.
App::import('Helper', 'Html');
$url = HtmlHelper::url($url, true);
if (headers_sent() ||
($this->dev() && $this->Option->enabled('dev'))) {
// If we've already sent the headers, it's because
// we're debugging, and our debug output has gotten
// out before the redirect. That's probably a good
// thing, as we don't typically want pages to be
// jerked out from under us while trying to read
// the debug output. So, since we can't redirect
// anyway, we may as well go with the flow and just
// render this page instead, using an empty template
$this->set('message',
("Intended redirect:<P><BR>" .
'<A HREF="'.$url.'">'.$url.'</A>'));
echo $this->render('/empty');
if ($exit)
$this->_stop();
}
echo "</PRE>\n";
pclose($handle);
return parent::redirect($url, $status, $exit);
}
@@ -90,8 +496,14 @@ class AppController extends Controller {
* helper: gridView
* - called by derived controllers to create an index listing
*/
function index() {
$names = Inflector::humanize(Inflector::pluralize($this->params['controller']));
$this->gridView('All ' . $names, 'all');
}
function gridView($title, $action = null, $element = null) {
$this->sideMenuEnable('SITE', $this->op_area);
$this->sideMenuAreaActivate('CONTROLLER');
$this->set('title', $title);
// The resulting page will contain a grid, which will
// use ajax to obtain the actual data for this action
@@ -130,6 +542,9 @@ class AppController extends Controller {
// Retreive the appropriate subset of data
$records = $this->gridDataRecords($params, $model, $pagination);
// If subtotaling, figure out the running total before pagination...
$this->gridDataRecordsRunningSubtotal($params, $model, $pagination);
// Post process the records
$this->gridDataPostProcess($params, $model, $records);
@@ -162,16 +577,10 @@ class AppController extends Controller {
}
function gridDataSetup(&$params) {
// Assume we're debugging.
// The actual grid request will set this to false
$debug = true;
// Debug only if requested
$params['debug'] = !empty($this->passedArgs['debug']);
if (isset($this->passedArgs['debug']))
$debug = $this->passedArgs['debug'];
$params['debug'] = $debug;
if ($debug) {
if ($params['debug']) {
ob_start();
}
else {
@@ -234,6 +643,7 @@ class AppController extends Controller {
$xml = preg_replace("/</", "&lt;", $xml);
$xml = preg_replace("/>/", "&gt;", $xml);
echo ("\n<PRE>\n$xml\n</PRE>\n");
$this->render_empty();
}
}
@@ -248,21 +658,21 @@ class AppController extends Controller {
$query = array_intersect_key($this->gridDataCountTableSet($params, $model),
array('link'=>1, 'contain'=>1));
// Conditions for the count
$query['fields'] = array($this->gridDataCountField($params, $model));
// Conditions for the count
$query['conditions'] = $this->gridDataCountConditionSet($params, $model);
// Grouping (which would not be typical)
$query['group'] = $this->gridDataCountGroup($params, $model);
// DEBUG PURPOSES ONLY!
$params['count_query'] = $query;
// Get the number of records prior to pagination
return $this->gridDataCountExecute($params, $model, $query);
}
function gridDataCountExecute(&$params, &$model, $query) {
return $model->find('count', $query);
return $this->gridDataFind($params, $model, 'count', $query);
}
function gridDataCountTables(&$params, &$model) {
@@ -280,6 +690,10 @@ class AppController extends Controller {
array('link'=>1, 'contain'=>1));
}
function gridDataCountField(&$params, &$model) {
return "COUNT(DISTINCT `".$model->alias.'`.`'.$model->primaryKey."`) AS 'count'";
}
function gridDataCountConditions(&$params, &$model) {
// Same conditions for counting as for retreiving
return $this->gridDataConditions($params, $model);
@@ -480,6 +894,9 @@ class AppController extends Controller {
$page = ($params['page'] <= 1) ? 1 : (($params['page'] > $total) ? $total : $params['page']);
$start = $limit * ($page - 1);
// Adjust the limit upward, if multiple pages were requested.
$limit *= empty($params['npage']) ? 1 : $params['npage'];
return compact('record_count', 'limit', 'page', 'start', 'total');
}
@@ -511,14 +928,11 @@ class AppController extends Controller {
isset($params['sidx']) ? $params['sidx'] : null,
isset($params['sord']) ? $params['sord'] : null);
// DEBUG PURPOSES ONLY!
$params['query'] = $query;
return $this->gridDataRecordsExecute($params, $model, $query);
}
function gridDataRecordsExecute(&$params, &$model, $query) {
return $model->find('all', $query);
return $this->gridDataFind($params, $model, 'all', $query);
}
function gridDataTables(&$params, &$model) {
@@ -560,12 +974,24 @@ class AppController extends Controller {
'value' => $params['filtValue']);
}
// Translate a user specified date into the SQL date format
foreach ($searches AS &$search) {
if (preg_match('/(_date|stamp)$/', $search['field']) &&
preg_match('%(\d{1,2})[-/](\d{1,2})[-/](\d{2,4})%', $search['value'], $matches)) {
$search['value'] = sprintf('%04d%02d%02d',
$matches[3] + ($matches[3] < 50 ? 2000 : ($matches[3] < 100 ? 1900 : 0)),
$matches[2], $matches[1]);
}
}
unset($search);
$ops = array('eq' => array('op' => null, 'pre' => '', 'post' => ''),
'ne' => array('op' => '<>', 'pre' => '', 'post' => ''),
'lt' => array('op' => '<', 'pre' => '', 'post' => ''),
'le' => array('op' => '<=', 'pre' => '', 'post' => ''),
'gt' => array('op' => '>', 'pre' => '', 'post' => ''),
'ge' => array('op' => '>=', 'pre' => '', 'post' => ''),
'in' => array('op' => 'IN', 'pre' => '(', 'post' => ')'),
'bw' => array('op' => 'LIKE', 'pre' => '', 'post' => '%'),
'ew' => array('op' => 'LIKE', 'pre' => '%', 'post' => ''),
'cn' => array('op' => 'LIKE', 'pre' => '%', 'post' => '%'),
@@ -615,6 +1041,60 @@ class AppController extends Controller {
return $start . ', ' . $limit;
}
function gridDataFind(&$params, &$model, $type, $query) {
if ($params['debug'])
$params['queries'][] = compact('type', 'query');
return $model->find($type, $query);
}
function gridDataRecordsRunningSubtotal(&$params, $model, $pagination) {
// REVISIT <AP>: 20090722
// Horrible solution to something that should be done
// in SQL. Doesn't really work, but for a grid that contains
// ALL records, and is sorted on the correct field, it does
// actually work.
//
// If this function worked correctly, this mechanism would also
// work for grids that did not contain ALL records.
$subtotals = array();
foreach ($params['post']['fields'] AS $field) {
if (preg_match('/subtotal-(.*)$/', $field, $matches))
$subtotals[] = array('field' => $matches[1],
'name' => $field,
'amount' => 0);
}
// This part, if functioning, should do a sub-total off all records
// that are not part of the grid, instead of starting at zero, so that
// the totals come out correctly for the each record entry.
/* $pagination['start'] = $pagination['start'] + $pagination['limit']; */
/* $pagination['limit'] = 10000000; */
/* // Retreive the appropriate subset of data */
/* $params_copy = $params; */
/* $records = $this->gridDataRecords($params_copy, $model, $pagination); */
/* foreach ($records AS &$record) { */
/* foreach ($subtotals AS &$subtotal) { */
/* $field = $subtotal['field']; */
/* if (preg_match("/\./", $field)) { */
/* list($tbl, $col) = explode(".", $field); */
/* $record['subtotal-'.$tbl][$col] = */
/* ($subtotal['amount'] += $record[$tbl][$col]); */
/* } */
/* else { */
/* $record[$model->alias]['subtotal-'.$field] = */
/* ($subtotal['amount'] += $record[$model->alias][$field]); */
/* } */
/* } */
/* } */
$params['subtotals'] = $subtotals;
}
/**************************************************************************
**************************************************************************
@@ -635,6 +1115,7 @@ class AppController extends Controller {
$this->gridDataPostProcessLinks($params, $model, $records, array());
// DEBUG PURPOSES ONLY!
//if ($params['debug'])
//$params['records'] = $records;
}
@@ -653,7 +1134,7 @@ class AppController extends Controller {
foreach ($records AS &$record) {
// Add the calculated fields (if any), to the model fields
if (isset($record[0])) {
$record[$model_alias] += $record[0];
$record[$model_alias] = $record[0] + $record[$model_alias];
unset($record[0]);
}
}
@@ -664,15 +1145,11 @@ class AppController extends Controller {
// REVISIT <AP>: 20090722
// Horrible solution to something that should be done
// in SQL. But, it works for now, so what the heck...
// in SQL. Doesn't really work, but for a grid that contains
// ALL records, and is sorted on the correct field, it does
// actually work.
$subtotals = array();
foreach ($params['post']['fields'] AS $field) {
if (preg_match('/subtotal-(.*)$/', $field, $matches))
$subtotals[] = array('field' => $matches[1],
'name' => $field,
'amount' => 0);
}
$subtotals = $params['subtotals'];
foreach ($records AS &$record) {
foreach ($subtotals AS &$subtotal) {
@@ -695,9 +1172,12 @@ class AppController extends Controller {
if (isset($params['post']['nolinks']))
return;
App::import('Helper', 'Html');
foreach ($links AS $table => $fields) {
$special = array('controller', 'id');
$special = array('controller', 'action', 'id');
$controller = Inflector::pluralize(Inflector::underscore($table));
$action = 'view';
$id = 'id';
extract(array_intersect_key($fields, array_flip($special)));
foreach ($records AS &$record) {
@@ -709,12 +1189,13 @@ class AppController extends Controller {
continue;
// DEBUG PURPOSES ONLY!
//if ($params['debug'])
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
$record[$table][$field] =
'<A HREF="' .
Router::url(array('controller' => $controller,
'action' => 'view',
$record[$table][$id])) .
HtmlHelper::url(array('controller' => $controller,
'action' => $action,
$record[$table][$id])) .
'">' .
$record[$table][$field] .
'</A>';
@@ -739,9 +1220,8 @@ class AppController extends Controller {
}
function gridDataOutputHeader(&$params, &$model) {
if (!$params['debug']) {
if (!$params['debug'])
header("Content-type: text/xml;charset=utf-8");
}
}
function gridDataOutputXMLHeader(&$params, &$model) {
@@ -757,7 +1237,8 @@ class AppController extends Controller {
}
function gridDataOutputSummary(&$params, &$model, $pagination) {
echo " <params><![CDATA[\n" . print_r($params, true) . "\n]]></params>\n";
if ($params['debug'])
echo " <params><![CDATA[\n" . print_r($params, true) . "\n]]></params>\n";
echo " <page>{$pagination['page']}</page>\n";
echo " <total>{$pagination['total']}</total>\n";
echo " <records>{$pagination['record_count']}</records>\n";
@@ -798,11 +1279,33 @@ class AppController extends Controller {
function gridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
// be sure to put text data in CDATA
if (preg_match("/^\d*$/", $data))
if (preg_match("/^[\d.]*$/", $data))
echo " <cell>$data</cell>\n";
else
echo " <cell><![CDATA[$data]]></cell>\n";
}
function authorize($name) {
if ($this->Permission->deny($name))
$this->UNAUTHORIZED("Unauthorized: $name");
}
function UNAUTHORIZED($msg) {
//$this->redirect('controller' => '???', 'action' => 'login');
//$this->render('/unauthorized');
$this->set('message', '<H2>' . $msg . '</H2>');
$this->render_empty();
}
function INTERNAL_ERROR($msg, $depth = 0) {
INTERNAL_ERROR($msg, false, $depth+1);
$this->render_empty();
}
function render_empty() {
echo $this->render('/empty');
$this->_stop();
}
}
?>

View File

@@ -37,5 +37,14 @@ App::import('Core', 'Helper');
* @subpackage cake.cake
*/
class AppHelper extends Helper {
function url($url = null, $full = false) {
foreach(array('sand_route', 'dev_route') AS $mod) {
if (isset($this->params[$mod]) && is_array($url) && !isset($url[$mod]))
$url[$mod] = $this->params[$mod];
}
return parent::url($url, $full);
}
}
?>

View File

@@ -42,6 +42,10 @@ class AppModel extends Model {
var $useNullForEmpty = true;
var $formatDateFields = true;
// Loaded related models with no association
var $knows = array();
var $app_knows = array('Option');
// Default Log Level, if not specified at the function level
var $default_log_level = 5;
@@ -58,16 +62,35 @@ class AppModel extends Model {
var $max_log_level;
// REVISIT <AP>: 20090730
// Why is this constructor crashing?
// Clearly it's in some sort of infinite
// loop, but it seems the correct way
// to have a constructor call the parent...
/**************************************************************************
**************************************************************************
**************************************************************************
* function: __construct
*/
function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
$this->knows = array_merge($this->app_knows, $this->knows);
//$this->pr(1, array('knows' => $this->knows));
foreach ($this->knows as $alias => $modelName) {
if (is_numeric($alias)) {
$alias = $modelName;
}
// Don't overwrite any existing alias
if (!empty($this->{$alias}) || get_class($this) == $alias)
continue;
$model = array('class' => $modelName, 'alias' => $alias);
if (PHP5) {
$this->{$alias} = ClassRegistry::init($model);
} else {
$this->{$alias} =& ClassRegistry::init($model);
}
}
}
/* function __construct() { */
/* parent::__construct(); */
/* $this->prClassLevel(5, 'Model'); */
/* } */
/**************************************************************************
**************************************************************************
@@ -81,7 +104,8 @@ class AppModel extends Model {
$caller = array_shift($trace);
$caller = array_shift($trace);
if (empty($class))
$class = $caller['class'];
$class = get_class($this);
$this->pr(50, compact('class', 'level'));
$this->class_log_level[$class] = $level;
}
@@ -90,9 +114,10 @@ class AppModel extends Model {
$caller = array_shift($trace);
$caller = array_shift($trace);
if (empty($class))
$class = $caller['class'];
$class = get_class($this);
if (empty($function))
$function = $caller['function'];
$this->pr(50, compact('class', 'function', 'level'));
$this->function_log_level["{$class}-{$function}"] = $level;
}
@@ -280,7 +305,9 @@ class AppModel extends Model {
if (preg_match("/^_/", $name) && !$all)
unset($vars[$name]);
}
pr($vars);
//$vars['class'] = get_class_vars(get_class($this));
$this->pr(1, $vars);
}
@@ -402,6 +429,10 @@ class AppModel extends Model {
}
function filter_null($array) {
return array_diff_key($array, array_filter($array, 'is_null'));
}
function recursive_array_replace($find, $replace, &$data) {
if (!isset($data))
return;
@@ -476,4 +507,12 @@ class AppModel extends Model {
return date('Y-m-d', strtotime($dateString));
}
function INTERNAL_ERROR($msg, $depth = 0, $force_stop = false) {
INTERNAL_ERROR($msg, $force_stop, $depth+1);
echo $this->requestAction(array('controller' => 'util',
'action' => 'render_empty'),
array('return', 'bare' => false)
);
$this->_stop();
}
}

View File

@@ -32,16 +32,48 @@
*
*/
function INTERNAL_ERROR($message) {
echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">';
echo '<H1 style="margin-bottom:0.2em">INTERNAL ERROR:</H1>';
echo '<H2 style="margin-top:0; margin-left:1.5em">' . $message . '</H2>';
echo '<H4>This error was not caused by anything that you did wrong.';
echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>';
function _box($type) {
static $box = array('type' => null, 'test' => array());
if (!isset($box['type']) && !isset($box['test'][$type])) {
$r = Router::requestRoute();
/* if (!preg_match("/gridData/", $_SERVER['REQUEST_URI'])) { */
/* print("<PRE>Route:\n");print_r($r);print("\n</PRE>\n"); */
/* } */
$box['test'][$type] = !empty($r[3]["${type}_route"]);
if ($box['test'][$type])
$box['type'] = $type;
}
return $box['type'] == $type;
}
function sandbox() { return _box('sand'); }
function devbox() { return _box('dev'); }
function server_request_var($var) {
if (preg_match("/^HTTP_ACCEPT|REMOTE_PORT/", $var))
return false;
return (preg_match("/^HTTP|REQUEST|REMOTE/", $var));
}
function INTERNAL_ERROR($message, $exit = true, $drop = 0) {
$O = new Object();
for ($i=0; $i<3; ++$i) {
$O->log(str_repeat("\\", 80));
$O->log(str_repeat("/", 80));
}
$O->log("INTERNAL ERROR: $message");
echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">' . "\n";
echo '<H1 style="color:#000; margin-bottom:0.2em; font-size:2em;">INTERNAL ERROR:</H1>' . "\n";
echo '<H2 style="color:#000; margin-top:0; margin-left:1.5em; font-size:1.5em">' . $message . '</H2>' . "\n";
echo '<H4 style="color:#000;">This error was not caused by anything that you did wrong.' . "\n";
echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>' . "\n";
// Print out the entire stack trace
echo "<HR>Stack Trace:<OL>";
$trace = debug_backtrace(false);
$O->log(str_repeat("-", 30));
$O->log("Stack:");
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nStack Trace:\n";
echo '<OL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
$trace = array_slice(debug_backtrace(false), $drop);
for ($i = 0; $i < count($trace); ++$i) {
$bline = $trace[$i]['line'];
$bfile = $trace[$i]['file'];
@@ -56,12 +88,40 @@ function INTERNAL_ERROR($message) {
$bclas = null;
}
$O->log(" $bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")");
echo("<LI>$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")</LI>\n");
}
echo '</OL>';
echo "</OL>\n";
$O->log(str_repeat("-", 30));
$O->log("HTTP Request:");
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nHTTP Request:\n";
echo '<UL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
foreach($_REQUEST AS $k => $v) {
$O->log(sprintf(" %-20s => %s", $k, $v));
echo("<LI>$k =&gt; $v</LI>\n");
}
echo "</UL>\n";
$O->log(str_repeat("-", 30));
$O->log("Server:");
$SRV = array_intersect_key($_SERVER, array_flip(array_filter(array_keys($_SERVER), 'server_request_var')));
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nServer:\n";
echo '<UL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
foreach($SRV AS $k => $v) {
if ($k == 'REQUEST_TIME')
$v = date('c', $v);
$O->log(sprintf(" %-20s => %s", $k, $v));
echo("<LI>$k =&gt; $v</LI>\n");
}
echo "</UL>\n";
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\n";
echo date('c') . "<BR>\n";
echo '</DIV>';
die();
if ($exit)
die();
}
/**

View File

@@ -117,7 +117,7 @@
/**
* The name of CakePHP's session cookie.
*/
Configure::write('Session.cookie', 'CAKEPHP');
Configure::write('Session.cookie', 'PMGR');
/**
* Session time out time (in seconds).
* Actual value depends on 'Security.level' setting.

View File

@@ -5,10 +5,17 @@ class DATABASE_CONFIG {
'driver' => 'mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'pmgr',
'password' => 'pmgruser',
'database' => 'property_manager',
'prefix' => 'pmgr_',
'login' => 'perki2_pmgruser',
'password' => 'pmgrauth',
'database' => 'perki2_pmgr',
'prefix' => '',
);
function __construct() {
if (devbox())
$this->default['database'] = 'perki2_pmgr_dev';
if (sandbox())
$this->default['database'] = 'perki2_pmgr_sand';
}
}
?>

View File

@@ -27,11 +27,49 @@
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
$default_path = array('controller' => 'maps', 'action' => 'view', '1');
/**
* Here, we are connecting '/' (base path) to our site map.
* It's hardcoded to map #1, but at some point we'll implement
* a login mechanism and the default path will be to log on instead.
*/
Router::connect('/', array('controller' => 'maps', 'action' => 'view', '1'));
Router::connect('/', $default_path);
/*
* Route for sandbox functionality
*/
Router::connect('/sand',
array('sand_route' => true) + $default_path);
Router::connect('/sand/:controller/:action/*',
array('sand_route' => true, 'action' => null));
/* Unfortunately, for some reason we need an extra route to solve
* a bug with form generation. When $this->data is set by the
* controller, and a URL is generated by the FormHelper, this
* route is required to ensure the form action is correct. An
* example of a broken page is for /customers/edit/XX. It appears
* the page location uses the route above, it's only URL generation
* that seems to be broken.
*/
Router::connect('/sand/:controller/:action/:id/*',
array('sand_route' => true,'action' => null, 'id'=>null));
/*
* Route for developement functionality
*/
Router::connect('/dev',
array('dev_route' => true) + $default_path);
Router::connect('/dev/:controller/:action/*',
array('dev_route' => true, 'action' => null));
/* Unfortunately, for some reason we need an extra route to solve
* a bug with form generation. When $this->data is set by the
* controller, and a URL is generated by the FormHelper, this
* route is required to ensure the form action is correct. An
* example of a broken page is for /customers/edit/XX. It appears
* the page location uses the route above, it's only URL generation
* that seems to be broken.
*/
Router::connect('/dev/:controller/:action/:id/*',
array('dev_route' => true,'action' => null, 'id'=>null));
?>

View File

@@ -2,30 +2,38 @@
class AccountsController extends AppController {
var $uses = array('Account', 'LedgerEntry');
var $sidemenu_links =
array(array('name' => 'Accounts', 'header' => true),
array('name' => 'All', 'url' => array('controller' => 'accounts', 'action' => 'all')),
array('name' => 'Asset', 'url' => array('controller' => 'accounts', 'action' => 'asset')),
array('name' => 'Liability', 'url' => array('controller' => 'accounts', 'action' => 'liability')),
array('name' => 'Equity', 'url' => array('controller' => 'accounts', 'action' => 'equity')),
array('name' => 'Income', 'url' => array('controller' => 'accounts', 'action' => 'income')),
array('name' => 'Expense', 'url' => array('controller' => 'accounts', 'action' => 'expense')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('Asset',
array('controller' => 'accounts', 'action' => 'asset'), null,
'CONTROLLER', $this->admin_area);
$this->addSideMenuLink('Liability',
array('controller' => 'accounts', 'action' => 'liability'), null,
'CONTROLLER', $this->admin_area);
$this->addSideMenuLink('Equity',
array('controller' => 'accounts', 'action' => 'equity'), null,
'CONTROLLER', $this->admin_area);
$this->addSideMenuLink('Income',
array('controller' => 'accounts', 'action' => 'income'), null,
'CONTROLLER', $this->admin_area);
$this->addSideMenuLink('Expense',
array('controller' => 'accounts', 'action' => 'expense'), null,
'CONTROLLER', $this->admin_area);
$this->addSideMenuLink('All',
array('controller' => 'accounts', 'action' => 'all'), null,
'CONTROLLER', $this->admin_area);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -39,7 +47,7 @@ class AccountsController extends AppController {
function equity() { $this->gridView('Equity Accounts'); }
function income() { $this->gridView('Income Accounts'); }
function expense() { $this->gridView('Expense Accounts'); }
function all() { $this->gridView('All Accounts', 'all'); }
function all() { $this->gridView('All Accounts', 'all'); }
/**************************************************************************
@@ -90,6 +98,9 @@ class AccountsController extends AppController {
$conditions[] = array('Account.type' => strtoupper($params['action']));
}
$conditions[] = array('Account.level >=' =>
$this->Permission->level('controller.accounts'));
return $conditions;
}
@@ -139,12 +150,9 @@ class AccountsController extends AppController {
$account = $this->Account->read(null, $id);
$account = $account['Account'];
$payment_accounts = $this->Account->collectableAccounts();
//$payment_accounts[$this->Account->nameToID('Closing')] = 'Closing';
//$payment_accounts[$this->Account->nameToID('Equity')] = 'Equity';
//$payment_accounts[$id] = 'Reversals';
$default_accounts = array_diff_key($this->Account->receiptAccounts(),
array($this->Account->concessionAccountID() => 1));
$accounts = $this->Account->collectableAccounts();
$payment_accounts = $accounts['all'];
$default_accounts = $accounts['default'];
$this->set(compact('payment_accounts', 'default_accounts'));
$title = ($account['name'] . ': Collected Report');
@@ -160,12 +168,6 @@ class AccountsController extends AppController {
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
// Get details about the account and its ledgers (no ledger entries yet)
$account = $this->Account->find
('first',
array('contain' =>
@@ -177,33 +179,32 @@ class AccountsController extends AppController {
array('CloseTransaction' => array
('order' => array('CloseTransaction.stamp' => 'DESC'))),
),
'conditions' => array(array('Account.id' => $id)),
'conditions' => array(array('Account.id' => $id),
array('Account.level >=' =>
$this->Permission->level('controller.accounts')),
),
)
);
// Get all ledger entries of the CURRENT ledger
$entries = $this->Account->ledgerEntries($id);
//pr(compact('entries'));
$account['CurrentLedger']['LedgerEntry'] = $entries;
if (empty($account)) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
// Obtain stats across ALL ledgers for the summary infobox
$stats = $this->Account->stats($id, true);
$stats = $stats['Ledger'];
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'New Ledger', 'url' => array('action' => 'newledger', $id));
$this->sidemenu_links[] =
array('name' => 'Collected', 'url' => array('action' => 'collected', $id));
$this->addSideMenuLink('New Ledger',
array('action' => 'newledger', $id), null,
'ACTION', $this->admin_area);
$this->addSideMenuLink('Collected',
array('action' => 'collected', $id), null,
'ACTION', $this->admin_area);
// Prepare to render
$title = 'Account: ' . $account['Account']['name'];
$this->set(compact('account', 'title', 'stats'));
}
function tst($id) {
//$entries = $this->Account->($id);
pr($entries);
}
}

View File

@@ -2,19 +2,7 @@
class ContactsController 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);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -35,19 +23,34 @@ class ContactsController extends AppController {
* to jqGrid.
*/
function gridDataFilterTablesConfig(&$params, &$model, $table) {
$config = parent::gridDataFilterTablesConfig($params, $model, $table);
// Special case for Customer; We need the Contact/Customer relationship
if ($table == 'Customer')
$config = array('fields' => array('ContactsCustomer.type',
'ContactsCustomer.active'),
'conditions' => array('ContactsCustomer.active' => true),
);
return $config;
}
function gridDataOrder(&$params, &$model, $index, $direction) {
$order = parent::gridDataOrder($params, $model, $index, $direction);
if ($index === 'Contact.last_name') {
$order[] = 'Contact.first_name ' . $direction;
}
if ($index === 'Contact.first_name') {
$order[] = 'Contact.last_name ' . $direction;
}
// After sorting by whatever the user wants, add these
// defaults into the sort mechanism. If we're already
// sorting by one of them, it will only be redundant,
// and should cause no harm (possible a longer query?)
$order[] = 'Contact.last_name ' . $direction;
$order[] = 'Contact.first_name ' . $direction;
return $order;
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Contact'] = array('id');
$links['Contact'] = array('display_name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -78,13 +81,9 @@ class ContactsController extends AppController {
));
// Set up dynamic menu items
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'Edit',
'url' => array('action' => 'edit',
$id));
$this->addSideMenuLink('Edit',
array('action' => 'edit', $id), null,
'ACTION');
// Prepare to render.
$title = 'Contact: ' . $contact['Contact']['display_name'];
@@ -126,8 +125,6 @@ class ContactsController extends AppController {
// Now that the work is done, let the user view the updated contact
$this->redirect(array('action'=>'view', $this->data['Contact']['id']));
//$this->render('/empty');
return;
}
if ($id) {

View File

@@ -1,28 +1,42 @@
<?php
class CustomersController extends AppController {
var $sidemenu_links =
array(array('name' => 'Customers', 'header' => true),
array('name' => 'Current', 'url' => array('controller' => 'customers', 'action' => 'current')),
array('name' => 'Past', 'url' => array('controller' => 'customers', 'action' => 'past')),
array('name' => 'All', 'url' => array('controller' => 'customers', 'action' => 'all')),
array('name' => 'Add Customer', 'url' => array('controller' => 'customers', 'action' => 'add')),
);
//var $components = array('RequestHandler');
var $components = array('RequestHandler');
// DEBUG FUNCTION ONLY!
// Call without id to update ALL customers
function force_update($id = null) {
$this->Customer->update($id);
$this->redirect(array('action'=>'index'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('Current',
array('controller' => 'customers', 'action' => 'current'), null,
'CONTROLLER');
$this->addSideMenuLink('Past',
array('controller' => 'customers', 'action' => 'past'), null,
'CONTROLLER');
$this->addSideMenuLink('All',
array('controller' => 'customers', 'action' => 'all'), null,
'CONTROLLER');
/* $this->addSideMenuLink('New Customer', */
/* array('controller' => 'customers', 'action' => 'add'), null, */
/* 'CONTROLLER', $this->new_area); */
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -81,19 +95,29 @@ class CustomersController extends AppController {
return $conditions;
}
function gridDataOrder(&$params, &$model, $index, $direction) {
$order = array();
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
function gridDataFilterTablesConfig(&$params, &$model, $table) {
$config = parent::gridDataFilterTablesConfig($params, $model, $table);
if ($index !== 'PrimaryContact.last_name')
$order[] = parent::gridDataOrder($params, $model,
'PrimaryContact.last_name', $direction);
if ($index !== 'PrimaryContact.first_name')
$order[] = parent::gridDataOrder($params, $model,
'PrimaryContact.first_name', $direction);
if ($index !== 'Customer.id')
$order[] = parent::gridDataOrder($params, $model,
'Customer.id', $direction);
// Special case for Contact; We need the Contact/Customer relationship
if ($table == 'Contact')
$config = array('fields' => array('ContactsCustomer.type',
'ContactsCustomer.active'),
'conditions' => array('ContactsCustomer.active' => true),
);
return $config;
}
function gridDataOrder(&$params, &$model, $index, $direction) {
$order = parent::gridDataOrder($params, $model, $index, $direction);
// After sorting by whatever the user wants, add these
// defaults into the sort mechanism. If we're already
// sorting by one of them, it will only be redundant,
// and should cause no harm (possible a longer query?)
$order[] = 'PrimaryContact.last_name ' . $direction;
$order[] = 'PrimaryContact.first_name ' . $direction;
$order[] = 'Customer.id ' . $direction;
return $order;
}
@@ -111,14 +135,18 @@ class CustomersController extends AppController {
* - Sets up the move-in page for the given customer.
*/
function move_in($id = null) {
function move_in($id = null, $unit_id = null) {
$customer = array();
$unit = array();
if (isset($id)) {
if (!empty($id)) {
$this->Customer->recursive = -1;
$customer = current($this->Customer->read(null, $id));
}
if (!empty($unit_id)) {
$this->Customer->Lease->Unit->recursive = -1;
$unit = current($this->Customer->Lease->Unit->read(null, $unit_id));
}
$this->set(compact('customer', 'unit'));
$title = 'Customer Move-In';
@@ -219,52 +247,76 @@ class CustomersController extends AppController {
$outstanding_deposit = $this->Customer->securityDepositBalance($id);
// Figure out if this customer has any non-closed leases
$show_moveout = false;
$show_payment = false;
$show_moveout = false; $moveout_lease_id = null;
$show_payment = false; $payment_lease_id = null;
foreach ($customer['Lease'] AS $lease) {
if (!isset($lease['close_date']))
if (!isset($lease['close_date'])) {
if ($show_payment)
$payment_lease_id = null;
else
$payment_lease_id = $lease['id'];
$show_payment = true;
if (!isset($lease['moveout_date']))
}
if (!isset($lease['moveout_date'])) {
if ($show_moveout)
$moveout_lease_id = null;
else
$moveout_lease_id = $lease['id'];
$show_moveout = true;
}
}
// Set up dynamic menu items
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'Edit',
'url' => array('action' => 'edit',
$id));
$this->sidemenu_links[] =
array('name' => 'Move-In',
'url' => array('action' => 'move_in',
$id));
/* if ($show_moveout) { */
/* $this->sidemenu_links[] = */
/* array('name' => 'Move-Out', */
/* 'url' => array('action' => 'move_out', */
/* $id)); */
/* } */
if ($show_payment || $outstanding_balance > 0)
$this->sidemenu_links[] =
array('name' => 'New Receipt',
'url' => array('action' => 'receipt',
$id));
$this->addSideMenuLink('New Receipt',
array('action' => 'receipt', $id), null,
'ACTION');
if ($show_payment) {
/* $ids = $this->Customer->leaseIds($id, true); */
/* if (count($ids) == 1) */
/* $lease_id = $ids[0]; */
/* else */
/* $lease_id = null; */
$this->addSideMenuLink('New Invoice',
array('controller' => 'leases',
'action' => 'invoice',
$payment_lease_id), null,
'ACTION');
}
$this->addSideMenuLink('Move-In',
array('action' => 'move_in', $id), null,
'ACTION');
if ($show_moveout) {
$this->addSideMenuLink('Move-Out',
array('controller' => 'leases',
'action' => 'move_out',
$moveout_lease_id), null,
'ACTION');
}
if (!$show_moveout && $outstanding_balance > 0)
$this->sidemenu_links[] =
array('name' => 'Write-Off',
'url' => array('action' => 'bad_debt',
$id));
$this->addSideMenuLink('Write-Off',
array('action' => 'bad_debt', $id), null,
'ACTION');
if ($outstanding_balance < 0)
$this->sidemenu_links[] =
array('name' => 'Issue Refund',
'url' => array('action' => 'refund', $id));
$this->addSideMenuLink('Issue Refund',
array('action' => 'refund', $id), null,
'ACTION');
$this->addSideMenuLink('Edit',
array('action' => 'edit', $id), null,
'ACTION');
if ($this->admin())
$this->addSideMenuLink('Merge',
array('action' => 'merge', $id), null,
'ACTION');
// Prepare to render.
$title = 'Customer: ' . $customer['Customer']['name'];
@@ -287,23 +339,20 @@ class CustomersController extends AppController {
if (isset($this->params['form']['cancel'])) {
if (isset($this->data['Customer']['id']))
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
else
$this->redirect(array('action'=>'index'));
return;
$this->redirect(array('action'=>'index'));
}
// Make sure we have at least one contact
if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) {
$this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true);
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
return;
}
// Make sure there is a primary contact
if (!isset($this->data['Customer']['primary_contact_entry'])) {
$this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true);
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
return;
}
// Go through each customer and strip the bogus ID if new
@@ -320,21 +369,56 @@ class CustomersController extends AppController {
pr("CUSTOMER SAVE FAILED");
}
// If existing customer, then view it. Otherwise, since
// this is a new customer, go to the move in screen.
// If existing customer, then view it.
if ($this->data['Customer']['id'])
$this->redirect(array('action'=>'view', $this->Customer->id));
else
$this->redirect(array('action'=>'move_in', $this->Customer->id));
// For debugging, only if the redirects above have been
// commented out, otherwise this section isn't reached.
$this->render('/empty');
return;
// Since this is a new customer, go to the move in screen.
// First set the move-in unit id, if there is one, ...
if (empty($this->data['movein']['Unit']['id']))
$unit_id = null;
else
$unit_id = $this->data['movein']['Unit']['id'];
// ... then redirect
$this->redirect(array('action'=>'move_in',
$this->Customer->id,
$unit_id,
));
}
if ($id) {
$this->data = $this->Customer->details($id);
// REVISIT <AP>: 20090816
// This should never need to be done by a controller.
// However, until things stabilize, this gives the
// user a way to update any cached items on the
// customer, by just clicking Edit then Cancel.
$this->Customer->update($id);
// Get details on this customer, its contacts and leases
$customer = $this->Customer->find
('first', array
('contain' => array
(// Models
'Contact' =>
array('order' => array('Contact.display_name'),
// Models
'ContactPhone',
'ContactEmail',
'ContactAddress',
),
'Lease' =>
array('Unit' =>
array('order' => array('sort_order'),
'fields' => array('id', 'name'),
),
),
),
'conditions' => array('Customer.id' => $id),
));
$this->data = $customer;
$title = 'Customer: ' . $this->data['Customer']['name'] . " : Edit";
}
else {
@@ -363,10 +447,46 @@ class CustomersController extends AppController {
* - Add a new customer
*/
function add() {
function add($unit_id = null) {
$this->set('movein', array('Unit' => array('id' => $unit_id)));
$this->edit();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: merge
* - Merges two customers
*/
function merge($id = null) {
if ($id) {
$this->Customer->recursive = -1;
$customer = $this->Customer->read(null, $id);
$customer = $customer['Customer'];
if (empty($customer))
$this->INTERNAL_ERROR("Customer $id does not exist");
$this->set('dst_customer', $customer);
$this->set('dst_name', $customer['name']);
$this->set('dst_id', $id);
}
else {
$this->INTERNAL_ERROR("Merge called with invalid customer");
}
}
function mergeFinal() {
if (!$this->RequestHandler->isPost()) {
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
return;
}
$post = $this->params['form'];
$this->Customer->merge($post['dst-id'], $post['src-id'],
unserialize($post['contact-ids']));
$this->redirect(array('action'=>'view', $post['dst-id']));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -379,20 +499,9 @@ class CustomersController extends AppController {
$this->Customer->recursive = -1;
$customer = $this->Customer->read(null, $id);
$customer = $customer['Customer'];
$unreconciled = $this->Customer->unreconciledCharges($id);
//pr($unreconciled);
$charges = $unreconciled['entries'];
$stats = $unreconciled['summary']['Charge'];
// Kludge until we update receipt to have the unpaid
// charges grid generated from a dynamic query instead
// of simply pre-providing the list of charge IDs
foreach ($charges AS &$charge)
$charge['id'] = $charge['StatementEntry']['id'];
}
else {
$customer = null;
$charges = array();
$stats = array('balance' => 0);
}
$TT = new TenderType();
@@ -401,7 +510,7 @@ class CustomersController extends AppController {
$this->set(compact('payment_types', 'default_type'));
$title = ($customer['name'] . ': Receipt Entry');
$this->set(compact('customer', 'charges', 'stats', 'title'));
$this->set(compact('customer', 'title'));
}
@@ -472,50 +581,4 @@ class CustomersController extends AppController {
$this->render('/transactions/bad_debt');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: unreconciled
* - returns the list of unreconciled entries
*/
function unreconciled($id) {
//$this->layout = 'ajax';
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
header("Content-type: text/xml;charset=utf-8");
App::import('Helper', 'Xml');
$xml = new XmlHelper();
// Find the unreconciled entries, then manipulate the structure
// slightly to accomodate the format necessary for XML Helper.
$unreconciled = $this->Customer->unreconciledCharges($id);
foreach ($unreconciled['entries'] AS &$entry)
$entry = array_intersect_key($entry['StatementEntry'],
array('id'=>1));
$unreconciled = array('entries' =>
array('entry' => $unreconciled['entries'],
'balance' => $unreconciled['summary']['balance']));
// XML Helper will dump an empty tag if the array is empty
if (empty($unreconciled['entries']['entry']))
unset($unreconciled['entries']['entry']);
/* pr(compact('unreconciled')); */
/* echo htmlspecialchars($xml->serialize($unreconciled)); */
/* $this->render('/fake'); */
$opts = array();
//$opts['format'] = 'tags';
echo $xml->header();
echo $xml->serialize($unreconciled, $opts);
}
}

View File

@@ -2,20 +2,7 @@
class DoubleEntriesController 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);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -36,6 +23,34 @@ class DoubleEntriesController extends AppController {
'conditions' => array('DoubleEntry.id' => $id),
));
$entry += $this->DoubleEntry->DebitEntry->Transaction->find
('first',
array('contain' => false,
'conditions' => array('id' => $entry['DebitEntry']['transaction_id']),
));
$entry += $this->DoubleEntry->DebitEntry->find
('first',
array('contain' => array('Ledger' => array('Account')),
'conditions' => array('DebitEntry.id' => $entry['DebitEntry']['id']),
));
$entry['Ledger']['link'] =
$entry['Ledger']['Account']['level'] >=
$this->Permission->level('controller.accounts');
$entry['DebitLedger'] = $entry['Ledger'];
unset($entry['Ledger']);
$entry += $this->DoubleEntry->CreditEntry->find
('first',
array('contain' => array('Ledger' => array('Account')),
'conditions' => array('CreditEntry.id' => $entry['CreditEntry']['id']),
));
$entry['Ledger']['link'] =
$entry['Ledger']['Account']['level'] >=
$this->Permission->level('controller.accounts');
$entry['CreditLedger'] = $entry['Ledger'];
unset($entry['Ledger']);
// Prepare to render.
$title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}";
$this->set(compact('entry', 'title'));

View File

@@ -2,25 +2,32 @@
class LeasesController extends AppController {
var $sidemenu_links =
array(array('name' => 'Leases', 'header' => true),
array('name' => 'Active', 'url' => array('controller' => 'leases', 'action' => 'active')),
array('name' => 'Closed', 'url' => array('controller' => 'leases', 'action' => 'closed')),
array('name' => 'All', 'url' => array('controller' => 'leases', 'action' => 'all')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('Active',
array('controller' => 'leases', 'action' => 'active'), null,
'CONTROLLER');
$this->addSideMenuLink('Closed',
array('controller' => 'leases', 'action' => 'closed'), null,
'CONTROLLER');
$this->addSideMenuLink('Delinquent',
array('controller' => 'leases', 'action' => 'delinquent'), null,
'CONTROLLER');
$this->addSideMenuLink('All',
array('controller' => 'leases', 'action' => 'all'), null,
'CONTROLLER');
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -28,10 +35,11 @@ class LeasesController extends AppController {
* - Generate a listing of leases
*/
function index() { $this->all(); }
function active() { $this->gridView('Active Leases'); }
function closed() { $this->gridView('Closed Leases'); }
function all() { $this->gridView('All Leases', 'all'); }
function index() { $this->active(); }
function active() { $this->gridView('Active Leases', 'active'); }
function delinquent() { $this->gridView('Delinquent Leases'); }
function closed() { $this->gridView('Closed Leases'); }
function all() { $this->gridView('All Leases'); }
/**************************************************************************
@@ -63,6 +71,8 @@ class LeasesController extends AppController {
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = ("IF(" . $this->Lease->conditionDelinquent() . "," .
" 'DELINQUENT', 'CURRENT') AS 'status'");
return array_merge($fields,
$this->Lease->StatementEntry->chargeDisbursementFields(true));
}
@@ -73,6 +83,9 @@ class LeasesController extends AppController {
if ($params['action'] === 'active') {
$conditions[] = 'Lease.close_date IS NULL';
}
elseif ($params['action'] === 'delinquent') {
$conditions[] = $this->Lease->conditionDelinquent();
}
elseif ($params['action'] === 'closed') {
$conditions[] = 'Lease.close_date IS NOT NULL';
}
@@ -151,10 +164,6 @@ class LeasesController extends AppController {
// Since this is a new lease, go to the invoice
// screen so we can start assessing charges.
$this->redirect(array('action'=>'invoice', $lid, 'move-in'));
// For debugging, only if the redirect above have been
// commented out, otherwise this section isn't reached.
$this->render('/empty');
}
/**************************************************************************
@@ -167,51 +176,54 @@ class LeasesController extends AppController {
function move_out($id = null) {
if ($this->data) {
// Handle the move out based on the data given
//pr($this->data);
$this->Lease->moveOut($this->data['Lease']['id'],
'VACANT',
$this->data['Lease']['moveout_date'],
//true // Close this lease, if able
false
$this->data['Lease']['moveout_date']
);
$this->redirect($this->data['redirect']);
$lease = $this->Lease->find
('first', array
('contain' => array('Customer.id'),
'conditions' => array(array('Lease.id' => $this->data['Lease']['id'])),
));
$this->redirect(array('controller' => 'customers',
'action' => 'view',
$lease['Customer']['id']));
}
if (!isset($id))
die("Oh Nooooo!!");
if (isset($id)) {
$lease = $this->Lease->find
('first', array
('contain' => array
(// Models
'Unit' =>
array('order' => array('sort_order'),
'fields' => array('id', 'name'),
),
$lease = $this->Lease->find
('first', array
('contain' => array
(// Models
'Unit' =>
array('order' => array('sort_order'),
'fields' => array('id', 'name'),
),
'Customer' =>
array('fields' => array('id', 'name'),
),
),
'Customer' =>
array('fields' => array('id', 'name'),
),
),
'conditions' => array(array('Lease.id' => $id),
array('Lease.close_date' => null),
),
));
$this->set('customer', $lease['Customer']);
$this->set('unit', $lease['Unit']);
$this->set('lease', $lease['Lease']);
'conditions' => array(array('Lease.id' => $id),
array('Lease.close_date' => null),
),
));
$this->set('customer', $lease['Customer']);
$this->set('unit', $lease['Unit']);
$this->set('lease', $lease['Lease']);
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
$lease['Unit']['name'] . ': ' .
$lease['Customer']['name'] . ': Move-Out');
}
else {
$title = 'Move-Out';
}
$redirect = array('controller' => 'leases',
'action' => 'view',
$id);
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
$lease['Unit']['name'] . ': ' .
$lease['Customer']['name'] . ': Prepare Move-Out');
$this->set(compact('title', 'redirect'));
$this->set(compact('title'));
$this->render('/leases/move');
}
@@ -226,8 +238,6 @@ class LeasesController extends AppController {
/* function promote_surplus($id) { */
/* $this->Lease->promoteSurplus($id); */
/* pr("PREVENTING REDIRECT"); */
/* $this->render('fake'); */
/* $this->redirect(array('controller' => 'leases', */
/* 'action' => 'view', */
/* $id)); */
@@ -324,20 +334,11 @@ class LeasesController extends AppController {
* - Closes a lease to any further action
*/
// REVISIT <AP>: 20090809
// While cleaning up the sitelink data, then delete reldep()
function reldep($id) {
$this->Lease->id = $id;
$stamp = $this->Lease->field('moveout_date');
$this->Lease->releaseSecurityDeposits($id, $stamp);
$this->redirect(array('action'=>'view', $id));
}
function close($id) {
// REVISIT <AP>: 20090708
// We should probably seek confirmation first...
if (!$this->Lease->closeable($id)) {
INTERNAL_ERROR("This lease is not ready to close");
$this->INTERNAL_ERROR("This lease is not ready to close");
$this->redirect(array('action'=>'view', $id));
}
@@ -345,6 +346,21 @@ class LeasesController extends AppController {
$this->redirect(array('action'=>'view', $id));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: open
* - Re-opens a lease for further action
*/
function open($id) {
// REVISIT <AP>: 20131204
// We should probably seek confirmation first, since this wipes out
// the old close date, with no way to restore that date.
$this->Lease->reopen($id);
$this->redirect(array('action'=>'view', $id));
}
/**************************************************************************
**************************************************************************
@@ -388,6 +404,10 @@ class LeasesController extends AppController {
$this->set(compact('default_late'));
if ($type === 'move-in') {
// Make sure we have a valid lease that we're moving in
if (empty($lease))
$this->redirect(array('action' => 'index'));
$movein = array();
$movein['time'] = strtotime($lease['Lease']['movein_date']);
$movein['effective_time'] = strtotime($lease['Lease']['movein_date']);
@@ -418,9 +438,73 @@ class LeasesController extends AppController {
function assess_rent($date = null) {
$this->Lease->assessMonthlyRentAll($date);
$this->redirect(array('action'=>'index'));
}
function assess_late($date = null) {
$this->Lease->assessMonthlyLateAll($date);
$this->redirect(array('action'=>'index'));
}
function assess_all($date = null) {
$this->Lease->assessMonthlyRentAll($date);
$this->Lease->assessMonthlyLateAll($date);
$this->redirect(array('action'=>'index'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: overview
* - Displays lease up information
*/
function overview($months = 12) {
$overview = array('months' => array());
for ($month = 0; $month < $months; ++$month) {
//for ($month = 12; $month >= 0; --$month) {
$this_month = "(DATE(NOW() - INTERVAL $month MONTH - INTERVAL DAY(NOW())-1 DAY))";
$next_month = "($this_month + INTERVAL 1 MONTH)";
$row = $this->Lease->find
('first', array('link' => array(),
'fields' => array("MONTHNAME($this_month) AS month",
"YEAR($this_month) AS year"),
));
$mname = $row[0]['month'] .', '. $row[0]['year'];
$overview['months'][$mname] = array('name' => $mname);
foreach(array('start' => array('before' => $this_month, 'after' => $this_month),
'finish' => array('before' => $next_month, 'after' => $next_month),
'peak' => array('before' => $next_month, 'after' => $this_month))
AS $type => $parm) {
$count = $this->Lease->find
('count',
array('link' => array(),
'conditions' => array("movein_date < {$parm['before']}",
"(moveout_date IS NULL OR moveout_date >= {$parm['after']})",
),
));
$overview['months'][$mname][$type] = $count;
}
foreach(array('movein', 'moveout') AS $mvinout) {
$count = $this->Lease->find
('count',
array('link' => array(),
'conditions' => array("{$mvinout}_date < $next_month",
"{$mvinout}_date >= $this_month")
));
$overview['months'][$mname][$mvinout] = $count;
}
}
// Enable the Reports menu section
$this->sideMenuAreaActivate('REPORT');
// Prepare to render.
$this->set('title', 'Lease Up Report');
$this->set(compact('overview'));
}
@@ -442,21 +526,18 @@ class LeasesController extends AppController {
('first',
array('contain' =>
array(// Models
'LeaseType',
'Unit',
'Customer',
'LeaseType(id,name)',
'Unit(id,name)',
'Customer(id,name)',
),
'fields' => array('Lease.*', $this->Lease->delinquentField()),
'conditions' => array(array('Lease.id' => $id)),
)
);
$lease['Lease'] += $lease[0];
unset($lease[0]);
$lease['Lease']['paid_through'] = $this->Lease->rentPaidThrough($id);
$this->set('charge_gaps', $this->Lease->rentChargeGaps($id));
$this->set('charge_through', $this->Lease->rentChargeThrough($id));
// Figure out the outstanding balances for this lease
// Figure out the outstanding balances for this lease
$outstanding_balance = $this->Lease->balance($id);
$outstanding_deposit = $this->Lease->securityDepositBalance($id);
@@ -465,28 +546,21 @@ class LeasesController extends AppController {
// yet still have an outstanding balance. This can happen if someone
// were to reverse charges, or if a payment should come back NSF.
if (!isset($lease['Lease']['close_date']) || $outstanding_balance > 0) {
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
if (!isset($lease['Lease']['moveout_date']))
$this->sidemenu_links[] =
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
$id));
$this->addSideMenuLink('Move-Out',
array('action' => 'move_out', $id), null,
'ACTION');
if (!isset($lease['Lease']['close_date']))
$this->sidemenu_links[] =
array('name' => 'New Invoice', 'url' => array('action' => 'invoice',
$id));
$this->addSideMenuLink('New Invoice',
array('action' => 'invoice', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'New Receipt', 'url' => array('controller' => 'customers',
'action' => 'receipt',
$lease['Customer']['id']));
/* if ($outstanding_balance < 0) */
/* $this->sidemenu_links[] = */
/* array('name' => 'Transfer Credit to Customer', */
/* 'url' => array('action' => 'promote_surplus', $id)); */
$this->addSideMenuLink('New Receipt',
array('controller' => 'customers',
'action' => 'receipt',
$lease['Customer']['id']), null,
'ACTION');
// REVISIT <AP>:
// Not allowing refund to be issued from the lease, as
@@ -495,24 +569,29 @@ class LeasesController extends AppController {
// when a charge is reimbursed; a bug that we'll either
// need to fix, or we'll have to revisit this assumption.
if ($outstanding_balance < 0)
INTERNAL_ERROR("Should not have a customer lease credit.");
$this->INTERNAL_ERROR("Should not have a customer lease credit.");
/* if ($outstanding_balance < 0) */
/* $this->sidemenu_links[] = */
/* array('name' => 'Issue Refund', */
/* 'url' => array('action' => 'refund', $id)); */
/* $this->addSideMenuLink('Issue Refund', */
/* array('action' => 'refund', $id), null, */
/* 'ACTION'); */
if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0)
$this->sidemenu_links[] =
array('name' => 'Write-Off', 'url' => array('action' => 'bad_debt',
$id));
if ($this->Lease->closeable($id))
$this->sidemenu_links[] =
array('name' => 'Close', 'url' => array('action' => 'close',
$id));
$this->addSideMenuLink('Write-Off',
array('action' => 'bad_debt', $id), null,
'ACTION');
}
if ($this->Lease->closeable($id))
$this->addSideMenuLink('Close',
array('action' => 'close', $id), null,
'ACTION');
if ($this->Lease->isClosed($id))
$this->addSideMenuLink('Re-Open',
array('action' => 'open', $id), null,
'ACTION');
// Prepare to render
$title = 'Lease: #' . $lease['Lease']['id'];
$this->set(compact('lease', 'title',

View File

@@ -2,19 +2,6 @@
class LedgerEntriesController 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);
}
/**************************************************************************
**************************************************************************
@@ -130,8 +117,12 @@ class LedgerEntriesController extends AppController {
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['LedgerEntry'] = array('id');
$links['Transaction'] = array('id');
$links['Ledger'] = array('id');
$links['Account'] = array('controller' => 'accounts', 'name');
// REVISIT <AP>: 20090827
// Need to take 'level' into account
if ($this->Permission->allow('controller.accounts')) {
$links['Ledger'] = array('id');
$links['Account'] = array('name');
}
$links['Tender'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -145,12 +136,6 @@ class LedgerEntriesController extends AppController {
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
}
// Get the Entry and related fields
$entry = $this->LedgerEntry->find
('first',
array('contain' => array
@@ -163,13 +148,16 @@ class LedgerEntriesController extends AppController {
array('fields' => array('id', 'sequence', 'name'),
'Account' =>
array('fields' => array('id', 'name', 'type'),
),
),
),
),
'Tender' =>
array('fields' => array('id', 'name'),
),
'DebitDoubleEntry' => array('id'),
'CreditDoubleEntry' => array('id'),
'DebitEntry' => array('fields' => array('id', 'crdr')),
'CreditEntry' => array('fields' => array('id', 'crdr')),
),
@@ -177,6 +165,11 @@ class LedgerEntriesController extends AppController {
'conditions' => array('LedgerEntry.id' => $id),
));
if (empty($entry) || empty($entry['Ledger']['Account'])) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
}
if (!empty($entry['DebitEntry']) && !empty($entry['CreditEntry']))
die("LedgerEntry has both a matching DebitEntry and CreditEntry");
if (empty($entry['DebitEntry']) && empty($entry['CreditEntry']))
@@ -191,6 +184,18 @@ class LedgerEntriesController extends AppController {
else
$entry['MatchingEntry'] = $entry['DebitEntry'][0];
if (empty($entry['DebitDoubleEntry']['id']))
$entry['DoubleEntry'] = $entry['CreditDoubleEntry'];
else
$entry['DoubleEntry'] = $entry['DebitDoubleEntry'];
// REVISIT <AP>: 20090816
// This page doesn't seem very useful, let's just keep it
// all to the double entry view.
$this->redirect(array('controller' => 'double_entries',
'action' => 'view',
$entry['DoubleEntry']['id']));
// Prepare to render.
$title = "Ledger Entry #{$entry['LedgerEntry']['id']}";
$this->set(compact('entry', 'title'));

View File

@@ -2,25 +2,29 @@
class LedgersController extends AppController {
var $sidemenu_links =
array(array('name' => 'Ledgers', 'header' => true),
array('name' => 'Current', 'url' => array('controller' => 'ledgers', 'action' => 'current')),
array('name' => 'Closed', 'url' => array('controller' => 'ledgers', 'action' => 'closed')),
array('name' => 'All', 'url' => array('controller' => 'ledgers', 'action' => 'all')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('Current',
array('controller' => 'ledgers', 'action' => 'current'), null,
'CONTROLLER');
$this->addSideMenuLink('Closed',
array('controller' => 'ledgers', 'action' => 'closed'), null,
'CONTROLLER');
$this->addSideMenuLink('All',
array('controller' => 'ledgers', 'action' => 'all'), null,
'CONTROLLER');
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -50,24 +54,21 @@ class LedgersController extends AppController {
}
function gridDataCountTables(&$params, &$model) {
// Our count should NOT include anything extra,
// so we need the virtual function to prevent
// the base class from just calling our
// gridDataTables function.
return parent::gridDataTables($params, $model);
}
function gridDataTables(&$params, &$model) {
return array
('link' =>
array(// Models
'Account',
'LedgerEntry',
'CloseTransaction',
),
);
}
function gridDataTables(&$params, &$model) {
$tables = $this->gridDataCountTables($params, $model);
$tables['link'][] = 'LedgerEntry';
$tables['link'][] = 'CloseTransaction';
return $tables;
}
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence';
@@ -85,28 +86,32 @@ class LedgersController extends AppController {
$conditions[] = array('Ledger.close_transaction_id !=' => null);
}
$conditions[] = array('Account.level >=' =>
$this->Permission->level('controller.accounts'));
return $conditions;
}
function gridDataOrder(&$params, &$model, $index, $direction) {
$id_sequence = false;
if ($index === 'id_sequence') {
$id_sequence = true;
$index = 'Ledger.account_id';
}
$order = parent::gridDataOrder($params, $model, $index, $direction);
if ($id_sequence) {
$order[] = 'Ledger.sequence ' . $direction;
}
// After sorting by whatever the user wants, add these
// defaults into the sort mechanism. If we're already
// sorting by one of them, it will only be redundant,
// and should cause no harm (possible a longer query?)
$order[] = 'Account.name ' . $direction;
$order[] = 'Ledger.sequence ' . $direction;
return $order;
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Ledger'] = array('id_sequence');
$links['Account'] = array('name');
// REVISIT <AP>: 20090827
// Need to take 'level' into account
if ($this->Permission->allow('controller.accounts')) {
$links['Ledger'] = array('sequence');
$links['Account'] = array('name');
}
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -119,22 +124,24 @@ class LedgersController extends AppController {
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
// Get details about the ledger itself (no entries yet)
$ledger = $this->Ledger->find
('first',
array('contain' =>
array(// Models
'Account',
),
'conditions' => array(array('Ledger.id' => $id)),
'conditions' => array(array('Ledger.id' => $id),
array('Account.level >=' =>
$this->Permission->level('controller.accounts')),
),
)
);
if (empty($ledger)) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
// Get ledger stats for our summary box
$stats = $this->Ledger->stats($id);

View File

@@ -0,0 +1,216 @@
<?php
class LocksController extends AppController {
/**************************************************************************
**************************************************************************
**************************************************************************
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('List',
array('controller' => 'locks', 'action' => 'all'), null,
'CONTROLLER');
$this->addSideMenuLink('Add',
array('controller' => 'locks', 'action' => 'add'), null,
'CONTROLLER');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: index / all
* - Generate a listing of locks
*/
function index() { $this->all(); }
function all() { $this->gridView('Locks', 'all'); }
/**************************************************************************
**************************************************************************
**************************************************************************
* virtuals: gridData
* - With the application controller handling the gridData action,
* these virtual functions ensure that the correct data is passed
* to jqGrid.
*/
/* function gridDataCountTables(&$params, &$model) { */
/* return array('link' => array('Unit')); */
/* } */
function gridDataTables(&$params, &$model) {
$tables = parent::gridDataTables($params, $model);
$tables['link']['LocksUnit'] = array();
return $tables;
}
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = 'COUNT(LocksUnit.id) AS inuse';
$fields[] = 'IF(Lock.qty > COUNT(LocksUnit.id), Lock.qty - COUNT(LocksUnit.id), 0) AS avail';
return $fields;
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Lock'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: view
* - Displays information about a specific entry
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'locks', 'action'=>'index'));
}
// Get the lock and related fields
$this->Lock->id = $id;
$lock = $this->Lock->find
('first', array
('contain' => array(),
));
//$lock['Lock'] = $lock[0] + $lock['lock'];
//unset($lock[0]);
$this->addSideMenuLink('Edit',
array('action' => 'edit', $id), null,
'ACTION');
$this->addSideMenuLink('Delete',
array('action' => 'delete', $id), null,
'ACTION');
$this->set(compact('lock'));
// Prepare to render.
$title = "Lock : {$lock['Lock']['name']}";
$this->set(compact('title'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: edit
* - Edit customer information
*/
function edit($id = null) {
if (isset($this->data)) {
// Check to see if the operation was cancelled.
if (isset($this->params['form']['cancel'])) {
if (isset($this->data['Lock']['id']))
$this->redirect(array('action'=>'view', $this->data['Lock']['id']));
$this->redirect(array('action'=>'index'));
}
// Save the lock and all associated data
if (!$this->Lock->saveLock($this->data)) {
$this->Session->setFlash("LOCK SAVE FAILED", true);
pr("LOCK SAVE FAILED");
}
// View the lock by redirect
$this->redirect(array('action'=>'view', $this->Lock->id));
}
if ($id) {
// Get details on this customer, its contacts and leases
$lock = $this->Lock->find
('first', array
('conditions' => array('Lock.id' => $id),
));
$this->data = $lock;
$title = 'Lock: ' . $this->data['Lock']['name'] . " : Edit";
}
else {
$title = "Enter New Lock Information";
$this->data = array();
}
// Prepare to render.
//pr($this->data);
$this->set(compact('title'));
$this->render('edit');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: add
* - Add a new lock
*/
function add() {
$this->edit();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: delete
* - Deletes an old lock
*/
function delete($id) {
if (isset($this->data)) {
// Check to see if the operation was cancelled.
if (isset($this->params['form']['cancel'])) {
if (isset($this->data['Lock']['id']))
$this->redirect(array('action'=>'view', $this->data['Lock']['id']));
$this->redirect(array('action'=>'index'));
}
// Delete the lock and all associated data
if (!$this->Lock->destroy($this->data['Lock']['id'])) {
$this->Session->setFlash(__('Failed to delete lock.', true));
$this->redirect(array('action'=>'view', $this->data['Lock']['id']));
}
// It's gone. Go back to the list of locks
$this->redirect(array('controller' => 'locks', 'action'=>'index'));
}
// User must specify an ID.
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'locks', 'action'=>'index'));
}
// Get the lock and related fields
$this->Lock->id = $id;
$lock = $this->Lock->find
('first', array
('contain' => array('Unit'),
));
// Make sure the lock isn't in use.
if (isset($lock['Unit']) && count($lock['Unit']) > 0) {
$this->Session->setFlash(__('Lock currently on units. Cannot be deleted!', true));
$this->redirect(array('action'=>'view', $id));
}
// Prepare to render.
$this->data = $lock;
$title = "Delete Lock : {$lock['Lock']['name']}";
$this->set(compact('title'));
}
}

View File

@@ -52,6 +52,7 @@ class MapsController extends AppController {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$this->sideMenuEnable('SITE', $this->op_area);
$this->set('info', $this->mapInfo($id, $requested_width));
$this->set('title', "Site Map");
}
@@ -85,11 +86,35 @@ class MapsController extends AppController {
'units' => array());
// Find all of the map/unit information from this SiteArea
$this->Map->recursive = 2;
$this->Map->SiteArea->unbindModel(array('hasOne' => array('Map')));
$map = $this->Map->read(null, $id);
//pr($map);
$map = $this->Map->find('first', array('contain' => false,
'conditions' => array('id' => $id)));
$units = $this->Map->Unit->find
('all',
array('link' =>
array('Map' =>
array('fields' => array()),
'CurrentLease' =>
array('fields' => array('id', 'paid_through_date',
$this->Map->Unit->CurrentLease->
delinquentField('CurrentLease')),
'Customer'),
'UnitSize' =>
array('fields' => array('id', 'depth', 'width',
'MapsUnit.pt_top',
'MapsUnit.pt_left',
'MapsUnit.transpose')),
),
'fields' => array('id', 'name', 'status'),
'conditions' => array('Map.id' => $id),
));
/* pr(compact('map', 'units')); */
/* $this->render('/empty'); */
/* return; */
/*****
* The preference would be to leave all things "screen" related
* to reside in the view. However, two separate views need this
@@ -113,7 +138,7 @@ class MapsController extends AppController {
$info['depth'] = $bottom * $screen_adjustment_factor;
// Go through each unit in the map, calculating the map location
foreach ($map['Unit'] AS $unit) {
foreach ($units AS $unit) {
$lft = $unit['MapsUnit']['pt_left'] + $boundary_adjustment;
$top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment;
@@ -132,10 +157,9 @@ class MapsController extends AppController {
$width *= $screen_adjustment_factor;
$depth *= $screen_adjustment_factor;
//$info['units'][$unit['id']] =
$info['units'][] =
array( 'id' => $unit['id'],
'name' => $unit['name'],
array( 'id' => $unit['Unit']['id'],
'name' => $unit['Unit']['name'],
'left' => $lft,
'right' => $lft + $width,
'top' => $top,
@@ -143,11 +167,15 @@ class MapsController extends AppController {
'width' => $width,
'depth' => $depth,
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
'status' => $unit['status']
'status' => (($unit['Unit']['status'] === 'OCCUPIED' &&
!empty($unit[0]['delinquent']))
? 'LATE' : $unit['Unit']['status']),
'data' => $unit,
);
}
//pr($info);
/* pr($info); */
/* $this->render('/empty'); exit(); */
return $info;
}
@@ -160,8 +188,10 @@ class MapsController extends AppController {
*/
function legend($id = null, $requested_width = 400) {
$status = $this->Map->Unit->activeStatusEnums();
//pr($status);
$status = array_keys($this->Map->Unit->activeStatusEnums());
$occupied_key = array_search('OCCUPIED', $status);
array_splice($status, $occupied_key+1, 0, array('LATE'));
$rows = 2;
$cols = (int)((count($status) + $rows - 1) / $rows);
@@ -191,7 +221,7 @@ class MapsController extends AppController {
$item_width *= $screen_adjustment_factor;
$item_depth *= $screen_adjustment_factor;
foreach ($status AS $code => $value) {
foreach ($status AS $code) {
$info['units'][] = array('name' => $code,
'status' => $code,
'width' => $item_width,
@@ -241,9 +271,9 @@ class MapsController extends AppController {
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
$info['palate']['unit']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 128, 'blue' => 128);
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 0, 'blue' => 128);
// Determine text color to go with each background
foreach ($info['palate']['unit'] AS &$code) {

View File

@@ -2,20 +2,7 @@
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);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -24,6 +11,7 @@ class StatementEntriesController extends AppController {
*/
function index() { $this->gridView('All Statement Entries'); }
function unpaid() { $this->gridView('Unpaid Charges', 'unreconciled'); }
/**************************************************************************
@@ -35,7 +23,7 @@ class StatementEntriesController extends AppController {
* to jqGrid.
*/
function gridDataTables(&$params, &$model) {
function gridDataCountTables(&$params, &$model) {
$link =
array(// Models
'Transaction' =>
@@ -58,27 +46,36 @@ class StatementEntriesController extends AppController {
),
);
if (isset($params['post']['custom']['statement_entry_id'])) {
$link['DisbursementEntry'] = array();
$link['ChargeEntry'] = array();
if (!empty($params['post']['custom']['statement_entry_id'])) {
$link['ChargeEntry'] = 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']);
}
/* if ($params['action'] === 'collected') { */
/* $link['DisbursementEntry'] = array('Receipt' => array('class' => 'Transaction')); */
/* $link['ChargeEntry'] = array('Invoice' => array('class' => 'Transaction')); */
/* } */
/* if (count(array_intersect($params['fields'], array('applied'))) == 1) { */
/* $link['DisbursementEntry'] = array(); */
/* $link['ChargeEntry'] = array(); */
/* } */
/* elseif (isset($params['post']['custom']['customer_id']) || isset($params['post']['custom']['lease_id'])) { */
/* $link['DisbursementEntry'] = array(); */
/* } */
return array('link' => $link);
}
function gridDataTables(&$params, &$model) {
$tables = $this->gridDataCountTables($params, $model);
if (in_array('applied', $params['post']['fields'])) {
$tables['link'] +=
array('ChargeEntry' => array(),
'DisbursementEntry' => array());
}
return $tables;
}
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
@@ -87,11 +84,13 @@ class StatementEntriesController extends AppController {
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
" AS 'applied'");
}
if (in_array('unapplied', $params['post']['fields'])) {
$fields[] = ("StatementEntry.amount - (" .
"IF(StatementEntry.type = 'CHARGE'," .
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
") AS 'balance'");
") AS 'unapplied'");
}
$fields = array_merge($fields,
@@ -117,11 +116,13 @@ class StatementEntriesController extends AppController {
if (isset($account_id))
$conditions[] = array('StatementEntry.account_id' => $account_id);
if (isset($statement_entry_id)) {
if (isset($customer_id))
$conditions[] = array('StatementEntry.customer_id' => $customer_id);
if (isset($statement_entry_id))
$conditions[] = array('OR' =>
array(array('ChargeEntry.id' => $statement_entry_id),
array('DisbursementEntry.id' => $statement_entry_id)));
}
return $conditions;
}
@@ -129,7 +130,10 @@ class StatementEntriesController extends AppController {
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['StatementEntry'] = array('id');
$links['Transaction'] = array('id');
$links['Account'] = array('name');
// REVISIT <AP>: 20090827
// Need to take 'level' into account
if ($this->Permission->allow('controller.accounts'))
$links['Account'] = array('name');
$links['Customer'] = array('name');
$links['Lease'] = array('number');
$links['Unit'] = array('name');
@@ -143,34 +147,49 @@ class StatementEntriesController extends AppController {
// defaults into the sort mechanism. If we're already
// sorting by one of them, it will only be redundant,
// and should cause no harm (possible a longer query?)
$order[] = 'Transaction.stamp ' . $direction;
$order[] = 'StatementEntry.effective_date ' . $direction;
if ($index != 'Transaction.stamp' &&
$index != 'StatementEntry.effective_date') {
$order[] = 'Transaction.stamp ' . $direction;
$order[] = 'StatementEntry.effective_date ' . $direction;
}
$order[] = 'StatementEntry.id ' . $direction;
return $order;
}
function gridDataRecordsExecute(&$params, &$model, $query) {
if (in_array('applied', $params['post']['fields'])) {
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
$tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," .
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
" AS 'applied'",
"StatementEntry.amount - (" .
"IF(StatementEntry.type = 'CHARGE'," .
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
") AS 'balance'",
);
//pr(compact('tquery'));
$total = $model->find('first', $tquery);
$params['userdata']['total'] = $total[0]['applied'];
$params['userdata']['balance'] = $total[0]['balance'];
function gridDataCountExecute(&$params, &$model, $query) {
if ($params['action'] === 'unreconciled') {
// REVISIT <AP> 20100413:
// This is a lame solution, as it runs the same queries twice
// (and causes code duplication). However, I'm not in the mood
// to flush out an actual "count" solution at the moment, and I
// also don't want to cache the results in $params (although
// that is probably the most sensible solution). So, I'll just
// calculate the reconciled set both times and live with the
// performance and maintenance penalty
$lquery = array('conditions' => $query['conditions']);
$set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true);
return count($set['entries']);
}
else {
return parent::gridDataCountExecute($params, $model, $query);
}
function gridDataRecordsExecute(&$params, &$model, $query) {
if ($params['action'] === 'unreconciled') {
$lquery = array('conditions' => $query['conditions']);
$set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true);
$entries = array();
foreach ($set['entries'] AS $entry)
$entries[] = $entry['StatementEntry']['id'];
$query['conditions'] = array('StatementEntry.id' => $entries);
$params['userdata']['balance'] = $set['summary']['balance'];
}
if ($params['action'] === 'collected') {
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
$total = $model->find('first', $tquery);
@@ -187,9 +206,42 @@ class StatementEntriesController extends AppController {
* action: reverse the ledger entry
*/
function reverse($id) {
$this->StatementEntry->reverse($id);
$this->redirect(array('action'=>'view', $id));
function reverse($id = null) {
if ($this->data) {
//pr($this->data); die();
$this->StatementEntry->reverse
($this->data['StatementEntry']['id'],
$this->data['Transaction']['stamp'],
$this->data['Transaction']['comment']);
$this->redirect(array('action'=>'view',
$this->data['StatementEntry']['id']));
$this->INTERNAL_ERROR('SHOULD HAVE REDIRECTED');
}
$this->StatementEntry->id = $id;
$entry = $this->StatementEntry->find
('first', array
('contain' => array('Customer', 'Transaction', 'Account'),
));
if (empty($entry)) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'customers',
'action'=>'index'));
}
if (!$this->StatementEntry->reversable($id)) {
$this->Session->setFlash(__('Item not reversable.', true));
$this->redirect(array('action'=>'view', $id));
}
// Prepare to render.
$title = ("Charge #{$entry['StatementEntry']['id']}" .
" : {$entry['StatementEntry']['amount']}" .
" : Reverse");
$this->set(compact('entry', 'title'));
}
@@ -205,6 +257,98 @@ class StatementEntriesController extends AppController {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: incexpbymonth
* - Displays income and/or expenses by month
*/
function incexpbymonth($accts, $security_deposits, $months) {
$datefrom = 'DATE(NOW() - INTERVAL '.($months-1).' MONTH - INTERVAL DAY(NOW())-1 DAY)';
$dateto = 'NOW()';
/* $datefrom = '"2009-01-01"'; */
/* $dateto = '"2012-12-31"'; */
$result = $this->StatementEntry->find
('all',
array('link' => array('Account' => array('fields' => 'name')),
'fields' => array_merge(array('MONTHNAME(effective_date) AS month',
'YEAR(effective_date) AS year'),
$this->StatementEntry->chargeDisbursementFields(true)),
'conditions' => array('Account.type' => $accts,
"effective_date >= $datefrom",
"effective_date <= $dateto",
),
'group' => array('YEAR(effective_date)', 'MONTH(effective_date)', 'Account.id'),
'order' => array('YEAR(effective_date) DESC', 'MONTH(effective_date) DESC', 'Account.type',
'IF(Account.id = '.$this->StatementEntry->Account->rentAccountID().', "---", Account.name)'),
));
if ($security_deposits) {
$sdresult = $this->StatementEntry->Transaction->LedgerEntry->find
('all',
array('link' => array('Transaction' => array('StatementEntry' => array('fields' => 'effective_date'),
'fields' => array()),
'Account' => array('fields' => 'name')),
'fields' => array_merge(array('MONTHNAME(effective_date) AS month',
'YEAR(effective_date) AS year'),
$this->StatementEntry->Transaction->LedgerEntry->debitCreditFields(true)),
'conditions' => array('LedgerEntry.account_id' => $this->StatementEntry->Account->securityDepositAccountID(),
"effective_date >= $datefrom",
"effective_date <= $dateto",
'StatementEntry.id = (SELECT MIN(id) FROM statement_entries WHERE transaction_id = `Transaction`.id)'
),
'group' => array('YEAR(effective_date)', 'MONTH(effective_date)', 'Account.id'),
'order' => array('YEAR(effective_date) DESC', 'MONTH(effective_date) DESC', 'Account.type', 'Account.name'),
));
} else {
$sdresult = array();
}
$overview = array('months' => array(), 'amount' => 0);
foreach (array_merge($result, $sdresult) AS $row) {
$mname = $row[0]['month'] .', '. $row[0]['year'];
if (empty($overview['months'][$mname]))
$overview['months'][$mname] = array('name' => $mname,
'subs' => array(),
'amount' => 0);
$month = &$overview['months'][$mname];
$month['subs'][] = array('name' => $row['Account']['name'],
'amount' => $row[0]['balance']);
$month['amount'] += $row[0]['balance'];
$overview['amount'] += $row[0]['balance'];
}
// Enable the Reports menu section
$this->sideMenuAreaActivate('REPORT');
// Prepare to render.
$this->set('months', $months);
$this->set(compact('overview'));
$this->render('chargesbymonth');
}
function incomebymonth($months = 12, $invoice = false) {
$this->set('title', 'Monthly Gross Income');
$this->set('reptype', 'Gross Income');
$this->incexpbymonth(array('INCOME'), $invoice, $months);
}
function expensebymonth($months = 12) {
$this->set('title', 'Gross Monthly Expenses');
$this->set('reptype', 'Gross Expenses');
$this->incexpbymonth(array('EXPENSE'), false, $months);
}
function netbymonth($months = 12) {
$this->set('title', 'Net Monthly Income');
$this->set('reptype', 'Net Income');
$this->incexpbymonth(array('INCOME', 'EXPENSE'), true, $months);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -213,25 +357,27 @@ class StatementEntriesController extends AppController {
*/
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
('Transaction' => array('fields' => array('id', 'type', 'stamp')),
'Account' => array('id', 'name', 'type'),
'Account' => array('id', 'name', 'type', 'level'),
'Customer' => array('fields' => array('id', 'name')),
'Lease' => array('fields' => array('id')),
'Lease' => array('fields' => array('id', 'number')),
),
'conditions' => array('StatementEntry.id' => $id),
'conditions' => array(array('StatementEntry.id' => $id),
),
));
$reconciled = $this->StatementEntry->reconciledEntries($id);
if (empty($entry)) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
}
$entry['Account']['link'] =
$entry['Account']['level'] >=
$this->Permission->level('controller.accounts');
$stats = $this->StatementEntry->stats($id);
@@ -243,34 +389,21 @@ class StatementEntriesController extends AppController {
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
$reversal = $this->StatementEntry->find
('first',
array('link' => array('DisbursementEntry'),
'conditions' => array(array('StatementEntry.id' => $id),
array('DisbursementEntry.type' => 'REVERSAL')),
));
// Set up dynamic menu items
if (empty($reversal) || $stats['balance'] > 0)
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
if (empty($reversal))
$this->sidemenu_links[] =
array('name' => 'Reverse',
'url' => array('action' => 'reverse',
$id));
if ($this->StatementEntry->reversable($id))
$this->addSideMenuLink('Reverse',
array('action' => 'reverse', $id), null,
'ACTION');
if ($stats['balance'] > 0)
$this->sidemenu_links[] =
array('name' => 'Waive Balance',
'url' => array('action' => 'waive',
$id));
$this->addSideMenuLink('Waive Balance',
array('action' => 'waive', $id), null,
'ACTION');
}
// Prepare to render.
$title = "Statement Entry #{$entry['StatementEntry']['id']}";
$this->set(compact('entry', 'title', 'reconciled', 'stats'));
$this->set(compact('entry', 'title', 'stats'));
}
}

View File

@@ -2,20 +2,7 @@
class TendersController 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);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -75,7 +62,7 @@ class TendersController extends AppController {
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Tender'] = array('name', 'id');
$links['Customer'] = array('name');
$links['TenderType'] = array('name');
//$links['TenderType'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -163,29 +150,25 @@ class TendersController extends AppController {
));
// Set up dynamic menu items
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
// Watch out for the special "Closing" entries
if (!empty($tender['TenderType']['id']))
$this->sidemenu_links[] =
array('name' => 'Edit',
'url' => array('action' => 'edit',
$id));
if (!empty($tender['Tender']['deposit_transaction_id'])
&& empty($tender['Tender']['nsf_transaction_id'])
// Hard to tell what types of items can come back as NSF.
// For now, assume iff it is a named item, it can be NSF.
&& !empty($tender['TenderType']['data1_name'])
// (or if we're in development mode)
&& (!empty($tender['TenderType']['data1_name']) || !empty($this->params['dev']))
) {
$this->sidemenu_links[] =
array('name' => 'NSF',
'url' => array('action' => 'nsf',
$id));
$this->addSideMenuLink('NSF',
array('action' => 'nsf', $id), null,
'ACTION');
}
// Watch out for the special "Closing" entries, which have
// tender_type_id set to NULL. Otherwise, allow editing.
if (!empty($tender['TenderType']['id']))
$this->addSideMenuLink('Edit',
array('action' => 'edit', $id), null,
'ACTION');
// Prepare to render.
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']}";
$this->set(compact('tender', 'title'));
@@ -233,11 +216,6 @@ class TendersController extends AppController {
}
$this->redirect(array('action'=>'view', $this->Tender->id));
// For debugging, only if the redirects above have been
// commented out, otherwise this section isn't reached.
$this->render('/fake');
return;
}
if ($id) {

View File

@@ -4,26 +4,38 @@ class TransactionsController extends AppController {
var $components = array('RequestHandler');
var $sidemenu_links =
array(array('name' => 'Transactions', 'header' => true),
array('name' => 'All', 'url' => array('controller' => 'transactions', 'action' => 'all')),
array('name' => 'Invoices', 'url' => array('controller' => 'transactions', 'action' => 'invoice')),
array('name' => 'Receipts', 'url' => array('controller' => 'transactions', 'action' => 'receipt')),
array('name' => 'Deposits', 'url' => array('controller' => 'transactions', 'action' => 'deposit')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('Invoices',
array('controller' => 'transactions', 'action' => 'invoice'), null,
'CONTROLLER');
$this->addSideMenuLink('Receipts',
array('controller' => 'transactions', 'action' => 'receipt'), null,
'CONTROLLER');
$this->addSideMenuLink('Deposits',
array('controller' => 'transactions', 'action' => 'deposit'), null,
'CONTROLLER');
$this->addSideMenuLink('All',
array('controller' => 'transactions', 'action' => 'all'), null,
'CONTROLLER');
// REVISIT <AP>: 20090824
// Right now, we wish to keep things simple. Don't make these
// links available to non-admin users.
if (empty($this->params['admin']))
$this->sideMenuEnable('CONTROLLER', $this->std_area, false);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -36,13 +48,18 @@ class TransactionsController extends AppController {
function invoice() { $this->gridView('Invoices'); }
function receipt() { $this->gridView('Receipts'); }
function deposit() {
$this->sidemenu_links = array
(array('name' => 'Operations', 'header' => true),
array('name' => 'New Deposit', 'url' => array('controller' => 'tenders',
'action' => 'deposit')));
/* $this->addSideMenuLink('New Deposit', */
/* array('controller' => 'tenders', 'action' => 'deposit'), null, */
/* 'CONTROLLER', $this->new_area); */
$this->gridView('Deposits');
}
function gridView($title, $action = null, $element = null) {
if ($title != 'Deposits')
$this->set('include', array('Customer'));
parent::gridView($title, $action, $element);
}
/**************************************************************************
**************************************************************************
@@ -54,13 +71,19 @@ class TransactionsController extends AppController {
*/
function gridDataCountTables(&$params, &$model) {
return parent::gridDataTables($params, $model);
return array
('link' =>
array(// Models
'Account' => array('fields' => array()),
),
);
}
function gridDataTables(&$params, &$model) {
$link = $this->gridDataCountTables($params, $model);
$link['link']['StatementEntry'] = array('fields' => array());
$link['link']['DepositTender'] = array('fields' => array());
$link['link']['Customer'] = array('fields' => array('id', 'name'));
return $link;
}
@@ -70,7 +93,8 @@ class TransactionsController extends AppController {
$fields[] = ("IF(Transaction.type = 'DEPOSIT'," .
" COUNT(DepositTender.id)," .
" COUNT(StatementEntry.id)) AS entries");
return $fields;
return array_merge($fields,
$this->Transaction->LedgerEntry->debitCreditFields(false, true, 'Transaction'));
}
function gridDataConditions(&$params, &$model) {
@@ -83,7 +107,9 @@ class TransactionsController extends AppController {
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Transaction'] = array('id');
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
? 'deposit_slip' : 'view'));
$links['Customer'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -95,7 +121,7 @@ class TransactionsController extends AppController {
* - handles the creation of a charge invoice
*/
function postInvoice() {
function postInvoice($redirect = true) {
if (!$this->RequestHandler->isPost()) {
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
return;
@@ -110,6 +136,17 @@ class TransactionsController extends AppController {
die("<H1>INVOICE FAILED</H1>");
}
if ($redirect) {
if (!empty($this->data['Customer']['id']))
$this->redirect(array('controller' => 'customers',
'action' => 'receipt',
$this->data['Customer']['id']));
else
$this->redirect(array('controller' => 'leases',
'action' => 'view',
$this->data['Lease']['id']));
}
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
@@ -123,7 +160,7 @@ class TransactionsController extends AppController {
* - handles the creation of a receipt
*/
function postReceipt() {
function postReceipt($redirect = true) {
if (!$this->RequestHandler->isPost()) {
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
return;
@@ -147,6 +184,11 @@ class TransactionsController extends AppController {
die("<H1>RECEIPT FAILED</H1>");
}
if ($redirect)
$this->redirect(array('controller' => 'customers',
'action' => 'view',
$this->data['Customer']['id']));
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
@@ -259,7 +301,7 @@ class TransactionsController extends AppController {
$this->Session->setFlash(__('Unable to Create Deposit', true));
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
}
// Present the deposit slip to the user
$this->redirect(array('controller' => 'transactions',
'action' => 'deposit_slip',
@@ -339,8 +381,6 @@ class TransactionsController extends AppController {
die("<H1>REFUND FAILED</H1>");
}
$this->render('/fake');
// Return to viewing the lease/customer
if (empty($data['Lease']['id']))
$this->redirect(array('controller' => 'customers',
@@ -353,6 +393,23 @@ class TransactionsController extends AppController {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: destroy
* - Deletes a transaction and associated entries
* - !!WARNING!! This should be used with EXTREME caution, as it
* irreversibly destroys the data. It is not for normal use.
*/
function destroy($id) {
$this->Transaction->id = $id;
$customer_id = $this->Transaction->field('customer_id');
$this->Transaction->destroy($id);
$this->redirect(array('controller' => 'customers', 'action' => 'view', $customer_id));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -361,35 +418,40 @@ class TransactionsController extends AppController {
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$transaction = $this->Transaction->find
('first',
array('contain' =>
array(// Models
'Account' =>
array('fields' => array('Account.id',
'Account.name'),
),
'Ledger' =>
array('fields' => array('Ledger.id',
'Ledger.name'),
),
'Account(id,name,level)',
'Ledger(id,sequence)',
'NsfTender(id,name)',
),
'conditions' => array('Transaction.id' => $id),
'conditions' => array(array('Transaction.id' => $id),
),
));
if ($transaction['Transaction']['type'] === 'DEPOSIT') {
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'View Slip', 'url' => array('action' => 'deposit_slip', $id));
if (empty($transaction)) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$transaction['Account']['link'] =
$transaction['Account']['level'] >=
$this->Permission->level('controller.accounts');
if ($transaction['Transaction']['type'] === 'DEPOSIT')
$this->addSideMenuLink('View Slip',
array('action' => 'deposit_slip', $id), null,
'ACTION');
$this->addSideMenuLink('Destroy',
array('action' => 'destroy', $id),
array('confirmMessage' =>
"This may leave the database in an unstable state." .
" Do NOT do this unless you know what you're doing." .
" Proceed anyway?"),
'ACTION', $this->admin_area);
// OK, prepare to render.
$title = 'Transaction #' . $transaction['Transaction']['id'];
$this->set(compact('transaction', 'title'));
@@ -405,15 +467,12 @@ class TransactionsController extends AppController {
*/
function deposit_slip($id) {
// Build a container for the deposit slip data
$deposit = array('types' => array());
$this->id = $id;
$deposit +=
$this->Transaction->find('first', array('contain' => false));
// Find the deposit transaction
$this->Transaction->id = $id;
$deposit = $this->Transaction->find('first', array('contain' => array('Account')));
// Get a summary of all forms of tender in the deposit
$result = $this->Transaction->find
$tenders = $this->Transaction->find
('all',
array('link' => array('DepositTender' =>
array('fields' => array(),
@@ -428,32 +487,29 @@ class TransactionsController extends AppController {
'group' => 'TenderType.id',
));
if (empty($result)) {
die();
// Verify the deposit exists, and that something was actually deposited
if (empty($deposit) || empty($tenders)) {
$this->Session->setFlash(__('Invalid Deposit.', true));
$this->redirect(array('action'=>'deposit'));
}
// Add the summary to our deposit slip data container
foreach ($result AS $type) {
$deposit['types'][$type['TenderType']['id']] =
$type['TenderType'] + $type[0];
$deposit['types'] = array();
foreach ($tenders AS $tender) {
$deposit['types'][$tender['TenderType']['id']] =
$tender['TenderType'] + $tender[0];
}
// For each form of tender in the deposit, get the deposit items
/* foreach ($deposit['types'] AS $type_id => &$type) { */
/* $type['entries'] = $this->Transaction->DepositTender->find */
/* ('all', */
/* array('contain' => array('Customer', 'LedgerEntry'), */
/* 'conditions' => array(array('DepositTender.deposit_transaction_id' => $id), */
/* array('DepositTender.tender_type_id' => $type_id)), */
/* )); */
/* } */
$deposit_total = 0;
foreach ($deposit['types'] AS $type)
$deposit_total += $type['total'];
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'View Transaction', 'url' => array('action' => 'view', $id));
if (abs($deposit['Transaction']['amount'] - $deposit_total) >= .001)
$this->INTERNAL_ERROR("Deposit items ($deposit_total) do not add up to deposit slip total (".$deposit['Transaction']['amount'].")");
$this->addSideMenuLink('View',
array('action' => 'view', $id), null,
'ACTION');
$title = 'Deposit Slip';
$this->set(compact('title', 'deposit'));

View File

@@ -0,0 +1,255 @@
<?php
class UnitSizesController extends AppController {
/**************************************************************************
**************************************************************************
**************************************************************************
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('1 Bedroom',
array('controller' => 'unit_sizes', 'action' => 'bd1'), null,
'CONTROLLER');
$this->addSideMenuLink('2 Bedroom',
array('controller' => 'unit_sizes', 'action' => 'bd2'), null,
'CONTROLLER');
$this->addSideMenuLink('3 Bedroom',
array('controller' => 'unit_sizes', 'action' => 'bd3'), null,
'CONTROLLER');
$this->addSideMenuLink('4+ Bedroom',
array('controller' => 'unit_sizes', 'action' => 'bd4'), null,
'CONTROLLER');
$this->addSideMenuLink('Auto',
array('controller' => 'unit_sizes', 'action' => 'auto'), null,
'CONTROLLER');
$this->addSideMenuLink('Boat',
array('controller' => 'unit_sizes', 'action' => 'boat'), null,
'CONTROLLER');
$this->addSideMenuLink('RV',
array('controller' => 'unit_sizes', 'action' => 'rv'), null,
'CONTROLLER');
$this->addSideMenuLink('All',
array('controller' => 'unit_sizes', 'action' => 'all'), null,
'CONTROLLER');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: index / unavailable / vacant / occupied / all
* - Generate a listing of units
*/
function index() { $this->all(); }
function bd1() { $this->gridView('Sizes for 1 Bedroom'); }
function bd2() { $this->gridView('Sizes for 2 Bedrooms'); }
function bd3() { $this->gridView('Sizes for 3 Bedroom'); }
function bd4() { $this->gridView('Sizes for 4+ Bedroom'); }
function auto() { $this->gridView('Sizes for an Automobile'); }
function boat() { $this->gridView('Sizes for a Boat'); }
function rv() { $this->gridView('Sizes for an RV'); }
function all() { $this->gridView('All Unit Sizes', 'all'); }
/**************************************************************************
**************************************************************************
**************************************************************************
* virtuals: gridData
* - With the application controller handling the gridData action,
* these virtual functions ensure that the correct data is passed
* to jqGrid.
*/
function gridDataCountTables(&$params, &$model) {
return array('link' => array('UnitType'));
}
function gridDataTables(&$params, &$model) {
$tables = $this->gridDataCountTables($params, $model);
$tables['link']['Unit'] = array();
return $tables;
}
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = 'ROUND(UnitSize.width/12, 1) AS width';
$fields[] = 'ROUND(UnitSize.depth/12, 1) AS depth';
$fields[] = 'ROUND(UnitSize.height/12, 1) AS height';
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft';
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12, 0) AS cuft';
$fields[] = 'ROUND(UnitSize.rent / (UnitSize.width/12 * UnitSize.depth/12), 2) AS sqcost';
$fields[] = 'ROUND(UnitSize.rent / (UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12), 2) AS cucost';
$fields[] = 'COUNT(Unit.id) AS units';
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionUnavailable() . ', 1, 0)) AS unavailable';
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionAvailable() . ', 1, 0)) AS available';
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 1, 0)) AS occupied';
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 0, 1)) / COUNT(Unit.id) AS vacancy';
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 1, 0)) / COUNT(Unit.id) AS occupancy';
return $fields;
}
function gridDataConditions(&$params, &$model) {
$conditions = parent::gridDataConditions($params, $model);
// REVISIT <AP>: 20090825
// Sizes should come from the database.
// For now, I took an assumed average need, then bracketed
// with +/- 50 sqft. This gives a 100sqft range for each.
if ($params['action'] === 'bd1') { // 75 sqft
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 125';
}
elseif ($params['action'] === 'bd2') { // 125 sqft
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 75';
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 175';
}
elseif ($params['action'] === 'bd3') { // 175 sqft
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 125';
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 225';
}
elseif ($params['action'] === 'bd4') { // 225 sqft
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 175';
}
elseif (in_array($params['action'], array('auto', 'boat', 'rv'))) {
$conditions[] = array('UnitType.id' =>
array_merge(array_keys($this->UnitSize->UnitType->enclosedTypes()),
array_keys($this->UnitSize->UnitType->outdoorTypes())));
list($width, $depth, $height) = array(8, 15, null);
if ($params['action'] === 'auto')
$depth = 15;
elseif ($params['action'] === 'boat')
$depth = 15;
elseif ($params['action'] === 'rv')
list($width, $depth, $height) = array(10, 25, 12);
$conditions[] = "(UnitSize.width/12) >= $width";
$conditions[] = "(UnitSize.depth/12) >= $depth";
if (isset($height))
$conditions[] = array('OR' =>
array("(UnitSize.height/12) >= $height",
//"UnitSize.height IS NULL",
array('UnitType.id' =>
array_keys($this->UnitSize->UnitType->outdoorTypes())),
));
}
return $conditions;
}
function gridDataOrder(&$params, &$model, $index, $direction) {
if ($index == 'UnitType.name')
$index = 'UnitType.code';
$order = parent::gridDataOrder($params, $model, $index, $direction);
// After sorting by whatever the user wants, add these
// defaults into the sort mechanism. If we're already
// sorting by one of them, it will only be redundant,
// and should cause no harm (possible a longer query?)
$order[] = 'UnitType.code ' . $direction;
$order[] = 'sqft ' . $direction;
$order[] = 'UnitSize.rent ' . $direction;
return $order;
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['UnitSize'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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 UnitSize and related fields
$this->UnitSize->id = $id;
$size = $this->UnitSize->find
('first', array
('contain' => array('UnitType'),
'fields' => array('UnitSize.*', 'UnitType.*',
'ROUND(UnitSize.width/12, 1) AS width',
'ROUND(UnitSize.depth/12, 1) AS depth',
'ROUND(UnitSize.height/12, 1) AS height',
'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft',
'ROUND(UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12, 0) AS cuft'),
));
$size['UnitSize'] = $size[0] + $size['UnitSize'];
unset($size[0]);
$this->set(compact('size'));
$this->set('stats', $this->UnitSize->stats($id));
// Prepare to render.
$title = "Unit Size : {$size['UnitSize']['name']}";
$this->set(compact('title'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: edit
* - Edit unit_size information
*/
function edit($id = null) {
$this->INTERNAL_ERROR('NOT READY');
if (isset($this->data)) {
// Check to see if the operation was cancelled.
if (isset($this->params['form']['cancel'])) {
if (empty($this->data['UnitSize']['id']))
$this->redirect(array('action'=>'index'));
$this->redirect(array('action'=>'view', $this->data['UnitSize']['id']));
}
// Make sure we have unit_size data
if (empty($this->data['UnitSize']) || empty($this->data['UnitSize']['id']))
$this->redirect(array('action'=>'index'));
// Save the unit_size and all associated data
$this->UnitSize->create();
$this->UnitSize->id = $this->data['UnitSize']['id'];
if (!$this->UnitSize->save($this->data, false)) {
$this->Session->setFlash("UNIT_SIZE SAVE FAILED", true);
pr("UNIT_SIZE SAVE FAILED");
}
$this->redirect(array('action'=>'view', $this->UnitSize->id));
}
if ($id) {
$this->data = $this->UnitSize->findById($id);
} else {
$this->redirect(array('action'=>'index'));
}
// Prepare to render.
$title = ('UnitSize ' . $this->data['UnitSize']['name'] .
" : Edit");
$this->set(compact('title'));
}
}

View File

@@ -2,26 +2,38 @@
class UnitsController extends AppController {
var $sidemenu_links =
array(array('name' => 'Units', 'header' => true),
array('name' => 'Occupied', 'url' => array('controller' => 'units', 'action' => 'occupied')),
array('name' => 'Vacant', 'url' => array('controller' => 'units', 'action' => 'vacant')),
array('name' => 'Unavailable', 'url' => array('controller' => 'units', 'action' => 'unavailable')),
array('name' => 'All', 'url' => array('controller' => 'units', 'action' => 'all')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
function addGridViewSideMenuLinks() {
parent::addGridViewSideMenuLinks();
$this->addSideMenuLink('Unavailable',
array('controller' => 'units', 'action' => 'unavailable'), null,
'CONTROLLER');
$this->addSideMenuLink('Vacant',
array('controller' => 'units', 'action' => 'vacant'), null,
'CONTROLLER');
$this->addSideMenuLink('Occupied',
array('controller' => 'units', 'action' => 'occupied'), null,
'CONTROLLER');
$this->addSideMenuLink('Overlocked',
array('controller' => 'units', 'action' => 'locked'), null,
'CONTROLLER');
$this->addSideMenuLink('Liened',
array('controller' => 'units', 'action' => 'liened'), null,
'CONTROLLER');
$this->addSideMenuLink('All',
array('controller' => 'units', 'action' => 'all'), null,
'CONTROLLER');
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -33,6 +45,8 @@ class UnitsController extends AppController {
function unavailable() { $this->gridView('Unavailable Units'); }
function vacant() { $this->gridView('Vacant Units'); }
function occupied() { $this->gridView('Occupied Units'); }
function locked() { $this->gridView('Overlocked Units'); }
function liened() { $this->gridView('Liened Units'); }
function all() { $this->gridView('All Units', 'all'); }
@@ -69,6 +83,7 @@ class UnitsController extends AppController {
function gridDataTables(&$params, &$model) {
$link = $this->gridDataCountTables($params, $model);
$link['link']['CurrentLease']['StatementEntry'] = array('fields' => array());
$link['link']['Lock'];
return $link;
}
@@ -81,6 +96,7 @@ class UnitsController extends AppController {
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft';
return array_merge($fields,
$this->Unit->Lease->StatementEntry->chargeDisbursementFields(true));
}
@@ -100,6 +116,12 @@ class UnitsController extends AppController {
elseif ($params['action'] === 'unoccupied') {
$conditions[] = array('NOT' => array($this->Unit->conditionOccupied()));
}
elseif ($params['action'] === 'locked') {
$conditions[] = $this->Unit->conditionLocked();
}
elseif ($params['action'] === 'liened') {
$conditions[] = $this->Unit->conditionLiened();
}
return $conditions;
}
@@ -139,7 +161,7 @@ class UnitsController extends AppController {
$customer = array();
$unit = array();
if (isset($id)) {
if (!empty($id)) {
$this->Unit->recursive = -1;
$unit = current($this->Unit->read(null, $id));
}
@@ -189,6 +211,149 @@ class UnitsController extends AppController {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: lock/unlock/lien
* - Transitions the unit into / out of the LOCKED state
*/
function status($id, $status) {
$this->Unit->updateStatus($id, $status, true);
$this->redirect(array('action' => 'view', $id));
}
function lock($id) {
if (isset($this->data)) {
$id = $this->id = $this->data['Unit']['id'];
// Check to see if the operation was cancelled.
if (isset($this->params['form']['cancel'])) {
if (isset($id))
$this->redirect(array('action'=>'view', $id));
$this->redirect(array('action'=>'index'));
}
// Figure out which locks the user put on
$locks = array();
if (isset($this->data['Lock']) && is_array($this->data['Lock'])) {
foreach ($this->data['Lock'] AS $lock) {
$locks[] = $lock['id'];
}
}
// Save the lock and all associated data
if (!$this->Unit->lockUnit($id, $locks)) {
$this->Session->setFlash("UNIT LOCK FAILED", true);
pr("UNIT LOCK FAILED");
}
// If it's no longer locked, change status to OCCUPIED
// Could still be liened... but that would be odd.
if (count($locks) == 0)
$this->status($id, 'OCCUPIED');
// If we're not liened, we must now just be locked
if (!$this->Unit->liened(intval($id)))
$this->status($id, 'LOCKED');
// Otherwise, don't change anything.
$this->redirect(array('action' => 'view', $id));
}
if (!$id)
$this->INTERNAL_ERROR("$id cannot be NULL");
// Get all locks on this unit
$this->data = $this->Unit->find
('first',
array('contain' => array('Lock' => array('id')),
'fields' => array('id', 'name'),
'conditions' => array('Unit.id' => $id)
));
$locks = $this->Unit->Lock->lockList();
/* $locksold = $locks; */
/* foreach ($locksold AS $name) { */
/* $locks[$name] = $name; */
/* } */
$this->set(compact('locks'));
// Prepare to render.
//pr($this->data);
$this->set(compact('title'));
// $this->render('lock');
}
function unlock($id) { $this->lock($id); }
function lien($id) { $this->status($id, 'LIENED'); }
/**************************************************************************
**************************************************************************
**************************************************************************
* action: overview
* - Displays overview information for all units
*/
function overview() {
$result = $this->Unit->find
('all',
array('link' => array('UnitSize' => array('fields' => array(), 'UnitType' => array('fields' => array('name')))),
'fields' => array('status', 'COUNT(Unit.id) AS cnt', 'SUM(Unit.rent) AS rents'),
//'conditions' => array('
'group' => array('UnitType.id', 'Unit.status'),
'order' => array('UnitType.name', 'Unit.status')
));
$overview = array('types' => array(), 'count' => 0, 'rents' => 0);
foreach ($result AS $row) {
$utname = $row['UnitType']['name'];
if (empty($overview['types'][$utname]))
$overview['types'][$utname] = array('name' => $utname,
'subs' => array(),
'count' => 0,
'rents' => 0,
'phys_pct' => 0,
'econ_pct' => 0);
$type = &$overview['types'][$utname];
$type['subs'][] = array('name' => $row['Unit']['status'],
'count' => $row[0]['cnt'],
'rents' => $row[0]['rents'],
'phys_subpct' => 0,
'phys_totpct' => 0,
'econ_subpct' => 0,
'econ_totpct' => 0);
$type['count'] += $row[0]['cnt'];
$type['rents'] += $row[0]['rents'];
$overview['count'] += $row[0]['cnt'];
$overview['rents'] += $row[0]['rents'];
}
foreach ($overview['types'] AS &$type) {
foreach ($type['subs'] AS &$sub) {
$sub['phys_subpct'] = $sub['count'] / $type['count'];
$sub['econ_subpct'] = $sub['rents'] / $type['rents'];
$sub['phys_totpct'] = $sub['count'] / $overview['count'];
$sub['econ_totpct'] = $sub['rents'] / $overview['rents'];
}
$type['phys_pct'] = $type['count'] / $overview['count'];
$type['econ_pct'] = $type['rents'] / $overview['rents'];
}
// Enable the Reports menu section
$this->sideMenuAreaActivate('REPORT');
// Prepare to render.
$this->set('title', 'Unit Overview');
$this->set(compact('overview'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -207,6 +372,7 @@ class UnitsController extends AppController {
array('contain' =>
array(// Models
'UnitSize',
'Lock',
'Lease' => array('Customer'),
'CurrentLease' => array('Customer')
),
@@ -232,39 +398,59 @@ class UnitsController extends AppController {
$outstanding_deposit = $this->Unit->Lease->securityDepositBalance($unit['CurrentLease']['id']);
}
// Set up dynamic menu items
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
// Add a mechanism to lock ANY unit, regardless of status
$this->addSideMenuLink($this->Unit->lockCount($id) == 0 ? 'Lock' : 'Relock/Unlock',
array('action' => 'lock', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Edit', 'url' => array('action' => 'edit',
$id));
// If the unit is locked, but not liened, give option to lien.
if ($this->Unit->locked($unit['Unit']['status']) &&
!$this->Unit->liened($unit['Unit']['status']))
$this->addSideMenuLink('Lien',
array('action' => 'lien', $id), null,
'ACTION');
if (isset($unit['CurrentLease']['id']) &&
!isset($unit['CurrentLease']['moveout_date'])) {
$this->sidemenu_links[] =
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
$id));
// If there is a current lease on this unit, then provide
// a link to move the tenant out. Current lease for a unit
// has a bit different definition than a current lease for
// a customer, since a lease stays with a customer until it
// is finally closed. A lease, however, only stays with a
// unit while occupied (since a unit is not responsible for
// any lingering financial obligations, like a customer is).
// Of course, if there is no current lease, provide a link
// to move a new tenant in (if the unit is available).
if (isset($unit['CurrentLease']['id'])) {
$this->addSideMenuLink('Move-Out',
array('action' => 'move_out', $id), null,
'ACTION');
} elseif ($this->Unit->available($unit['Unit']['status'])) {
$this->sidemenu_links[] =
array('name' => 'Move-In', 'url' => array('action' => 'move_in',
$id));
$this->addSideMenuLink('Move-In',
array('action' => 'move_in', $id), null,
'ACTION');
} else {
// Unit is unavailable (dirty, damaged, reserved, business-use, etc)
}
if (isset($unit['CurrentLease']['id']) &&
!isset($unit['CurrentLease']['close_date'])) {
$this->sidemenu_links[] =
array('name' => 'Charge', 'url' => array('controller' => 'leases',
'action' => 'invoice',
$unit['CurrentLease']['id']));
$this->sidemenu_links[] =
array('name' => 'Payment', 'url' => array('controller' => 'customers',
'action' => 'receipt',
$unit['CurrentLease']['customer_id']));
// If there is a current lease, allow new charges to
// be added, and payments to be made.
if (isset($unit['CurrentLease']['id'])) {
$this->addSideMenuLink('New Invoice',
array('controller' => 'leases',
'action' => 'invoice',
$unit['CurrentLease']['id']), null,
'ACTION');
$this->addSideMenuLink('New Receipt',
array('controller' => 'customers',
'action' => 'receipt',
$unit['CurrentLease']['customer_id']), null,
'ACTION');
}
// Always allow the unit to be edited.
$this->addSideMenuLink('Edit',
array('action' => 'edit', $id), null,
'ACTION');
// Prepare to render.
$title = 'Unit ' . $unit['Unit']['name'];
$this->set(compact('unit', 'title',
@@ -307,11 +493,6 @@ class UnitsController extends AppController {
}
$this->redirect(array('action'=>'view', $this->Unit->id));
// For debugging, only if the redirects above have been
// commented out, otherwise this section isn't reached.
$this->render('/fake');
return;
}
if ($id) {
@@ -333,7 +514,6 @@ class UnitsController extends AppController {
$this->set(compact('unit_sizes'));
// Prepare to render.
pr($this->data);
$this->set(compact('title'));
}

View File

@@ -0,0 +1,50 @@
<?php
class UtilController extends AppController {
var $uses = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* function: rebuild_box
*/
function rebuild_box($type) {
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
$usrpass = '--user=perki2_pmgruser --password=pmgrauth';
$boxdb = 'perki2_pmgr_' . $type;
$handle = popen("mysqldump $usrpass --opt perki2_pmgr" .
" | mysql $usrpass --database=$boxdb", 'r');
while (($read = fread($handle, 2096))) {
// Do nothing
}
pclose($handle);
$url = $_SERVER['HTTP_REFERER'];
if (empty($url) || $url == 'undefined')
$url = "/$type";
$this->redirect($url);
}
function rebuild_sandbox() { $this->rebuild_box('sand'); }
function rebuild_devbox() { $this->rebuild_box('dev'); }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: logmsg
* - action to allow posting log message data
*/
function logmsg() {
}
}

View File

@@ -121,25 +121,42 @@ class Account extends AppModel {
* - Returns the ID of the desired account
*/
function securityDepositAccountID() { return $this->nameToID('Security Deposit'); }
function rentAccountID() { return $this->nameToID('Rent'); }
function lateChargeAccountID() { return $this->nameToID('Late Charge'); }
function nsfAccountID() { return $this->nameToID('NSF'); }
function nsfChargeAccountID() { return $this->nameToID('NSF Charge'); }
function taxAccountID() { return $this->nameToID('Tax'); }
function accountReceivableAccountID() { return $this->nameToID('A/R'); }
function accountPayableAccountID() { return $this->nameToID('A/P'); }
function cashAccountID() { return $this->nameToID('Cash'); }
function checkAccountID() { return $this->nameToID('Check'); }
function moneyOrderAccountID() { return $this->nameToID('Money Order'); }
function achAccountID() { return $this->nameToID('ACH'); }
function concessionAccountID() { return $this->nameToID('Concession'); }
function waiverAccountID() { return $this->nameToID('Waiver'); }
function pettyCashAccountID() { return $this->nameToID('Petty Cash'); }
function invoiceAccountID() { return $this->nameToID('Invoice'); }
function receiptAccountID() { return $this->nameToID('Receipt'); }
function badDebtAccountID() { return $this->nameToID('Bad Debt'); }
function lookup($name, $check = true) {
$id = $this->nameToID($name);
if (empty($id) && $check)
$this->INTERNAL_ERROR("Missing Account '$name'");
return $id;
}
function securityDepositAccountID() { return $this->lookup('Security Deposit'); }
function rentAccountID() { return $this->lookup('Rent'); }
function lateChargeAccountID() { return $this->lookup('Late Charge'); }
function nsfAccountID() { return $this->lookup('NSF'); }
function nsfChargeAccountID() { return $this->lookup('NSF Charge'); }
function taxAccountID() { return $this->lookup('Tax'); }
function accountReceivableAccountID() { return $this->lookup('A/R'); }
function accountPayableAccountID() { return $this->lookup('A/P'); }
function cashAccountID() { return $this->lookup('Cash'); }
function checkAccountID() { return $this->lookup('Check'); }
function moneyOrderAccountID() { return $this->lookup('Money Order'); }
function achAccountID() { return $this->lookup('ACH'); }
function concessionAccountID() { return $this->lookup('Concession'); }
function waiverAccountID() { return $this->lookup('Waiver'); }
function pettyCashAccountID() { return $this->lookup('Petty Cash'); }
function invoiceAccountID() { return $this->lookup('Invoice'); }
function receiptAccountID() { return $this->lookup('Receipt'); }
function badDebtAccountID() { return $this->lookup('Bad Debt'); }
function customerCreditAccountID() { return $this->lookup(
// REVISIT <AP>: 20090816
// Use of A/R works, and saves an excess of accounts.
// However, a dedicated account is nice, since it can
// quickly be spotted how much is _really_ due, vs
// how much has been pre-paid. Customer credits in
// A/R is not as clear, although a report is an
// obvious solution.
//'A/R'
'Credit'
); }
/**************************************************************************
**************************************************************************
@@ -171,8 +188,7 @@ class Account extends AppModel {
function relatedAccounts($attribute, $extra = null) {
$this->cacheQueries = true;
$accounts = $this->find('all', array
('contain' => array('CurrentLedger'),
'fields' => array('Account.id', 'Account.type', 'Account.name', 'CurrentLedger.id'),
('fields' => array('Account.id', 'Account.name'),
'conditions' => array('Account.'.$attribute => true),
'order' => array('Account.name'),
) + (isset($extra) ? $extra : array())
@@ -196,21 +212,10 @@ class Account extends AppModel {
* - Returns an array of accounts suitable for activity xxx
*/
function invoiceAccounts() {
return $this->relatedAccounts('invoices', array('order' => 'name'));
}
function receiptAccounts() {
return $this->relatedAccounts('receipts', array('order' => 'name'));
}
function depositAccounts() {
return $this->relatedAccounts('deposits', array('order' => 'name'));
}
function refundAccounts() {
return $this->relatedAccounts('refunds', array('order' => 'name'));
}
function invoiceAccounts() { return $this->relatedAccounts('invoices'); }
function receiptAccounts() { return $this->relatedAccounts('receipts'); }
function depositAccounts() { return $this->relatedAccounts('deposits'); }
function refundAccounts() { return $this->relatedAccounts('refunds'); }
/**************************************************************************
@@ -223,13 +228,28 @@ class Account extends AppModel {
function collectableAccounts() {
$accounts = $this->receiptAccounts();
foreach(array($this->nsfAccountID(),
foreach(array($this->customerCreditAccountID(),
$this->securityDepositAccountID(),
$this->nsfAccountID(),
$this->waiverAccountID(),
$this->badDebtAccountID(),
$this->securityDepositAccountID())
//$this->lookup('Closing'),
//$this->lookup('Equity'),
)
AS $account_id) {
$accounts[$account_id] = $this->name($account_id);
}
$accounts['all'] = $accounts['default'] = $accounts;
foreach(array($this->concessionAccountID(),
$this->waiverAccountID(),
$this->badDebtAccountID(),
)
AS $account_id) {
unset($accounts['default'][$account_id]);
}
return $accounts;
}
@@ -345,6 +365,7 @@ class Account extends AppModel {
$this->queryInit($query);
$query['link'] = array('Account' => $query['link']);
$stats = array();
foreach ($this->ledgers($id, $all) AS $ledger)
$this->statsMerge($stats['Ledger'],
$this->Ledger->stats($ledger, $query));

View File

@@ -41,14 +41,15 @@ class Contact extends AppModel {
function saveContact($id, $data) {
// Establish a display name if not already given
if (!$data['Contact']['display_name'])
if (!$data['Contact']['display_name'] &&
$data['Contact']['first_name'] && $data['Contact']['last_name'])
$data['Contact']['display_name'] =
(($data['Contact']['first_name'] &&
$data['Contact']['last_name'])
? $data['Contact']['last_name'] . ', ' . $data['Contact']['first_name']
: ($data['Contact']['first_name']
? $data['Contact']['first_name']
: $data['Contact']['last_name']));
$data['Contact']['last_name'] . ', ' . $data['Contact']['first_name'];
foreach (array('last_name', 'first_name', 'company_name') AS $fld) {
if (!$data['Contact']['display_name'] && $data['Contact'][$fld])
$data['Contact']['display_name'] = $data['Contact'][$fld];
}
// Save the contact data
$this->create();
@@ -90,7 +91,7 @@ class Contact extends AppModel {
// If the user has entered all new data, we need to
// save that as a brand new entry.
if (!isset($item['id'])) {
if (!isset($item['id']) || $item['source'] == 'new') {
$I = new $class();
$I->create();
if (!$I->save($item, false)) {

View File

@@ -20,15 +20,25 @@ class Customer extends AppModel {
),
'Lease',
'StatementEntry',
'ContactsCustomer',
'ContactsCustomer' => array(
// It would be nice to claim a dependency here, which would
// simplify deletion of a customer. However, for this to work
// Cake must have a primaryKey as a single field. This table
// makes use of a complex key, so we're out of luck.
/* 'dependent' => true, */
),
'Transaction',
'Tender',
);
var $hasAndBelongsToMany = array(
'Contact',
'Contact' => array(
'unique' => true,
),
);
//var $default_log_level = 20;
/**************************************************************************
**************************************************************************
@@ -54,17 +64,19 @@ class Customer extends AppModel {
* function: leaseIds
* - Returns the lease IDs for the given customer
*/
function leaseIds($id) {
function leaseIds($id, $current = false) {
$Lease = $current ? 'CurrentLease' : 'Lease';
$this->cacheQueries = true;
$customer = $this->find('first',
array('contain' =>
array('Lease' => array('fields' => array('id'))),
array($Lease => array('fields' => array('id'))),
'fields' => array(),
'conditions' => array(array('Customer.id' => $id))));
$this->cacheQueries = false;
$ids = array();
foreach ($customer['Lease'] AS $lease)
foreach ($customer[$Lease] AS $lease)
$ids[] = $lease['id'];
return $ids;
@@ -101,12 +113,35 @@ class Customer extends AppModel {
$this->prEnter(compact('id', 'query'));
$this->queryInit($query);
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
$query['conditions'][] = array('StatementEntry.account_id' =>
$this->StatementEntry->Account->securityDepositAccountID());
$sd_account_id =
$this->StatementEntry->Account->securityDepositAccountID();
$stats = $this->StatementEntry->stats(null, $query);
return $this->prReturn($stats['account_balance']);
$squery = $query;
$squery['conditions'][] = array('StatementEntry.customer_id' => $id);
$squery['conditions'][] = array('StatementEntry.account_id' => $sd_account_id);
$stats = $this->StatementEntry->stats(null, $squery);
$this->pr(26, compact('squery', 'stats'));
// OK, we know now how much we charged for a security
// deposit, as well as how much we received to pay for it.
// Now we need to know if any has been released.
// Yes... this sucks.
$lquery = $query;
$lquery['link'] = array('Transaction' =>
array('fields' => array(),
'Customer' =>
(empty($query['link'])
? array('fields' => array())
: $query['link'])));
$lquery['conditions'][] = array('Transaction.customer_id' => $id);
$lquery['conditions'][] = array('LedgerEntry.account_id' => $sd_account_id);
$lquery['conditions'][] = array('LedgerEntry.crdr' => 'DEBIT');
$lquery['fields'][] = 'SUM(LedgerEntry.amount) AS total';
$released = $this->StatementEntry->Transaction->LedgerEntry->find
('first', $lquery);
$this->pr(26, compact('lquery', 'released'));
return $this->prReturn($stats['Charge']['disbursement'] - $released[0]['total']);
}
@@ -142,10 +177,8 @@ class Customer extends AppModel {
continue;
$I = new Contact();
$I->create();
if (!$I->save($contact, false)) {
if (!$I->saveContact(null, array('Contact' => $contact)))
return false;
}
$contact['id'] = $I->id;
}
@@ -169,6 +202,13 @@ class Customer extends AppModel {
}
$id = $this->id;
// Appears that $this->save() "helpfully" choses to add in
// any missing data fields, populated with default values.
// So, after saving is complete, the fields 'lease_count',
// 'past_lease_count', and 'current_lease_count' have all
// been reset to zero. Gee, thanks Cake...
$this->update($id);
// Remove all associated Customer Contacts, as it ensures
// any entries deleted by the user actually get deleted
// in the system. We'll recreate the needed ones anyway.
@@ -203,6 +243,162 @@ class Customer extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
$this->prEnter(compact('id'));
if (empty($id)) {
$customers = $this->find('all', array('contain' => false, 'fields' => array('id')));
foreach ($customers AS $customer) {
// This SHOULDN'T happen, but check to be sure
// or we'll get infinite recursion.
if (empty($customer['Customer']['id']))
continue;
$this->update($customer['Customer']['id']);
}
return;
}
// updateLeaseCount is typically handled directly when needed.
// However, this function is used to _ensure_ customer info is
// current, so we're obligated to call it anyway.
$this->updateLeaseCount($id);
$current_leases =
$this->find('all',
// REVISIT <AP>: 20090816
// Do we need to update leases other than the current ones?
// It may be necessary. For example, a non-current lease
// can still be hit with an NSF item. In that case, it
// could have stale data if we look only to current leases.
//array('link' => array('CurrentLease' => array('type' => 'INNER')),
array('link' => array('Lease' => array('type' => 'INNER')),
'conditions' => array('Customer.id' => $id)));
foreach ($current_leases AS $lease) {
if (!empty($lease['CurrentLease']['id']))
$this->Lease->update($lease['CurrentLease']['id']);
if (!empty($lease['Lease']['id']))
$this->Lease->update($lease['Lease']['id']);
}
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: merge
* - Merges two customers into one
*/
function merge($dst_id, $src_id, $contacts) {
$this->prEnter(compact('dst_id', 'src_id', 'contacts'));
// Get the entire list of destination customer contacts
$dst_contacts = array();
$result = $this->find('all',
array('link' => array('ContactsCustomer'),
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
'conditions' => array(array('id' => $dst_id,
'ContactsCustomer.active' => true))));
foreach ($result AS $contact) {
$dst_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
}
$this->pr(17, compact('dst_contacts'));
// Get the entire list of source customer contacts
$src_contacts = array();
$result = $this->find('all',
array('link' => array('ContactsCustomer'),
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
'conditions' => array(array('id' => $src_id,
'ContactsCustomer.active' => true))));
foreach ($result AS $contact) {
$src_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
}
$this->pr(17, compact('src_contacts'));
// Verify the contacts list are all valid source customer contacts
foreach ($contacts AS $contact_id) {
if (!array_key_exists($contact_id, $src_contacts))
return $this->prReturn(false);
}
// Remove any contacts which are already destination customer contacts
$new_contacts = array_diff($contacts, array_keys($dst_contacts));
$all_contacts = array_merge($new_contacts, array_keys($dst_contacts));
$this->pr(17, compact('new_contacts', 'all_contacts'));
// For now, we'll assume the operation will succeed.
$ret = true;
// Add each desired source customer contact to the destination customer
foreach ($new_contacts AS $contact_id) {
$CM = new ContactsCustomer();
if (!$CM->save(array('customer_id' => $dst_id)
+ $src_contacts[$contact_id], false)) {
$ret = false;
}
}
$this->Lease->updateAll
(array('Lease.customer_id' => $dst_id),
array('Lease.customer_id' => $src_id)
);
$this->Tender->updateAll
(array('Tender.customer_id' => $dst_id),
array('Tender.customer_id' => $src_id)
);
$this->StatementEntry->updateAll
(array('StatementEntry.customer_id' => $dst_id),
array('StatementEntry.customer_id' => $src_id)
);
$this->Transaction->updateAll
(array('Transaction.customer_id' => $dst_id),
array('Transaction.customer_id' => $src_id)
);
// Make sure our lease counts, etc are correct
$this->update($dst_id);
// Delete the old customer
$this->pr(12, compact('src_id'), "Delete Customer");
$this->delete($src_id);
// Delete all the orphaned customers
foreach (array_diff(array_keys($src_contacts), $all_contacts) AS $contact_id) {
// Delete un-used or duplicate contacts
// REVISIT <AP> 20100702:
// Not sure if we really want to do this.
// On the one hand, they're probably really redundant,
// and only clutter up the list of all contacts. On the
// other hand, it destroys data, not only losing the
// history, but making it difficult to recover if the
// merge is a mistake. Additionally, we need to do
// extra checking to ensure that the contact is not
// in use by some other customer.
// We need some sort of Contact.deleted field...
$this->pr(12, compact('contact_id'), "Delete Contact");
$this->Contact->delete($contact_id);
}
// Finally, delete all customer contact relationships
$this->ContactsCustomer->deleteAll
(array('customer_id' => $src_id), false);
// Return the result
return $this->prReturn($ret);
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -0,0 +1,21 @@
<?php
class DefaultOption extends AppModel {
var $belongsTo =
array('OptionValue',
);
function values($name = null) {
$this->prEnter(compact('name'));
$query = array();
$this->queryInit($query);
$query['link']['DefaultOption'] = array();
$query['link']['DefaultOption']['type'] = 'INNER';
$query['link']['DefaultOption']['fields'] = array();
return $this->prReturn($this->OptionValue->values($name, $query));
}
}

View File

@@ -0,0 +1,21 @@
<?php
class DefaultPermission extends AppModel {
var $belongsTo =
array('PermissionValue',
);
function values($name = null) {
$this->prEnter(compact('name'));
$query = array();
$this->queryInit($query);
$query['link']['DefaultPermission'] = array();
$query['link']['DefaultPermission']['type'] = 'INNER';
$query['link']['DefaultPermission']['fields'] = array();
return $this->prReturn($this->PermissionValue->values($name, $query));
}
}

View File

@@ -53,12 +53,27 @@ class DoubleEntry extends AppModel {
*/
function addDoubleEntry($entry1, $entry2, $entry1_tender = null) {
/* pr(array('DoubleEntry::addDoubleEntry' => */
/* compact('entry1', 'entry2', 'entry1_tender'))); */
//$this->prFunctionLevel(16);
$this->prEnter(compact('entry1', 'entry2', 'entry1_tender'));
$ret = array();
if (!$this->verifyDoubleEntry($entry1, $entry2, $entry1_tender))
return array('error' => true) + $ret;
return $this->prReturn(array('error' => true) + $ret);
// Handle the case where a double entry involves the same
// exact ledger. This would not serve any useful purpose.
// It is not, however, an error. It is semantically correct
// just not really logically correct. To make this easier,
// just ensure ledger_id is set for each entry, even though
// it would be handled later by the LedgerEntry model.
//array($entry1, $entry2) AS &$entry) {
for ($i=1; $i <= 2; ++$i) {
if (empty(${'entry'.$i}['ledger_id']))
${'entry'.$i}['ledger_id'] =
$this->DebitEntry->Account->currentLedgerID(${'entry'.$i}['account_id']);
}
if ($entry1['ledger_id'] == $entry2['ledger_id'])
return $this->prReturn(array('error' => false));
// Since this model only relates to DebitEntry and CreditEntry...
$LE = new LedgerEntry();
@@ -67,13 +82,13 @@ class DoubleEntry extends AppModel {
$result = $LE->addLedgerEntry($entry1, $entry1_tender);
$ret['Entry1'] = $result;
if ($result['error'])
return array('error' => true) + $ret;
return $this->prReturn(array('error' => true) + $ret);
// Add the second ledger entry to the database
$result = $LE->addLedgerEntry($entry2);
$ret['Entry2'] = $result;
if ($result['error'])
return array('error' => true) + $ret;
return $this->prReturn(array('error' => true) + $ret);
// Now link them as a double entry
$double_entry = array();
@@ -82,15 +97,13 @@ class DoubleEntry extends AppModel {
$double_entry['credit_entry_id'] =
($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
/* pr(array('DoubleEntry::addDoubleEntry' => */
/* array('checkpoint' => 'Pre-Save') */
/* + compact('double_entry'))); */
$ret['data'] = $double_entry;
$this->create();
if (!$this->save($double_entry))
return array('error' => true) + $ret;
return $this->prReturn(array('error' => true) + $ret);
$ret['double_entry_id'] = $this->id;
return $ret + array('error' => false);
return $this->prReturn($ret + array('error' => false));
}
}

38
site/models/group.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
class Group extends AppModel {
var $hasMany =
array('GroupOption',
'Membership',
);
var $knows =
array('User',
'Site',
);
static $current_group_ids;
function currentGroupIds() {
if (empty(self::$current_group_ids))
self::$current_group_ids = $this->groupIds();
if (empty(self::$current_group_ids))
// We must force a stop here, since this is typically
// called very early on, and so will cause a recursive
// crash as we try to render the internal error and
// again stumble on this problem.
$this->INTERNAL_ERROR('INVALID MEMBERSHIP', 0, true);
return self::$current_group_ids;
}
function groupIds($user_id = null, $site_id = null) {
if (empty($user_id))
$user_id = $this->User->currentUserId();
if (empty($site_id))
$site_id = $this->Site->currentSiteId();
return $this->Membership->memberGroups($user_id, $site_id);
}
}

View File

@@ -0,0 +1,25 @@
<?php
class GroupOption extends AppModel {
var $belongsTo =
array('Group',
'OptionValue',
);
function values($ids, $name = null) {
$this->prEnter(compact('id', 'name'));
$query = array();
$this->queryInit($query);
$query['link']['GroupOption'] = array();
$query['link']['GroupOption']['fields'] = array();
$query['link']['GroupOption']['Group'] = array();
$query['link']['GroupOption']['Group']['fields'] = array();
$query['conditions'][] = array('Group.id' => $ids);
$query['order'][] = 'Group.rank';
return $this->prReturn($this->OptionValue->values($name, $query));
}
}

View File

@@ -0,0 +1,25 @@
<?php
class GroupPermission extends AppModel {
var $belongsTo =
array('Group',
'PermissionValue',
);
function values($ids, $name = null) {
$this->prEnter(compact('id', 'name'));
$query = array();
$this->queryInit($query);
$query['link']['GroupPermission'] = array();
$query['link']['GroupPermission']['fields'] = array();
$query['link']['GroupPermission']['Group'] = array();
$query['link']['GroupPermission']['Group']['fields'] = array();
$query['conditions'][] = array('Group.id' => $ids);
$query['order'][] = 'Group.rank';
return $this->prReturn($this->PermissionValue->values($name, $query));
}
}

View File

@@ -12,7 +12,7 @@ class Lease extends AppModel {
'StatementEntry',
);
//var $default_log_level = array('log' => 30, 'show' => 15);
//var $default_log_level = array('log' => 30, 'show' => 30);
/**************************************************************************
**************************************************************************
@@ -148,8 +148,11 @@ class Lease extends AppModel {
array('class' => 'StatementEntry',
'fields' => array(),
'conditions' => array
('SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
'SEx.lease_id = StatementEntry.lease_id',
('SEx.lease_id = StatementEntry.lease_id',
'SEx.type' => 'CHARGE',
'SEx.account_id' => $rent_account_id,
'SEx.reverse_transaction_id IS NULL',
'SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
),
),
),
@@ -159,6 +162,7 @@ class Lease extends AppModel {
'conditions' => array(array('Lease.id' => $id),
array('StatementEntry.type' => 'CHARGE'),
array('StatementEntry.account_id' => $rent_account_id),
array('StatementEntry.reverse_transaction_id IS NULL'),
array('SEx.id' => null),
),
)
@@ -259,7 +263,9 @@ class Lease extends AppModel {
'conditions' =>
array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id)),
array('StatementEntry.account_id' => $rent_account_id),
array('StatementEntry.reverse_transaction_id IS NULL'),
),
'order' => array('StatementEntry.effective_date'),
),
@@ -278,7 +284,9 @@ class Lease extends AppModel {
('CHARGE',
array('conditions' =>
array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id)),
array('StatementEntry.account_id' => $rent_account_id),
array('StatementEntry.reverse_transaction_id IS NULL'),
),
'order' => array('StatementEntry.through_date DESC'),
),
@@ -339,6 +347,8 @@ class Lease extends AppModel {
$this->pr(17, compact('date', 'charge_through_date')
+ array('date_str' => date('Y-m-d', $date),
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
if (!$charge_through_date)
return $this->prReturn(null);
if ($charge_through_date >= $date)
return $this->prReturn(null);
@@ -408,7 +418,6 @@ class Lease extends AppModel {
*/
function assessMonthlyLate($id, $date = null) {
$this->prFunctionLevel(25);
$this->prEnter(compact('id', 'date'));
$this->id = $id;
@@ -426,6 +435,17 @@ class Lease extends AppModel {
$date = mktime(0, 0, 0, $date_parts['mon'], 11, $date_parts['year']);
}
// Don't assess a late charge if the late charge date hasn't
// even come yet. This is questionable whether we really
// should restrict, since the user could know what they're
// doing, and/or the server clock could be off (although that
// would certainly have much larger ramifications). But, the
// fact is that this check likely handles the vast majority
// of the expected behavior, and presents an issue for very
// few users, if any at all.
if ($date > time())
return $this->prReturn(null);
// Make sure we're not trying to assess late charges on a closed lease
$close_date = $this->field('close_date');
$this->pr(17, compact('close_date'));
@@ -449,6 +469,10 @@ class Lease extends AppModel {
// Determine if the customer is actually late. This is based on
// when they've paid through, plus 10 days before they're late.
// REVISIT <AP>: 20090813
// Of course, 10 days is a terrible hardcode. This should be
// driven from the late schedule, saved as part of the lease
// (when finally implemented).
$paid_through_date = strtotime($this->rentPaidThrough($id));
$this->pr(17, compact('date', 'paid_through_date')
+ array('date_str' => date('Y-m-d', $date),
@@ -512,6 +536,31 @@ class Lease extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* functions: delinquency
* - SQL fragments to determine whether a lease is delinquent
*/
function conditionDelinquent($table_name = 'Lease') {
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
return ("({$t}close_date IS NULL AND" .
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 1 DAY))");
}
function delinquentDaysSQL($table_name = 'Lease') {
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
return ("IF(" . $this->conditionDelinquent($table_name) . "," .
" DATEDIFF(NOW(), {$t}paid_through_date)-1," .
" NULL)");
}
function delinquentField($table_name = 'Lease') {
return ($this->delinquentDaysSQL($table_name) . " AS 'delinquent'");
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -610,7 +659,7 @@ class Lease extends AppModel {
*/
function moveOut($id, $status = 'VACANT',
$stamp = null, $close = false)
$stamp = null, $close = true)
{
$this->prEnter(compact('id', 'status', 'stamp', 'close'));
@@ -679,6 +728,53 @@ class Lease extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reopen
* - Re-Opens the lease for further action
*/
function reopen($id) {
$this->prEnter(compact('id'));
if (!$this->isClosed($id))
return $this->prReturn(false);
// Reset the data
$this->create();
$this->id = $id;
// Set the close date
$this->data['Lease']['close_date'] = null;
// Save it!
$this->save($this->data, false);
// Update the current lease count for the customer
$this->Customer->updateLeaseCount($this->field('customer_id'));
return $this->prReturn(true);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: isClosed
* - Checks to see if the lease is closed
*/
function isClosed($id) {
$this->prEnter(compact('id'));
$this->recursive = -1;
$this->read(null, $id);
return $this->prReturn(!empty($this->data['Lease']['close_date']));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -745,6 +841,25 @@ class Lease extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
$this->prEnter(compact('id'));
$this->id = $id;
$this->saveField('charge_through_date', $this->rentChargeThrough($id));
$this->saveField('paid_through_date', $this->rentPaidThrough($id));
$moveout = $this->field('moveout_date');
if (empty($moveout))
$this->Unit->update($this->field('unit_id'));
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -8,8 +8,22 @@ class LedgerEntry extends AppModel {
);
var $hasOne = array(
'Tender',
'DoubleEntry',
'Tender' => array(
'dependent' => true,
),
'DebitDoubleEntry' => array(
'className' => 'DoubleEntry',
'foreignKey' => 'debit_entry_id',
'dependent' => true,
),
'CreditDoubleEntry' => array(
'className' => 'DoubleEntry',
'foreignKey' => 'credit_entry_id',
'dependent' => true,
),
'DoubleEntry' => array(
'foreignKey' => false,
),
);
var $hasMany = array(
@@ -113,24 +127,20 @@ class LedgerEntry extends AppModel {
* - Inserts new Ledger Entry into the database
*/
function addLedgerEntry($entry, $tender = null) {
/* pr(array('LedgerEntry::addLedgerEntry' => */
/* compact('entry', 'tender'))); */
//$this->prFunctionLevel(16);
$this->prEnter(compact('entry', 'tender'));
$ret = array();
$ret = array('data' => $entry);
if (!$this->verifyLedgerEntry($entry, $tender))
return array('error' => true) + $ret;
return $this->prReturn(array('error' => true) + $ret);
if (empty($entry['ledger_id']))
$entry['ledger_id'] =
$this->Account->currentLedgerID($entry['account_id']);
/* pr(array('LedgerEntry::addLedgerEntry' => */
/* array('checkpoint' => 'Pre-Save') */
/* + compact('entry'))); */
$this->create();
if (!$this->save($entry))
return array('error' => true) + $ret;
return $this->prReturn(array('error' => true) + $ret);
$ret['ledger_entry_id'] = $this->id;
@@ -140,10 +150,10 @@ class LedgerEntry extends AppModel {
$result = $this->Tender->addTender($tender);
$ret['Tender'] = $result;
if ($result['error'])
return array('error' => true) + $ret;
return $this->prReturn(array('error' => true) + $ret);
}
return $ret + array('error' => false);
return $this->prReturn($ret + array('error' => false));
}
@@ -155,53 +165,13 @@ class LedgerEntry extends AppModel {
*/
function stats($id = null, $query = null, $set = null) {
$this->queryInit($query);
unset($query['group']);
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
/* if (!isset($query['link']['DoubleEntry']['fields'])) */
/* $query['link']['DoubleEntry']['fields'] = array(); */
if (isset($id))
$query['conditions'][] = array('Entry.id' => $id);
if (isset($set))
$set = strtoupper($set);
//pr(array('stats()', compact('id', 'query', 'set')));
$rtypes = array('charge', 'disbursement',
// 'debit', 'credit',
);
$stats = array();
foreach($rtypes AS $rtype) {
$Rtype = ucfirst($rtype);
if (($rtype == 'charge' && (!isset($set) || $set == 'DISBURSEMENT')) ||
($rtype == 'disbursement' && (!isset($set) || $set == 'CHARGE'))
) {
$rquery = $query;
$rquery['link'][$Rtype] =
array('fields' => array("SUM(COALESCE(Applied{$Rtype}.amount,0)) AS reconciled"));
$rquery['fields'] = array();
//$rquery['fields'][] = "SUM(DoubleEntry.amount) AS total";
$rquery['fields'][] = "SUM(DoubleEntry.amount) - SUM(COALESCE(Applied{$Rtype}.amount,0)) AS balance";
$rquery['conditions'][] = array("Applied{$Rtype}.id !=" => null);
$result = $this->find('first', $rquery);
//pr(compact('Rtype', 'rquery', 'result'));
$sumfld = $Rtype;
$stats[$sumfld] = $result[0];
/* if (!isset($stats[$sumfld]['applied'])) */
/* $stats[$sumfld]['applied'] = 0; */
}
}
return $stats;
// REVISIT <AP>: 20090816
// This function appeared to be dramatically broken,
// a throwback to an earlier time. I deleted its
// contents and added this error to ensure it does
// not get used.
$this->INTERNAL_ERROR('This function should not be used');
}
}

110
site/models/lock.php Normal file
View File

@@ -0,0 +1,110 @@
<?php
class Lock extends AppModel {
var $name = 'Lock';
var $validate = array(
'id' => array('numeric'),
'name' => array('notempty'),
'key' => array('notempty')
);
var $hasMany = array(
'LocksUnits'
);
var $hasAndBelongsToMany = array(
'Unit'
);
var $default_log_level = array('log' => 30, 'show' => 15);
/**************************************************************************
**************************************************************************
**************************************************************************
* function: saveLock
* - save data about a new or existing lock
*/
function saveLock($data) {
$this->prEnter(compact('data'));
$id = $data['Lock']['id'];
if ($id) {
$this->id = $id;
// Save the old key
$oldkey = $this->field('key');
$this->pr(5, compact('oldkey'));
if ($this->field('key') != $data['Lock']['key']) {
$data['Lock']['key_last'] = $this->field('key');
$data['Lock']['key_ts'] = date('Y-m-d G:i:s');
}
/* // Find the number of outstanding locks in use */
/* $locks = $this->find('first', */
/* array('link' => array('Unit' => array('fields' => array('Unit.id'))), */
/* 'fields' => 'SUM(Unit.id) AS inuse', */
/* 'conditions' => array('Lock.id' => $id), */
/* )); */
/* $this->pr(5, compact('locks')); */
/* // Can't reduce the locks if there are all in use */
/* if ($locks[0]['inuse'] > $data['Lock']['qty']) */
/* return $this->prReturn(false); */
}
else {
// Brand new lock
}
if (!$data['Lock']['qty'])
$data['Lock']['qty'] = 1;
// Everything looks good... save it!
return $this->prReturn($this->save($data, false));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: destroy
* - destroys a lock
*/
function destroy($id) {
$this->prEnter(compact('id'));
// Can't delete a lock that's in use... check.
$this->id = $id;
$lock = $this->find
('first', array
('contain' => array('Unit'),
));
// If it's in use, bail with error
$this->pr(1, $lock);
if (isset($lock['Unit']) && count($lock['Unit']) > 0)
return $this->prReturn(false);
// Otherwise, attempt to delete the lock from the database
return $this->prReturn($this->delete());
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: lockList
* - list of all locks in the system
*/
function lockList() {
return $this->find('list',
array('order' =>
array('name'),
));
}
}

View File

@@ -0,0 +1,11 @@
<?php
class LocksUnit extends AppModel {
var $primaryKey = false;
var $belongsTo = array(
'Lock',
'Unit',
);
}
?>

View File

@@ -1,15 +0,0 @@
<?php
class MapsUnit extends AppModel {
var $name = 'MapsUnit';
var $validate = array(
'id' => array('numeric'),
'map_id' => array('numeric'),
'unit_id' => array('numeric'),
'pt_top' => array('numeric'),
'pt_left' => array('numeric'),
'transpose' => array('boolean')
);
}
?>

View File

@@ -0,0 +1,37 @@
<?php
class Membership extends AppModel {
var $belongsTo =
array('User',
'Site',
'Group'
);
function memberGroups($user_id, $site_id) {
$this->prEnter(compact('user_id', 'site_id'));
$this->cacheQueries = true;
$groups = $this->find('all', array
('recursive' => -1,
'fields' => array('group_id'),
'conditions' => array(array('user_id' => $user_id),
array('site_id' => $site_id)),
));
$this->cacheQueries = false;
if (empty($groups))
return $this->prReturn(null);
$group_ids = array();
foreach ($groups AS $group)
$group_ids[] = $group['Membership']['group_id'];
return $this->prReturn($group_ids);
}
function memberOf($user_id, $site_id) {
$groups = $this->memberGroups($user_id, $site_id);
return (!empty($groups));
}
}

76
site/models/option.php Normal file
View File

@@ -0,0 +1,76 @@
<?php
class Option extends AppModel {
var $hasMany =
array('OptionValue',
);
var $knows =
array('User', 'Site', 'Group');
static $option_set = array();
function getAll($name, $force = false) {
/* $this->prClassLevel(30); */
/* //$this->OptionValue->prClassLevel(30); */
/* $this->Group->Membership->prClassLevel(30); */
/* $this->OptionValue->SiteOption->prClassLevel(30); */
/* $this->OptionValue->UserOption->prClassLevel(30); */
/* $this->OptionValue->GroupOption->prClassLevel(30); */
/* $this->OptionValue->DefaultOption->prClassLevel(30); */
$this->prEnter(compact('name'));
if (!empty(self::$option_set[$name]) && !$force)
return $this->prReturn(self::$option_set[$name]);
self::$option_set[$name] = array();
$site_id = $this->Site->currentSiteId();
$user_id = $this->User->currentUserId();
$group_ids = $this->Group->currentGroupIds();
/* $site_id = 2; */
/* $user_id = 4; */
/* $group_ids = $this->Group->groupIds($user_id, $site_id); */
if (!empty($site_id))
self::$option_set[$name] =
array_merge(self::$option_set[$name],
$this->OptionValue->SiteOption->values($site_id, $name));
if (!empty($user_id))
self::$option_set[$name] =
array_merge(self::$option_set[$name],
$this->OptionValue->UserOption->values($user_id, $name));
if (!empty($group_ids))
self::$option_set[$name] =
array_merge(self::$option_set[$name],
$this->OptionValue->GroupOption->values($group_ids, $name));
self::$option_set[$name] =
array_merge(self::$option_set[$name],
$this->OptionValue->DefaultOption->values($name));
return $this->prReturn(self::$option_set[$name]);
}
function get($name) {
$this->prEnter(compact('name'));
$values = $this->getAll($name);
if (empty($values))
return null;
return $this->prReturn($values[0]);
}
function enabled($name) {
$val = $this->get($name);
return (!empty($val));
}
function disabled($name) {
return (!$this->enabled($name));
}
}

View File

@@ -0,0 +1,35 @@
<?php
class OptionValue extends AppModel {
var $belongsTo =
array('Option',
);
var $hasMany =
array('UserOption',
'SiteOption',
'GroupOption',
'DefaultOption',
);
function values($name = null, $query = null) {
$this->prEnter(compact('name', 'query'));
$this->queryInit($query);
$query['link']['Option'] = array();
if (!empty($name)) {
$query['conditions'][] = array('Option.name' => $name);
$query['link']['Option']['fields'] = array();
}
$this->cacheQueries = true;
$values = array();
foreach ($this->find('all', $query) AS $result)
$values[] = $result['OptionValue']['value'];
$this->cacheQueries = false;
return $this->prReturn($values);
}
}

105
site/models/permission.php Normal file
View File

@@ -0,0 +1,105 @@
<?php
class Permission extends AppModel {
var $hasMany =
array('PermissionValue',
);
var $knows =
array('User', 'Site', 'Group');
static $permission_set = array();
function getAll($name, $force = false) {
/* $this->prClassLevel(30); */
/* $this->PermissionValue->prClassLevel(30); */
/* $this->Group->Membership->prClassLevel(30); */
/* $this->PermissionValue->SitePermission->prClassLevel(30); */
/* $this->PermissionValue->UserPermission->prClassLevel(30); */
/* $this->PermissionValue->GroupPermission->prClassLevel(30); */
/* $this->PermissionValue->DefaultPermission->prClassLevel(30); */
$this->prEnter(compact('name'));
if (!empty(self::$permission_set[$name]) && !$force)
return $this->prReturn(self::$permission_set[$name]);
self::$permission_set[$name] = array();
$site_id = $this->Site->currentSiteId();
$user_id = $this->User->currentUserId();
$group_ids = $this->Group->currentGroupIds();
/* $site_id = 1; */
/* $user_id = 2; */
/* $group_ids = $this->Group->groupIds($user_id, $site_id); */
if (empty($group_ids)) {
self::$permission_set[$name][$name][] = array('access' => 'DENY', 'level' => null);
$site_id = null;
$user_id = null;
}
if (!empty($site_id))
self::$permission_set[$name] =
array_merge(self::$permission_set[$name],
$this->PermissionValue->SitePermission->values($site_id, $name));
if (!empty($user_id))
self::$permission_set[$name] =
array_merge(self::$permission_set[$name],
$this->PermissionValue->UserPermission->values($user_id, $name));
if (!empty($group_ids)) {
self::$permission_set[$name] =
array_merge(self::$permission_set[$name],
$this->PermissionValue->GroupPermission->values($group_ids, $name));
self::$permission_set[$name] =
array_merge(self::$permission_set[$name],
$this->PermissionValue->DefaultPermission->values($name));
self::$permission_set[$name][] = array('access' => 'ALLOW', 'level' => null);
}
return $this->prReturn(self::$permission_set[$name]);
}
function get($name) {
$this->prEnter(compact('name'));
// REVISIT <AP>: 20090827
// This is a pretty crappy algorithm. How do we decide whether DENY really
// means DENY, or whether an ALLOW has priority.
// Oh well, it works for now...
$values = $this->getAll($name);
$result = array_shift($values);
foreach ($values AS $value)
if (empty($result['level']) || (!empty($value['level']) && $value['level'] < $result['level']))
$result['level'] = $value['level'];
if ($result['access'] !== 'ALLOW')
$result['level'] = 9999999;
return $this->prReturn($result);
}
function allow($name) {
$this->prEnter(compact('name'));
$result = $this->get($name);
return $this->prReturn($result['access'] === 'ALLOW');
}
function deny($name) {
$this->prEnter(compact('name'));
return $this->prReturn(!$this->allow($name));
}
function level($name) {
$this->prEnter(compact('name'));
$result = $this->get($name);
return $this->prReturn($result['level']);
}
}

View File

@@ -0,0 +1,36 @@
<?php
class PermissionValue extends AppModel {
var $belongsTo =
array('Permission',
);
var $hasMany =
array('UserPermission',
'SitePermission',
'GroupPermission',
'DefaultPermission',
);
function values($name = null, $query = null) {
$this->prEnter(compact('name', 'query'));
$this->queryInit($query);
$query['link']['Permission'] = array();
if (!empty($name)) {
$query['conditions'][] = array('Permission.name' => $name);
$query['link']['Permission']['fields'] = array();
}
$this->cacheQueries = true;
$values = array();
foreach ($this->find('all', $query) AS $result)
$values[] = array('access' => $result['PermissionValue']['access'],
'level' => $result['PermissionValue']['level']);
$this->cacheQueries = false;
return $this->prReturn($values);
}
}

View File

@@ -1,16 +1,37 @@
<?php
class Site extends AppModel {
var $name = 'Site';
var $validate = array(
'id' => array('numeric'),
'name' => array('notempty')
);
var $hasMany =
array('SiteArea',
'SiteOption',
'Membership',
);
var $hasMany = array(
'SiteArea',
'SiteOption',
);
static $current_site_id;
function currentSiteId() {
if (!empty(self::$current_site_id))
return self::$current_site_id;
// REVISIT <AP>: 20090827
// Must get the actual site
$code = 'VSS';
$site = $this->find
('first',
array('recursive' => -1,
'conditions' => compact('code')));
if (!empty($site['Site']['id']))
self::$current_site_id = $site['Site']['id'];
else
// We must force a stop here, since this is typically
// called very early on, and so will cause a recursive
// crash as we try to render the internal error and
// again stumble on this problem.
$this->INTERNAL_ERROR('UNKNOWN SITE', 0, true);
return self::$current_site_id;
}
}
?>

View File

@@ -0,0 +1,24 @@
<?php
class SiteOption extends AppModel {
var $belongsTo =
array('Site',
'OptionValue',
);
function values($id, $name = null) {
$this->prEnter(compact('id', 'name'));
$query = array();
$this->queryInit($query);
$query['link']['SiteOption'] = array();
$query['link']['SiteOption']['fields'] = array();
$query['link']['SiteOption']['Site'] = array();
$query['link']['SiteOption']['Site']['fields'] = array();
$query['conditions'][] = array('Site.id' => $id);
return $this->prReturn($this->OptionValue->values($name, $query));
}
}

View File

@@ -0,0 +1,24 @@
<?php
class SitePermission extends AppModel {
var $belongsTo =
array('Site',
'PermissionValue',
);
function values($id, $name = null) {
$this->prEnter(compact('id', 'name'));
$query = array();
$this->queryInit($query);
$query['link']['SitePermission'] = array();
$query['link']['SitePermission']['fields'] = array();
$query['link']['SitePermission']['Site'] = array();
$query['link']['SitePermission']['Site']['fields'] = array();
$query['conditions'][] = array('Site.id' => $id);
return $this->prReturn($this->PermissionValue->values($name, $query));
}
}

View File

@@ -18,11 +18,13 @@ class StatementEntry extends AppModel {
'DisbursementEntry' => array(
'className' => 'StatementEntry',
'foreignKey' => 'charge_entry_id',
'dependent' => true,
),
);
//var $default_log_level = array('log' => 30, 'show' => 15);
var $max_log_level = 19;
/**************************************************************************
**************************************************************************
@@ -123,13 +125,10 @@ class StatementEntry extends AppModel {
function addStatementEntry($entry) {
$this->prEnter(compact('entry'));
$ret = array();
$ret = array('data' => $entry);
if (!$this->verifyStatementEntry($entry))
return $this->prReturn(array('error' => true, 'verify_data' => $entry) + $ret);
$this->pr(20, array('checkpoint' => 'Pre-Save')
+ compact('entry'));
$this->create();
if (!$this->save($entry))
return $this->prReturn(array('error' => true, 'save_data' => $entry) + $ret);
@@ -155,7 +154,7 @@ class StatementEntry extends AppModel {
$charge = $charge['StatementEntry'];
if ($charge['type'] !== 'CHARGE')
INTERNAL_ERROR("Waiver item is not CHARGE.");
$this->INTERNAL_ERROR("Waiver item is not CHARGE.");
// Query the stats to get the remaining balance
$stats = $this->stats($id);
@@ -168,7 +167,6 @@ class StatementEntry extends AppModel {
// Add the charge waiver
$waiver['Entry'][] =
array('amount' => $stats['Charge']['balance'],
'account_id' => $this->Account->waiverAccountID(),
'comment' => null,
);
@@ -178,89 +176,64 @@ class StatementEntry extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reversable
* - Returns true if the charge can be reversed; false otherwise
*/
function reversable($id) {
$this->prEnter(compact('id'));
if (empty($id))
return $this->prReturn(false);
// Verify the item is an actual charge
$this->id = $id;
$charge_type = $this->field('type');
if ($charge_type !== 'CHARGE')
return $this->prReturn(false);
// Determine anything reconciled against the charge
$reverse_transaction_id = $this->field('reverse_transaction_id');
if (!empty($reverse_transaction_id))
return $this->prReturn(false);
return $this->prReturn(true);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reverse
* - Reverses the charges
*
*/
function reverse($id, $balance = false, $stamp = null) {
$this->prEnter(compact('id', 'balance', 'stamp'));
function reverse($id, $stamp = null, $comment) {
$this->prEnter(compact('id', 'stamp'));
$ret = array();
// Verify the item can be reversed
if (!$this->reversable($id))
$this->INTERNAL_ERROR("Item is not reversable.");
// Get the basic information about the entry to be reversed.
$this->recursive = -1;
$charge = $this->read(null, $id);
$charge = $charge['StatementEntry'];
if ($charge['type'] !== 'CHARGE')
INTERNAL_ERROR("Reversal item is not CHARGE.");
$voided_entry_transactions = array();
$reconciled = $this->reconciledEntries($id);
$this->pr(21, compact('reconciled'));
if ($reconciled && !$balance) {
foreach ($reconciled['entries'] AS $entry) {
if ($entry['DisbursementEntry']['type'] === 'REVERSAL')
INTERNAL_ERROR("Charge has already been reversed");
$voided_entry_transactions[$entry['DisbursementEntry']['transaction_id']]
= array_intersect_key($entry['DisbursementEntry'],
array('customer_id'=>1, 'lease_id'=>1));
$this->del($entry['DisbursementEntry']['id']);
continue;
$DE = new StatementEntry();
$DE->id = $entry['DisbursementEntry']['id'];
$DE->saveField('type', 'VOID');
$DE->saveField('charge_entry_id', null);
}
$this->pr(17, compact('voided_entry_transactions'));
}
// Get the basic information about this charge
$charge = $this->find('first', array('contain' => true));
//$charge = $charge['StatementEntry'];
// Query the stats to get the remaining balance
$stats = $this->stats($id);
// Build a transaction
$reversal = array('Transaction' => array(), 'Entry' => array());
$reversal['Transaction']['stamp'] = $stamp;
$reversal['Transaction']['comment'] = "Credit Note: Charge Reversal";
// Add the charge reversal
$reversal['Entry'][] =
array('amount' => $stats['Charge']['balance'],
'account_id' => $charge['account_id'],
'comment' => 'Charge Reversal',
);
$charge['paid'] = $stats['Charge']['disbursement'];
// Record the reversal transaction
$result = $this->Transaction->addReversal
($reversal, $id, $charge['customer_id'], $charge['lease_id']);
$this->pr(21, compact('result'));
$ret['reversal'] = $result;
if ($result['error'])
$ret['error'] = true;
($charge, $stamp, $comment ? $comment : 'Charge Reversal');
foreach ($voided_entry_transactions AS $transaction_id => $tx) {
$result = $this->assignCredits
(null,
$transaction_id,
null,
null,
$tx['customer_id'],
$tx['lease_id']
);
$this->pr(21, compact('result'));
$ret['assigned'][] = $result;
if ($result['error'])
$ret['error'] = true;
if (empty($result['error'])) {
// Mark the charge as reversed
$this->id = $id;
$this->saveField('reverse_transaction_id', $result['transaction_id']);
}
return $this->prReturn($ret + array('error' => false));
return $this->prReturn($result);
}
@@ -321,7 +294,7 @@ class StatementEntry extends AppModel {
}
return $this->prReturn(array('entries' => $resultset,
'summary' => $this->stats(null, $query)));
'summary' => $this->stats(null, $query)));
}
@@ -365,6 +338,72 @@ class StatementEntry extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: outstandingDebits
* - Determines all debit types that have not yet been resolved.
* The name is a bit dumb, but it means any statement entry type
* that a positive customer balance could be used to offset. In
* other words, entries that are still in need of matching
* disbursements. Most notably, this means charges but could
* also mean things like refunds as well.
*/
function outstandingDebits($query = null, $customer_id = null,
$lease_id = null, $debit_types = null)
{
$this->prEnter(compact('query', 'lease_id',
'customer_id', 'charge_ids',
'debit_types'));
$this->queryInit($query);
if (empty($debit_types))
$debit_types = $this->debitTypes();
if (!empty($customer_id))
$query['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
if (!empty($lease_id))
$query['conditions'][] = array('StatementEntry.lease_id' => $lease_id);
/* if (isset($charge_ids)) { */
/* // REVISIT <AP> 20100330: */
/* // Not using $query here, as this code was extracted from its */
/* // original location in assignCredits, and so I'm keeping the */
/* // logic consistent. It does seem, however, that we shouldn't */
/* // be ignoring $query if passed in. I'm sure this won't be */
/* // looked at until someone _does_ pass $query in (and it break), */
/* // so hopefully at that time, we can understand what needs to */
/* // happen in that case (requirements are not clear at present). */
/* $lquery = array('contain' => false, */
/* 'conditions' => array('StatementEntry.id' => $charge_ids)); */
/* } else { */
/* $lquery = $query; */
/* // If we're working with a specific lease, then limit charges to it */
/* if (!empty($lease_id)) */
/* $lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id); */
/* } */
if (empty($query['order']))
$query['order'] = 'StatementEntry.effective_date ASC';
$debits = array();
foreach ($debit_types AS $dtype) {
$rset = $this->reconciledSet($dtype, $query, true);
$entries = $rset['entries'];
$debits = array_merge($debits, $entries);
$this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries");
}
return $this->prReturn($debits);
}
function outstandingCharges($query = null, $customer_id = null, $lease_id = null) {
return $this->outstandingDebits($query, $customer_id, $lease_id, array('CHARGE'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -386,9 +425,6 @@ class StatementEntry extends AppModel {
'customer_id', 'lease_id'));
$this->queryInit($query);
if (!empty($customer_id))
$query['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
if (empty($disbursement_type))
$disbursement_type = 'DISBURSEMENT';
@@ -396,11 +432,15 @@ class StatementEntry extends AppModel {
// First, find all known credits, unless this call is to make
// credit adjustments to a specific charge
// REVISIT <AP>: 20090806
// If the theory below is correct, we should only search for
// explicit credits if we don't have a receipt_id
if (empty($charge_ids)) {
if (empty($receipt_id)) {
if (!empty($charge_ids))
$this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt");
$lquery = $query;
if (!empty($customer_id))
$lquery['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
// REVISIT <AP>: 20090804
// We need to ensure that we're using surplus credits ONLY from either
@@ -424,20 +464,13 @@ class StatementEntry extends AppModel {
"Credits Established");
}
else {
if (empty($receipt_id))
INTERNAL_ERROR("Can't make adjustments to a charge without a receipt ID.");
}
// Next, establish credit from the newly added receipt
$receipt_credit = null;
if (!empty($receipt_id)) {
// Establish credit from the (newly added) receipt
$lquery =
array('link' =>
array('StatementEntry',
'LedgerEntry' =>
array('conditions' =>
array('LedgerEntry.account_id !=' =>
$this->Account->accountReceivableAccountID()),
array('LedgerEntry.account_id <> Transaction.account_id')
),
),
'conditions' => array('Transaction.id' => $receipt_id),
@@ -445,173 +478,190 @@ class StatementEntry extends AppModel {
);
$receipt_credit = $this->Transaction->find('first', $lquery);
if (!$receipt_credit)
INTERNAL_ERROR("Unable to locate receipt.");
//$reconciled = $this->reconciledEntries($id);
$this->INTERNAL_ERROR("Unable to locate receipt.");
$stats = $this->Transaction->stats($receipt_id);
$receipt_credit['balance'] =
$receipt_credit['Transaction']['amount'] - $stats['Disbursement']['total'];
$receipt_credit['balance'] = $stats['undisbursed'];
$this->pr(18, compact('receipt_credit'),
$receipt_credit['receipt'] = true;
$credits = array($receipt_credit);
$this->pr(18, compact('credits'),
"Receipt Credit Added");
}
// Now find all unpaid charges
if (isset($charge_ids)) {
$lquery = array('contain' => false,
'conditions' => array('StatementEntry.id' => $charge_ids));
} else {
// Now find all unpaid charges, using either the specific set
// of charges given, or all outstanding charges based on the
// query, customer and/or lease
if (!empty($charge_ids)) {
$this->INTERNAL_ERROR("PERHAPS IMPLEMENTED - THOUGH NEVER TESTED");
$lquery = $query;
// If we're working with a specific lease, then limit charges to it
if (!empty($lease_id))
$lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id);
$lquery['conditions'][] = array('StatementEntry.id' => $charge_ids);
$charges = $this->reconciledSet('CHARGE', $query, true);
} else {
$charges = $this->outstandingDebits($query, $customer_id, $lease_id);
}
$lquery['order'] = 'StatementEntry.effective_date ASC';
$charges = array();
foreach ($this->debitTypes() AS $dtype) {
$rset = $this->reconciledSet($dtype, $lquery, true);
$entries = $rset['entries'];
$charges = array_merge($charges, $entries);
$this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries");
}
// Initialize our list of used credits
$used_credits = array();
// REVISIT <AP>: 20090806
// Testing a theory. We should never have
// explicit credits, as well as a new receipt,
// and yet have outstanding charges.
if (!empty($credits) && !empty($receipt_credit) && !empty($charges))
INTERNAL_ERROR("Explicit credits that haven't already been applied.");
// Work through all unpaid charges, applying disbursements as we go
foreach ($charges AS $charge) {
$this->pr(20, compact('charge'),
'Process Charge');
// Check that we have available credits.
// Technically, this isn't necessary, since the loop
// will handle everything just fine. However, this
// just saves extra processing if/when there is no
// means to resolve a charge anyway.
if (empty($credits) && empty($receipt_credit['balance'])) {
$this->pr(17, 'No more available credits');
break;
}
$charge['balance'] = $charge['StatementEntry']['balance'];
while ($charge['balance'] > 0 &&
(!empty($credits) || !empty($receipt_credit['balance']))) {
// Use explicit credits before using the new receipt credit
foreach ($credits AS &$credit) {
if (empty($charge['balance']))
break;
if ($charge['balance'] < 0)
$this->INTERNAL_ERROR("Negative Charge Balance");
if (!isset($credit['balance']))
$credit['balance'] = $credit['StatementEntry']['amount'];
if (empty($credit['balance']))
continue;
if ($credit['balance'] < 0)
$this->INTERNAL_ERROR("Negative Credit Balance");
$this->pr(20, compact('charge'),
'Attempt Charge Reconciliation');
// Use explicit credits before using implicit credits
// (Not sure it matters though).
if (!empty($credits)) {
// Peel off the first credit available
$credit =& $credits[0];
$disbursement_date = $credit['StatementEntry']['effective_date'];
$disbursement_transaction_id = $credit['StatementEntry']['transaction_id'];
if (empty($credit['receipt']))
$disbursement_account_id = $credit['StatementEntry']['account_id'];
if (!isset($credit['balance']))
$credit['balance'] = $credit['StatementEntry']['amount'];
}
elseif (!empty($receipt_credit['balance'])) {
// Use our only receipt credit
$credit =& $receipt_credit;
$disbursement_date = $credit['Transaction']['stamp'];
$disbursement_transaction_id = $credit['Transaction']['id'];
else
$disbursement_account_id = $credit['LedgerEntry']['account_id'];
}
else {
die("HOW DID WE GET HERE WITH NO SURPLUS?");
}
// REVISIT <AP>: 20090811
// Need to come up with a better strategy for handling
// concessions. For now, just restricting concessions
// to apply only towards rent will resolve the most
// predominant (or only) needed usage case.
if ($disbursement_account_id == $this->Account->concessionAccountID() &&
$charge['StatementEntry']['account_id'] != $this->Account->rentAccountID())
continue;
// Set the disbursement amount to the maximum amount
// possible without exceeding the charge or credit balance
$disbursement_amount = min($charge['balance'], $credit['balance']);
$disbursement_amount = round(min($charge['balance'], $credit['balance']), 2);
if (!isset($credit['applied']))
$credit['applied'] = 0;
$credit['applied'] += $disbursement_amount;
$credit['balance'] -= $disbursement_amount;
$credit['applied'] = round($credit['applied'] + $disbursement_amount, 2);
$credit['balance'] = round($credit['balance'] - $disbursement_amount, 2);
$this->pr(20, compact('credit'),
$this->pr(20, compact('credit', 'disbursement_amount'),
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
(!empty($credits) ? ' Credit' : ' Receipt'));
(empty($credit['receipt']) ? ' Credit' : ' Receipt'));
if ($credit['balance'] < 0)
die("HOW DID WE END UP WITH NEGATIVE SURPLUS BALANCE?");
if (strtotime($charge['StatementEntry']['effective_date']) >
strtotime($credit['StatementEntry']['effective_date']))
$disbursement_edate = $charge['StatementEntry']['effective_date'];
else
$disbursement_edate = $credit['StatementEntry']['effective_date'];
// If we've exhausted the credit, get it out of the
// available credit pool (but keep track of it for later).
if ($credit['balance'] <= 0 && !empty($credits))
$used_credits[] = array_shift($credits);
if (empty($credit['receipt'])) {
// Explicit Credit
$result = $this->Transaction->addTransactionEntries
(array('include_ledger_entry' => true,
'include_statement_entry' => true),
array('type' => 'INVOICE',
'id' => $credit['StatementEntry']['transaction_id'],
'account_id' => $this->Account->accountReceivableAccountID(),
'crdr' => 'CREDIT',
'customer_id' => $charge['StatementEntry']['customer_id'],
'lease_id' => $charge['StatementEntry']['lease_id'],
),
array
(array('type' => $disbursement_type,
'effective_date' => $disbursement_edate,
'account_id' => $credit['StatementEntry']['account_id'],
'amount' => $disbursement_amount,
'charge_entry_id' => $charge['StatementEntry']['id'],
),
));
// Add a disbursement that uses the available credit to pay the charge
$disbursement = array('type' => $disbursement_type,
'account_id' => $disbursement_account_id,
'amount' => $disbursement_amount,
'effective_date' => $disbursement_date,
'transaction_id' => $disbursement_transaction_id,
'customer_id' => $charge['StatementEntry']['customer_id'],
'lease_id' => $charge['StatementEntry']['lease_id'],
'charge_entry_id' => $charge['StatementEntry']['id'],
'comment' => null,
);
$ret['Disbursement'][] = $result;
if ($result['error'])
$ret['error'] = true;
}
else {
// Receipt Credit
$this->pr(20, compact('disbursement'),
'New Disbursement Entry');
if (strtotime($charge['StatementEntry']['effective_date']) >
strtotime($credit['Transaction']['stamp']))
$disbursement_edate = $charge['StatementEntry']['effective_date'];
else
$disbursement_edate = $credit['Transaction']['stamp'];
$result = $this->addStatementEntry($disbursement);
$ret['Disbursement'][] = $result;
if ($result['error'])
$ret['error'] = true;
// Add a disbursement that uses the available credit to pay the charge
$disbursement =
array('type' => $disbursement_type,
'effective_date' => $disbursement_edate,
'amount' => $disbursement_amount,
'account_id' => $credit['LedgerEntry']['account_id'],
'transaction_id' => $credit['Transaction']['id'],
'customer_id' => $charge['StatementEntry']['customer_id'],
'lease_id' => $charge['StatementEntry']['lease_id'],
'charge_entry_id' => $charge['StatementEntry']['id'],
'comment' => null,
);
$this->pr(20, compact('disbursement'), 'New Disbursement Entry');
$result = $this->addStatementEntry($disbursement);
$ret['Disbursement'][] = $result;
if ($result['error'])
$ret['error'] = true;
}
// Adjust the charge balance to reflect the new disbursement
$charge['balance'] -= $disbursement_amount;
$charge['balance'] = round($charge['balance'] - $disbursement_amount, 2);
$this->pr(20, compact('charge', 'disbursement_amount'),
($charge['balance'] > 0 ? 'Unfinished' : 'Fully Paid') . ' Charge');
if ($charge['balance'] < 0)
die("HOW DID WE GET A NEGATIVE CHARGE AMOUNT?");
if ($charge['balance'] <= 0)
$this->pr(20, 'Fully Paid Charge');
}
// Break the $credit reference to avoid future problems
unset($credit);
}
// Partially used credits must be added to the used list
if (isset($credits[0]['applied']))
$used_credits[] = array_shift($credits);
$this->pr(18, compact('credits', 'used_credits', 'receipt_credit'),
'Disbursements added');
$this->pr(18, compact('credits'),
'Disbursements complete');
// Clean up any explicit credits that have been used
foreach ($used_credits AS $credit) {
foreach ($credits AS $credit) {
if (!empty($credit['receipt']))
continue;
if (empty($credit['applied']))
continue;
if ($credit['balance'] > 0) {
$this->pr(20, compact('credit'),
'Update Credit Entry');
$this->id = $credit['StatementEntry']['id'];
$this->id = $credit['StatementEntry']['id'];
$this->saveField('amount', $credit['balance']);
}
else {
$this->pr(20, compact('credit'),
'Delete Exhausted Credit Entry');
$this->del($credit['StatementEntry']['id'], false);
$this->delete($credit['StatementEntry']['id'], false);
}
}
// Convert non-exhausted receipt credit to an explicit one
if (!empty($receipt_credit['balance'])) {
$credit =& $receipt_credit;
// Check for any implicit receipt credits, converting
// into explicit credits if there is a remaining balance.
foreach ($credits AS $credit) {
if (empty($credit['receipt']))
continue;
if (empty($credit['balance']))
continue;
// See if there is an existing explicit credit
// for this transaction.
$explicit_credit = $this->find
('first', array('contain' => false,
'conditions' =>
@@ -619,30 +669,31 @@ class StatementEntry extends AppModel {
array('type' => 'SURPLUS')),
));
if (empty($explicit_credit)) {
$this->pr(18, compact('credit'),
'Create Explicit Credit');
if (!empty($explicit_credit)) {
// REVISIT <AP>: 20090815
// Testing whether or not this case occurs
$this->INTERNAL_ERROR('Existing explicit credit unexpected');
$result = $this->addStatementEntry
(array('type' => 'SURPLUS',
'account_id' => $credit['LedgerEntry']['account_id'],
'amount' => $credit['balance'],
'effective_date' => $credit['Transaction']['stamp'],
'transaction_id' => $credit['Transaction']['id'],
'customer_id' => $customer_id,
'lease_id' => $lease_id,
));
$ret['Credit'] = $result;
if ($result['error'])
$ret['error'] = true;
}
else {
// Since there IS an existing explicit credit, we must update
// its balance instead of creating a new one, since it has
// already been incorporated in the overall credit balance.
// If we were to create a new one, we would erroneously create
// an excess of credit available.
$this->pr(18, compact('explicit_credit', 'credit'),
'Update Explicit Credit');
'Update existing explicit credit');
$EC = new StatementEntry();
$EC->id = $explicit_credit['StatementEntry']['id'];
$EC->saveField('amount', $credit['balance']);
continue;
}
if (!empty($ret['receipt_balance']))
$this->INTERNAL_ERROR('Only one receipt expected in assignCredits');
// Give caller the information necessary to create an explicit
// credit from the passed receipt, which we've not exhausted.
$this->pr(18, compact('credit'), 'Convert to explicit credit');
$ret['receipt_balance'] = $credit['balance'];
}
return $this->prReturn($ret + array('error' => false));
@@ -656,7 +707,7 @@ class StatementEntry extends AppModel {
* - Returns summary data from the requested statement entry
*/
function stats($id = null, $query = null) {
//$this->prFunctionLevel(array('log' => 19, 'show' => 10));
//$this->prFunctionLevel(array('log' => 16, 'show' => 10));
$this->prEnter(compact('id', 'query'));
$this->queryInit($query);

View File

@@ -8,8 +8,12 @@ class Tender extends AppModel {
'DepositTransaction' => array(
'className' => 'Transaction',
),
'DepositLedgerEntry' => array(
'className' => 'LedgerEntry',
),
'NsfTransaction' => array(
'className' => 'Transaction',
'dependent' => true,
),
);
@@ -17,11 +21,11 @@ class Tender extends AppModel {
/**************************************************************************
**************************************************************************
**************************************************************************
* function: beforeSave
* - Performs any work needed before the save occurs
* function: afterSave
* - Performs any work needed after the save occurs
*/
function afterSave() {
function afterSave($created) {
// Come up with a (not necessarily unique) name for the tender.
// For checks & money orders, this will be based on the check
// number. For other types of tender, we'll just use the
@@ -45,10 +49,32 @@ class Tender extends AppModel {
if ($newname !== $this->field('name'))
$this->saveField('name', $newname);
return parent::afterSave();
return parent::afterSave($created);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: beforeDelete
* - Performs any work needed before the delete occurs
*/
function beforeDelete($cascade = true) {
// REVISIT <AP>: 20090814
// Experimental, and incomplete mechanism to protect
// against trying to delete data that shouldn't be deleted.
$deposit_id = $this->field('deposit_transaction_id');
pr(compact('deposit_id'));
// If this tender has already been deposited, it would
// be a rats nest to figure out how to delete this tender.
if (!empty($deposit_id))
return false;
return parent::beforeDelete($cascade);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -78,7 +104,7 @@ class Tender extends AppModel {
function addTender($tender) {
$this->prEnter(compact('tender'));
$ret = array();
$ret = array('data' => $tender);
if (!$this->verifyTender($tender))
return $this->prReturn(array('error' => true) + $ret);
@@ -108,6 +134,7 @@ class Tender extends AppModel {
('contain' =>
array('LedgerEntry',
'DepositTransaction',
'DepositLedgerEntry',
'NsfTransaction'),
));
$this->pr(20, compact('tender'));

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,11 @@ class Unit extends AppModel {
var $hasMany = array(
'Lease',
'LocksUnit'
);
var $hasAndBelongsToMany = array(
'Lock'
);
//var $default_log_level = array('log' => 30, 'show' => 15);
@@ -87,6 +92,23 @@ class Unit extends AppModel {
return $this->prReturn(true);
}
function locked($enum) {
return $this->statusCheck($enum, 'LOCKED', false, null, false);
}
function conditionLocked() {
//return array('Unit.status' => 'LOCKED');
return ('Unit.status >= ' . $this->statusValue('LOCKED'));
}
function liened($enum) {
return $this->statusCheck($enum, 'LIENED', false, null, false);
}
function conditionLiened() {
return ('Unit.status >= ' . $this->statusValue('LIENED'));
}
function occupied($enum) {
return $this->statusCheck($enum, 'OCCUPIED', false, null, false);
}
@@ -115,6 +137,7 @@ class Unit extends AppModel {
}
function available($enum) { return $this->vacant($enum); }
function conditionAvailable() { return $this->conditionVacant($enum); }
/**************************************************************************
@@ -181,6 +204,67 @@ class Unit extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: lockUnit
* - Put lock on unit
*/
function lockUnit($id, $lock_ids) {
$this->prEnter(compact('id', 'lock_ids'));
$this->id = $id;
// Remove any exising locks for this unit
$this->LocksUnit->deleteAll
(array('unit_id' => $id), false);
// We'll proceed forward as much as possible, even
// if we encounter an error. For now, we'll assume
// the operation will succeed.
$ret = true;
// Go through each lock, and put them on the unit
foreach ($lock_ids AS $lock_id) {
$pair['unit_id'] = $id;
$pair['lock_id'] = $lock_id;
// Save the relationship between lock and unit
$LU = new LocksUnit();
if (!$LU->save($pair, false))
$ret = false;
}
return $this->prReturn($ret);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: lockCount
* - Number of locks on a unit
*/
function lockCount($id) {
$this->prEnter(compact('id'));
return $this->prReturn($this->find
('count', array
('fields' => array("COUNT(Lock.id) AS count"),
'link' => array('Lock'),
'conditions' => array('Unit.id' => $id),
)));
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -1,25 +1,64 @@
<?php
class UnitSize extends AppModel {
var $name = 'UnitSize';
var $validate = array(
'id' => array('numeric'),
'unit_type_id' => array('numeric'),
'code' => array('notempty'),
'name' => array('notempty'),
'width' => array('numeric'),
'depth' => array('numeric'),
'deposit' => array('money'),
'amount' => array('money')
);
var $belongsTo =
array(
'UnitType',
);
var $belongsTo = array(
'UnitType',
);
var $hasMany =
array(
'Unit',
);
var $hasMany = array(
'Unit',
);
/**************************************************************************
**************************************************************************
**************************************************************************
* function: stats
* - Returns summary data from the requested unit size.
*/
function stats($id = null) {
$this->prEnter(compact('id'));
// Right now, we only work with id not null
if (!$id)
return null;
$stats = array();
// Get the total number of units this size
$stats['all'] =
$this->find('count',
array('link' => array('Unit'),
'conditions' => array(array('UnitSize.id' => $id)),
));
// Get numbers for units in the various states
foreach (array('unavailable', 'vacant', 'occupied', 'locked', 'liened') AS $status) {
$statusfunc = 'condition' . ucfirst($status);
$stats[$status] =
$this->find('count',
array('link' => array('Unit'),
'conditions' => array(array('UnitSize.id' => $id),
$this->Unit->{$statusfunc}()),
));
}
// Count up each unit by physical status
foreach
($this->find('all',
array('link' => array('Unit' => array('fields' => array())),
'fields' => array('Unit.status', 'COUNT(Unit.id) AS total'),
'conditions' => array(array('UnitSize.id' => $id)),
'group' => 'Unit.status',
)) AS $status) {
$stats['status'][$status['Unit']['status']] = $status[0]['total'];
}
// Return the collection
return $this->prReturn($stats);
}
}
?>

View File

@@ -1,16 +1,50 @@
<?php
class UnitType extends AppModel {
var $name = 'UnitType';
var $validate = array(
'id' => array('numeric'),
'code' => array('notempty'),
'name' => array('notempty')
);
var $hasMany =
array(
'UnitSize',
);
var $hasMany = array(
'UnitSize',
);
/**************************************************************************
**************************************************************************
**************************************************************************
* function: relatedTypes
* - Returns an array of types related by similar attributes
*/
function relatedTypes($attribute, $extra = null) {
$this->cacheQueries = true;
$types = $this->find('all', array
('fields' => array('UnitType.id', 'UnitType.name'),
'conditions' => array('UnitType.'.$attribute => true),
'order' => array('UnitType.name'),
) + (isset($extra) ? $extra : array())
);
$this->cacheQueries = false;
// Rearrange to be of the form (id => name)
$rel_types = array();
foreach ($types AS $type) {
$rel_types[$type['UnitType']['id']] = $type['UnitType']['name'];
}
return $rel_types;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: xxxTypes
* - Returns an array of types suitable for activity xxx
*/
function residentialTypes() { return $this->relatedTypes('residential'); }
function enclosedTypes() { return $this->relatedTypes('enclosed'); }
function climateTypes() { return $this->relatedTypes('climate'); }
function outdoorTypes() { return $this->relatedTypes('outdoor'); }
function coveredTypes() { return $this->relatedTypes('covered'); }
}
?>

39
site/models/user.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
class User extends AppModel {
var $hasMany =
array('UserOption',
'Membership',
);
static $current_user_id;
function currentUser() {
if (!empty($_SERVER['REMOTE_USER']))
return $_SERVER['REMOTE_USER'];
return null;
}
function currentUserId() {
if (!empty(self::$current_user_id))
return self::$current_user_id;
$user = $this->find
('first',
array('recursive' => -1,
'conditions' => array('login' => $this->currentUser())));
if (!empty($user['User']['id']))
self::$current_user_id = $user['User']['id'];
else
// We must force a stop here, since this is typically
// called very early on, and so will cause a recursive
// crash as we try to render the internal error and
// again stumble on this problem.
$this->INTERNAL_ERROR('UNKNOWN USER', 0, true);
return self::$current_user_id;
}
}

View File

@@ -0,0 +1,24 @@
<?php
class UserOption extends AppModel {
var $belongsTo =
array('User',
'OptionValue',
);
function values($id, $name = null) {
$this->prEnter(compact('id', 'name'));
$query = array();
$this->queryInit($query);
$query['link']['UserOption'] = array();
$query['link']['UserOption']['fields'] = array();
$query['link']['UserOption']['User'] = array();
$query['link']['UserOption']['User']['fields'] = array();
$query['conditions'][] = array('User.id' => $id);
return $this->prReturn($this->OptionValue->values($name, $query));
}
}

View File

@@ -0,0 +1,24 @@
<?php
class UserPermission extends AppModel {
var $belongsTo =
array('User',
'PermissionValue',
);
function values($id, $name = null) {
$this->prEnter(compact('id', 'name'));
$query = array();
$this->queryInit($query);
$query['link']['UserPermission'] = array();
$query['link']['UserPermission']['fields'] = array();
$query['link']['UserPermission']['User'] = array();
$query['link']['UserPermission']['User']['fields'] = array();
$query['conditions'][] = array('User.id' => $id);
return $this->prReturn($this->PermissionValue->values($name, $query));
}
}

View File

@@ -163,7 +163,7 @@ class ToolbarComponent extends Object {
trigger_error(sprintf(__('Could not load DebugToolbar panel %s', true), $panel), E_USER_WARNING);
continue;
}
$panelObj =& new $className();
$panelObj = new $className();
if (is_subclass_of($panelObj, 'DebugPanel') || is_subclass_of($panelObj, 'debugpanel')) {
$this->panels[$panel] =& $panelObj;
}
@@ -456,7 +456,7 @@ class LogPanel extends DebugPanel {
* @return array
*/
function _parseFile($filename) {
$file =& new File($filename);
$file = new File($filename);
$contents = $file->read();
$timePattern = '/(\d{4}-\d{2}\-\d{2}\s\d{1,2}\:\d{1,2}\:\d{1,2})/';
$chunks = preg_split($timePattern, $contents, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);

View File

@@ -30,14 +30,14 @@ $timers = DebugKitDebugger::getTimers();
?>
<h2><?php __('Timers'); ?></h2>
<p class="request-time">
<?php $totalTime = sprintf(__('%s (seconds)', true), $number->precision(DebugKitDebugger::requestTime(), 6)); ?>
<?php $totalTime = sprintf(__('%.6s (seconds)', true), DebugKitDebugger::requestTime()); ?>
<?php echo $toolbar->message(__('Total Request Time:', true), $totalTime)?>
</p>
<?php foreach ($timers as $timerName => $timeInfo):
$rows[] = array(
$timeInfo['message'],
$number->precision($timeInfo['time'], 6)
sprintf(__('%.6s', true), $timeInfo['time'])
);
$headers = array(__('Message', true), __('time in seconds', true));
endforeach;

View File

@@ -0,0 +1,9 @@
abijah:Property Manager:a2369e3cc9e231ea6f02ce799a8b9970
anja:Property Manager:4539d5a6e58dd5895f2f3891d29705b0
kevin:Property Manager:f01accc9f5e5cdfc028dcf0cca837cf1
adam:Property Manager:ae6835569bb2fc0a0a4a773580ac8cda
shirley:Property Manager:e7e9d674c700796c99cdbf3cf105e739
admin:Property Manager:bab2226685d9b4b66220db8df80f1822
dev:Property Manager:e5c27b3c025e47239a45daceea2c0a00
vasst:Property Manager:523abc6c2b8458b463d5a9baa4f58f2e
answerfirst:Property Manager:6ac128447fab8be985c74ba7539c39b3

View File

@@ -15,8 +15,8 @@ echo '<div class="account collected">' . "\n";
// Reset the form
function resetForm() {
<?php /* REVISIT <AP>: 20090810; Hate to do this, but first data is wrong... */ ?>
setTimeout(updateEntriesGrid, 1000);
// Kick off the grid
updateEntriesGrid();
}
function onGridLoadComplete() {
@@ -40,12 +40,15 @@ function updateEntriesGrid() {
$('#collected-total').html('Calculating...');
$('#collected-entries-jqGrid').clearGridData();
$('#collected-entries-jqGrid').setPostDataItem('dynamic_post', serialize(dynamic_post));
$('#collected-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#collected-entries-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
//$('#collected-entries .HeaderButton').click();
//$('#debug').html("<PRE>\n"+htmlEncode(dump($('#collected-entries-jqGrid').getGridParam()))+"\n</PRE>")
var gridstate = $('#collected-entries-jqGrid').getGridParam('gridstate');
if (gridstate == 'hidden')
$('#collected-entries .HeaderButton').click();
}
@@ -162,12 +165,12 @@ echo $this->element('statement_entries', array
'grid_div_id' => 'collected-entries',
'grid_div_class' => 'text-below',
'grid_events' => array('loadComplete' => 'onGridLoadComplete()'),
//'grid_setup' => array('hiddengrid' => true),
//'caption' => '<SPAN id="receipt-charges-caption"></SPAN>',
'grid_setup' => array('hiddengrid' => true),
'caption' => 'Collected ' . Inflector::pluralize($account['name']),
'filter' => array(//'StatementEntry.type' => 'DISBURSEMENT',
'ChargeEntry.account_id' => $account['id']),
'exclude' => array('Account', 'Charge', 'Type'),
'action' => 'collected',
'filter' => array('ChargeEntry.account_id' => $account['id']),
'include' => array('Amount'),
'exclude' => array(/*'Type',*/ 'Debit', 'Credit'),
),
));
@@ -175,20 +178,8 @@ echo $this->element('statement_entries', array
<script type="text/javascript"><!--
$(document).ready(function(){
$("#TxFromDate")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
$("#TxThroughDate")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
datepicker('TxFromDate');
datepicker('TxThroughDate');
resetForm();
});
--></script>
@@ -202,5 +193,3 @@ echo '</div>' . "\n";
echo '</div>' . "\n";
?>
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>

View File

@@ -16,7 +16,6 @@ if (isset($account['Account']))
$account = $account['Account'];
$rows = array();
$rows[] = array('ID', $account['id']);
$rows[] = array('Name', $account['name']);
$rows[] = array('Type', $account['type']);
$rows[] = array('External Name', $account['external_name']);
@@ -78,12 +77,12 @@ echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('grid_div_id' => 'ledger-ledger-entry-list',
'caption' => ("Current Ledger: " .
"(". $current_ledger['name'] .")"),
'filter' => array('Ledger.id' => $current_ledger['id']),
'caption' => "Current Ledger: #{$current_ledger['sequence']}",
'filter' => array('Ledger.id' => $current_ledger['id']),
'exclude' => array('Account', 'Amount', 'Cr/Dr', 'Balance',
empty($account['receipts']) ? 'Tender' : null),
'include' => array('Debit', 'Credit', 'Sub-Total'),
'limit' => 50,
)));
@@ -101,7 +100,8 @@ echo $this->element('ledger_entries', array
'filter' => array('Account.id' => $account['id']),
'exclude' => array('Account', 'Amount', 'Cr/Dr', 'Balance',
empty($account['receipts']) ? 'Tender' : null),
'include' => array('Debit', 'Credit', 'Sub-Total'),
'include' => array('Transaction', 'Debit', 'Credit', 'Sub-Total'),
'limit' => 50,
)));

View File

@@ -45,6 +45,7 @@ function contactMethodDiv($obj, $type, $legend, $values = null) {
' CLASS="'.$type.'-method-%{id}-source" ' . "\n" .
' ID="'.$type.'-method-%{id}-source-'.$stype.'"' . "\n" .
' VALUE="'.$stype.'"' . "\n" .
($stype == 'new' ? ' CHECKED' . "\n" : '') .
' />' . "\n" .
' <LABEL FOR="'.$type.'-method-%{id}-source-'.$stype.'">'.$sname.'</LABEL>' . "\n" .
' ';
@@ -67,7 +68,7 @@ function contactMethodDiv($obj, $type, $legend, $values = null) {
'</DIV>' . "\n" .
// BEGIN method-div
'<div id="'.$type.'-%{id}-method-div"' . "\n" .
'<div id="'.$type.'-%{id}-method-div"' . '>' . "\n" .
$obj->element
('form_table',
@@ -76,21 +77,30 @@ function contactMethodDiv($obj, $type, $legend, $values = null) {
'fields' => array
(
'preference' => array
('opts' => array
('label_attributes' => array('class' => 'required'),
'opts' => array
('options' => $obj->varstore['methodPreferences'],
'selected' => (isset($values) ? $values['ContactsMethod']['preference'] : null),
)),
),
'after' => "Intended purpose for this method of communication.",
),
'type' => array
('opts' => array
('label_attributes' => array('class' => 'required'),
'opts' => array
('options' => $obj->varstore['methodTypes'],
'selected' => (isset($values) ? $values['ContactsMethod']['type'] : null),
)),
),
'after' => "How / Where this communication reaches the contact.",
),
'comment' => array
('opts' => array
('label_attributes' => array('class' => 'optional empty'),
'opts' => array
('value' => (isset($values) ? $values['ContactsMethod']['comment'] : null),
)),
),
'after' => "Optional: Comments on how this form of communication relates to the contact.",
),
))) . "\n" .
@@ -113,16 +123,27 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
if ($type === 'phone') {
if ($stype === 'existing') {
$fields = array
('id' => array('name' => 'Phone/Ext',
('id' => array('label_attributes' => array('class' => 'required empty'),
'name' => 'Phone/Ext',
'opts' => array('options' => $obj->varstore['contactPhones'])),
);
}
elseif ($stype === 'new') {
$fields = array
('type' => array('opts' => array('options' => $obj->varstore['phoneTypes'])),
'phone' => true,
'ext' => array('name' => "Extension"),
'comment' => true,
('type' => array('label_attributes' => array('class' => 'required'),
'opts' => array('autocomplete' => 'off',
'options' => $obj->varstore['phoneTypes']),
'after' => "Physical type of the phone."),
'phone' => array('label_attributes' => array('class' => 'required empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Required: Phone number."),
'ext' => array('name' => "Extension",
'label_attributes' => array('class' => 'optional empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Optional: Extension number."),
'comment' => array('label_attributes' => array('class' => 'optional empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Optional: Comments about this phone number."),
);
}
elseif ($stype === 'show') {
@@ -149,12 +170,25 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
}
elseif ($stype === 'new') {
$fields = array
('address' => true,
'city' => true,
'state' => true,
'postcode' => array('name' => 'Zip Code'),
'country' => true,
'comment' => true,
('address' => array('label_attributes' => array('class' => 'required empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Required: First line of mailing address."),
'city' => array('label_attributes' => array('class' => 'required empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Required."),
'state' => array('label_attributes' => array('class' => 'required empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Required."),
'postcode' => array('name' => 'Zip Code',
'label_attributes' => array('class' => 'required empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Required."),
'country' => array('label_attributes' => array('class' => 'optional empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Optional: USA is presumed."),
'comment' => array('label_attributes' => array('class' => 'optional empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Optional: Comments about this mailing address."),
);
}
elseif ($stype === 'show') {
@@ -177,13 +211,18 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
if ($stype === 'existing') {
$fields = array
('id' => array('name' => 'Email',
'label_attributes' => array('class' => 'required'),
'opts' => array('options' => $obj->varstore['contactEmails'])),
);
}
elseif ($stype === 'new') {
$fields = array
('email' => true,
'comment' => true,
('email' => array('label_attributes' => array('class' => 'required empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Required: E-mail address."),
'comment' => array('label_attributes' => array('class' => 'optional empty'),
'opts' => array('autocomplete' => 'off'),
'after' => "Optional: Comments about this email address."),
);
}
elseif ($stype === 'show') {
@@ -204,7 +243,7 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
'<div ' . "\n" .
' class="'.$type.'-%{id}-div"' . "\n" .
' id="'.$type.'-%{id}-'.$stype.'-div"' . "\n" .
(isset($values) ? '' : ' STYLE="display:none;"' . "\n") .
((isset($values) || $stype == 'new') ? '' : ' STYLE="display:none;"' . "\n") .
'>' . "\n" .
$obj->element
@@ -319,8 +358,27 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
.slideDown();
}
function setEmpty(input_elem) {
selector = "label[for=" + $(input_elem).attr("id") + "]";
if ($(input_elem).val() == '')
$(selector).addClass('empty');
else
$(selector).removeClass('empty');
}
$(document).ready(function(){
resetForm();
// In case refresh is hit with populated fields
$(":input").each(function(i,elem){ setEmpty(elem); });
// keyup doesn't catch cut from menu
$(":input").live('keyup', function(){
setEmpty(this);
});
$(":input").live('mouseup', function(){
setEmpty(this);
});
});
--></script>
@@ -345,17 +403,30 @@ echo($this->element
array('class' => 'item contact detail',
'caption' => isset($this->data['Contact']) ? 'Edit Contact' : 'New Contact',
'fields' => array
('first_name' => true,
'last_name' => true,
'middle_name' => true,
'display_name' => true,
'company_name' => array('name' => 'Company'),
'id_federal' => array('name' => 'SSN'),
'id_local' => array('name' => 'ID #'),
'id_local_state' => array('name' => 'ID State'),
('last_name' => array('label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended."),
'first_name' => array('label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended."),
'middle_name' => array('label_attributes' => array('class' => 'optional empty'),
'after' => "Optional."),
'company_name' => array('name' => 'Company',
'label_attributes' => array('class' => 'optional empty'),
'after' => "Optional: Company name, if corporate contact."),
'display_name' => array('label_attributes' => array('class' => 'optional empty'),
'after' => "Optional with first/last name; Required otherwise."),
'id_federal' => array('name' => 'SSN',
'label_attributes' => array('class' => 'optional empty'),
'after' => "Optional: Social Security Number."),
'id_local' => array('name' => 'ID #',
'label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended: Driver's license, for example."),
'id_local_state' => array('name' => 'ID State',
'label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended: State which issued the ID."),
/* 'id_local_exp' => array('name' => 'ID Expiration', */
/* 'opts' => array('empty' => true)), */
'comment' => true,
'comment' => array('label_attributes' => array('class' => 'optional empty'),
'after' => "Optional: Comments about this contact."),
))) . "\n");
echo $form->submit('Update') . "\n";

View File

@@ -17,16 +17,17 @@ if (isset($contact['Contact']))
$contact = $contact['Contact'];
$rows = array();
$rows[] = array('First Name', $contact['first_name']);
$rows[] = array('Middle Name', $contact['middle_name']);
$rows[] = array('Last Name', $contact['last_name']);
$rows[] = array('Company', $contact['company_name']);
$rows[] = array('SSN', $contact['id_federal']);
$rows[] = array('ID', ($contact['id_local']
. ($contact['id_local']
? " - ".$contact['id_local_state']
: "")));
$rows[] = array('Comment', $contact['comment']);
$rows[] = array('Display Name', $contact['display_name']);
$rows[] = array('First Name', $contact['first_name']);
$rows[] = array('Middle Name', $contact['middle_name']);
$rows[] = array('Last Name', $contact['last_name']);
$rows[] = array('Company', $contact['company_name']);
$rows[] = array('SSN', $contact['id_federal']);
$rows[] = array('ID', ($contact['id_local']
. ($contact['id_local']
? " - ".$contact['id_local_state']
: "")));
$rows[] = array('Comment', $contact['comment']);
echo $this->element('table',
array('class' => 'item contact detail',
@@ -135,6 +136,7 @@ echo $this->element('customers', array
'config' => array
('caption' => 'Related Customers',
'filter' => array('Contact.id' => $contact['id']),
'include' => array('Relationship'),
)));

View File

@@ -42,11 +42,12 @@ function customerContactDiv($obj, $values = null, $primary = false) {
' CLASS="contact-%{id}-source" ' . "\n" .
' ID="contact-%{id}-source-'.$stype.'"' . "\n" .
' VALUE="'.$stype.'"' . "\n" .
//' CHECKED' . "\n" .
($stype == 'new' ? ' CHECKED' . "\n" : '') .
' />' . "\n" .
' <LABEL FOR="contact-%{id}-source-'.$stype.'">'.$sname.'</LABEL>' . "\n" .
' ';
}
$div .= "<P>(Phone numbers / Addresses can be added later)";
}
$div .= "\n";
@@ -65,7 +66,7 @@ function customerContactDiv($obj, $values = null, $primary = false) {
'</DIV>' . "\n" .
// BEGIN contact-div
'<div id="contact-%{id}-contact-div"' . "\n" .
'<div id="contact-%{id}-contact-div">' . "\n" .
$obj->element
('form_table',
@@ -75,23 +76,35 @@ function customerContactDiv($obj, $values = null, $primary = false) {
(
'Customer.primary_contact_entry' => array
('name' => 'Primary Contact',
'label_attributes' => array('class' => null),
'no_prefix' => true,
'opts' => array
('type' => 'radio',
'options' => array('%{id}' => false),
'value' => ($primary ? '%{id}' : 'bogus-value-to-suppress-hidden-input'),
)),
),
'after' => ("Check this button if this contact will be the primary" .
" contact for this customer (there can be only one primary" .
" contact"),
),
'type' => array
('opts' => array
('label_attributes' => array('class' => 'required'),
'opts' => array
('options' => $obj->varstore['contactTypes'],
'selected' => (isset($values) ? $values['ContactsCustomer']['type'] : null),
)),
),
'after' => "An actual tenant, or just an alternate contact?"
),
'comment' => array
('opts' => array
('label_attributes' => array('class' => 'optional empty'),
'opts' => array
('value' => (isset($values) ? $values['ContactsCustomer']['comment'] : null),
)),
),
'after' => "Optional: Comments on the relationship between this customer and this contact."
),
))) . "\n" .
@@ -115,22 +128,37 @@ function customerContactTypeDiv($obj, $stype, $values = null) {
if ($stype === 'existing') {
$fields = array
('id' => array('name' => 'Contact',
'opts' => array('options' => $obj->varstore['contacts'])),
'label_attributes' => array('class' => 'required empty'),
'opts' => array('options' => $obj->varstore['contacts']),
'after' => "Select the existing contact."),
);
}
elseif ($stype === 'new') {
$fields = array
('first_name' => true,
'last_name' => true,
'middle_name' => true,
'display_name' => true,
'company_name' => array('name' => 'Company'),
'id_federal' => array('name' => 'SSN'),
'id_local' => array('name' => 'ID #'),
'id_local_state' => array('name' => 'ID State'),
('last_name' => array('label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended."),
'first_name' => array('label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended."),
'middle_name' => array('label_attributes' => array('class' => 'optional empty'),
'after' => "Optional."),
'company_name' => array('name' => 'Company',
'label_attributes' => array('class' => 'optional empty'),
'after' => "Optional: Company name, if corporate contact."),
'display_name' => array('label_attributes' => array('class' => 'optional empty'),
'after' => "Optional with first/last name; Required otherwise."),
'id_federal' => array('name' => 'SSN',
'label_attributes' => array('class' => 'optional empty'),
'after' => "Optional: Social Security Number."),
'id_local' => array('name' => 'ID #',
'label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended: Driver's license, for example."),
'id_local_state' => array('name' => 'ID State',
'label_attributes' => array('class' => 'recommended empty'),
'after' => "Recommended: State which issued the ID."),
/* 'id_local_exp' => array('name' => 'ID Expiration', */
/* 'opts' => array('empty' => true)), */
'comment' => true,
'comment' => array('label_attributes' => array('class' => 'optional empty'),
'after' => "Optional: Comments about this contact."),
);
}
elseif ($stype === 'show') {
@@ -151,14 +179,14 @@ function customerContactTypeDiv($obj, $stype, $values = null) {
'<div ' . "\n" .
' class="contact-%{id}-div"' . "\n" .
' id="contact-%{id}-'.$stype.'-div"' . "\n" .
(isset($values) ? '' : ' STYLE="display:none;"' . "\n") .
((isset($values) || $stype == 'new') ? '' : ' STYLE="display:none;"' . "\n") .
'>' . "\n" .
$obj->element
($element,
array('class' => "item contact {$class}",
'field_prefix' => 'Contact.%{id}')
+ compact('rows', 'fields', 'column_class')) .
+ compact('rows', 'fields', 'row_class', 'column_class')) .
($stype === 'show'
? '<input type="hidden" name="data[Contact][%{id}][id]" value="'.$values['id'].'"/>' . "\n"
@@ -221,8 +249,28 @@ function customerContactTypeDiv($obj, $stype, $values = null) {
.slideDown();
}
function setEmpty(input_elem) {
selector = "label[for=" + $(input_elem).attr("id") + "]";
//$("#debug").append($(input_elem).attr("id") + ": " + $(input_elem).val() + "<BR>");
if ($(input_elem).val() == '')
$(selector).addClass('empty');
else
$(selector).removeClass('empty');
}
$(document).ready(function(){
resetForm();
// In case refresh is hit with populated fields
$(":input").each(function(i,elem){ setEmpty(elem); });
// keyup doesn't catch cut from menu
$(":input").live('keyup', function(){
setEmpty(this);
});
$(":input").live('mouseup', function(){
setEmpty(this);
});
});
--></script>
@@ -247,8 +295,12 @@ echo($this->element
array('class' => 'item customer detail',
'caption' => isset($this->data['Customer']) ? 'Edit Customer' : 'New Customer',
'fields' => array
('name' => true,
'comment' => true,
('name' => array('label_attributes' => array('class' => 'optional empty'),
'after' => ("Optional: If this field is left blank, the" .
" customer name will be set to the name of" .
" the primary contact, below.")),
'comment' => array('label_attributes' => array('class' => 'optional empty'),
'after' => 'Optional: Comments about this customer.'),
))) . "\n");
echo $form->submit(isset($this->data['Customer']) ? 'Update' : 'Add New Customer') . "\n";
@@ -268,6 +320,11 @@ echo $form->submit(isset($this->data['Customer']) ? 'Update' : 'Add New Customer
<?php
; // Alignment
if (!empty($movein['Unit']['id']))
echo $form->input("movein.Unit.id",
array('type' => 'hidden',
'value' => $movein['Unit']['id'])) . "\n";
echo $form->submit(isset($this->data['Customer']) ? 'Update' : 'Add New Customer') . "\n";
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
echo $form->end() . "\n";

View File

@@ -0,0 +1,176 @@
<?php /* -*- mode:PHP -*- */ ?>
<div class="customer merge">
<?php
; // Editor alignment
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Javascript
*/
// Warnings _really_ screw up javascript
$saved_debug_state = Configure::read('debug');
Configure::write('debug', '0');
?>
<script type="text/javascript"><!--
// pre-submit callback
function verifyRequest() {
if (!$("#src-customer-id").val()) {
alert("Must select source customer");
return false;
}
rows = $('#<?php echo "contacts-jqGrid"; ?>').getGridParam('selarrrow');
$('#<?php echo "contact-ids"; ?>').val(serialize(rows));
// return false to prevent the form from being submitted;
// anything other than false will allow submission.
return true;
}
function updateContacts() {
$('#contacts-jqGrid').clearGridData();
var filter = new Array();
filter['ContactsCustomer.customer_id'] = $("#src-customer-id").val();
var dynamic_post = new Array();
dynamic_post['filter'] = filter;
$('#contacts-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#contacts-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
}
function onRowSelect(grid_id, customer_id) {
//$('#output-debug').append("select: "+grid_id+"; "+customer_id+"<BR>\n");
// Set the item id that will be returned with the form
$("#src-customer-id").val(customer_id);
// Get the item name from the grid
$("#src-customer-name").html($(grid_id).getCell(customer_id, "Customer-name"));
updateContacts();
$("#customers-list .HeaderButton").click();
}
function onGridState(grid_id, state) {
//$('#output-debug').append("state: "+grid_id+"; "+state+"<BR>\n");
if (state == 'visible') {
$(".customer-selection-invalid").hide();
$(".customer-selection-valid").hide();
}
else {
if ($("#src-customer-id").val() > 0) {
$(".customer-selection-invalid").hide();
$(".customer-selection-valid").show();
} else {
$(".customer-selection-invalid").show();
$(".customer-selection-valid").hide();
}
}
}
--></script>
<?php
; // align
// Re-Enable warnings
Configure::write('debug', $saved_debug_state);
echo $form->create(null, array('id' => 'customer-merge-form',
'onsubmit' => 'return verifyRequest();',
'url' => array('controller' => 'customers',
'action' => 'mergeFinal')))."\n";
echo '<input type="hidden" id="src-customer-id" name="src-id" value="0" />'."\n";
echo '<input type="hidden" id="dst-customer-id" name="dst-id" value="'.$dst_id.'" />'."\n";
echo $this->element('customers', array
('config' => array
('grid_div_id' => 'customers-list',
'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#customers-list .HeaderButton\').click();'.
' return false;">Select Customer</A>'),
'grid_events' => array('onSelectRow' =>
array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
'onHeaderClick' =>
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'filter' => array('Customer.id !=' => $dst_id),
//'nolinks' => true,
'limit' => 10,
)));
echo ('<DIV CLASS="customer-merge grid-selection-text">' .
'<DIV CLASS="customer-selection-valid" style="display:none">' .
'Destination Customer: <SPAN id="src-customer-name"></SPAN>' .
'</DIV>' .
'<DIV CLASS="customer-selection-invalid" style="display:none">' .
'Please select customer to merge into' .
'</DIV>' .
'</DIV>' . "\n");
echo $this->element('contacts', array
(// Grid configuration
'config' => array
(
'grid_div_id' => 'contacts',
'grid_setup' => array('multiselect' => true),
'caption' => 'Source contacts to keep',
'filter' => array('ContactsCustomer.customer_id' => 0),
'include' => array('Relationship', 'License', 'Comment'),
),
));
// Add a hidden item to hold the jqGrid selection,
// which we'll populate prior to form submission.
echo "\n";
echo '<input type="hidden" id="contact-ids" name="contact-ids" value="" />'."\n";
?>
<H3>WARNING!</H3>
The above selected customer is about to be deleted, and all related data (leases, transactions, etc) will be merged into customer #<?php echo $dst_id ?>: <?php echo $dst_name ?>. This process is NOT reversible, so please ensure the selections are correct before proceeding.<BR>
<?php
echo $form->end('Merge Customers') . "\n";
?>
<div id="output-debug" style="display:none"></div>
<?php
// Warnings _really_ screw up javascript
Configure::write('debug', '0');
?>
<script type="text/javascript"><!--
$(document).ready(function(){
$("#src-customer-id").val(0);
$("#src-customer-name").html("INTERNAL ERROR");
//onGridState(null, 'visible');
<?php if ($this->params['dev']): ?>
$('#output-debug').show();
<?php endif; ?>
});
--></script>
</div>

View File

@@ -28,17 +28,61 @@ Configure::write('debug', '0');
// other available options:
//clearForm: true, // clear all form fields after successful submit
//resetForm: true, // reset the form after successful submit
url: "<?php echo $html->url(array('controller' => 'transactions',
'action' => 'postReceipt', 0)); ?>"
};
// bind form using 'ajaxForm'
$('#receipt-form').ajaxForm(options);
if ($('#receipt-form').ajaxForm != null)
$('#receipt-form').ajaxForm(options);
else
$('#repeat, label[for=repeat]').remove();
});
// pre-submit callback
function verifyRequest(formData, jqForm, options) {
function verifyRequest(formData, jqForm, options) {
//$("#debug").html('');
for (var i = 0; i < formData.length; ++i) {
//$("#debug").append(i + ') ' + dump(formData[i]) + '<BR>');
if (formData[i]['name'] == "data[Customer][id]" &&
!(formData[i]['value'] > 0)) {
//$("#debug").append('<P>Missing Customer ID');
alert("Please select a customer first.");
return false;
}
if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') {
//$("#debug").append('<P>Bad 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;
}
// Terrible way to accomplish this...
for (var j = 0; j < 20; ++j) {
if (formData[i]['name'] == "data[Entry]["+j+"][amount]") {
var val = formData[i]['value'].replace(/\$/,'');
//$("#debug").append('<P>Bad Amount');
if (!(val > 0)) {
if (formData[i]['value'] == '')
alert("Please enter an amount first.");
else
alert('"'+formData[i]['value']+'"' + " is not valid amount. Please correct it.");
return false;
}
}
}
}
//$("#debug").append('OK');
//return false;
$('#results').html('Working <BLINK>...</BLINK>');
// here we could return false to prevent the form from being submitted;
// returning anything other than false will allow the form submit to continue
return true;
}
@@ -81,22 +125,42 @@ function resetForm() {
updateCharges($("#customer-id").val());
}
function updateCharges(id) {
$('#charge-entries-jqGrid').clearGridData();
$("#receipt-balance").html("Calculating...");
$("#receipt-charges-caption").html("Please Wait...");
var filter = new Array();
filter['StatementEntry.customer_id'] = id;
var dynamic_post = new Array();
dynamic_post['filter'] = filter;
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#charge-entries-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
var gridstate = $('#charge-entries-jqGrid').getGridParam('gridstate');
if (gridstate == 'hidden')
$('#charge-entries .HeaderButton').click();
}
function onGridLoadComplete() {
var userdata = $('#charge-entries-jqGrid').getGridParam('userData');
$('#receipt-balance').html(fmtCurrency(userdata['balance']));
$("#receipt-charges-caption").html("Outstanding Charges");
}
function onRowSelect(grid_id, customer_id) {
// Set the customer id that will be returned with the form
$("#customer-id").val(customer_id);
// Get the item names from the grid
//$("#receipt-customer-id").html($(grid_id).getCell(customer_id, 'Customer-id'));
// REVISIT <AP>: 20090708
// This is not intended as a long term solution,
// but I need a way to enter data and then view
// the results. This link will help.
$("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
$(grid_id).getCell(customer_id, 'Customer-id').replace(/^#/,'') +
'">' +
$(grid_id).getCell(customer_id, 'Customer-id') +
'</A>');
$("#receipt-customer-name").html($(grid_id).getCell(customer_id, 'Customer-name'));
// Set the customer name, so the user knows who the receipt is for
$("#receipt-customer-name")
.html('<A HREF="view/' + customer_id + '">'
+ $(grid_id).getCell(customer_id, 'Customer-name')
+ '</A>');
// Hide the "no customer" message and show the current customer
$(".customer-selection-invalid").hide();
@@ -214,48 +278,6 @@ function switchPaymentType(paymentid_base, paymentid, radioid) {
$("#"+paymentid_base+"-"+paymentid+"-"+type_id).slideDown();
}
function updateChargesGrid(idlist) {
var dynamic_post = new Array();
dynamic_post['idlist'] = idlist;
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#charge-entries-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
}
function updateCharges(id) {
var url = '<?php echo ($html->url(array("controller" => $this->params["controller"],
"action" => "unreconciled"))); ?>';
url += '/'+id;
$('#charge-entries-jqGrid').clearGridData();
$("#receipt-balance").html("Calculating...");
$("#receipt-charges-caption").html("Please Wait...");
$.ajax({
type: "GET",
url: url,
dataType: "xml",
success: function(xml) {
var ids = new Array();
$('entry',xml).each(function(i){
ids.push($(this).attr('id'));
});
$('#receipt-balance').html(fmtCurrency($('entries',xml).attr('balance')));
$("#receipt-charges-caption").html("Outstanding Charges");
updateChargesGrid(ids);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
/* alert('ERROR'); */
/* $('#debug').html('<P>request<BR>'+escape(XMLHttpRequest)); */
/* $('#debug').append('<P>status<BR>'+escape(textStatus)); */
/* $('#debug').append('<P>error<BR>'+escape(errorThrown)); */
}
});
}
--></script>
<?php
@@ -277,15 +299,15 @@ echo $this->element('customers', array
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'action' => 'current',
'nolinks' => true,
'limit' => 10,
'limit' => 20,
)));
echo ('<DIV CLASS="receipt grid-selection-text">' .
'<DIV CLASS="customer-selection-valid" style="display:none">' .
'Customer <SPAN id="receipt-customer-id"></SPAN>' .
': <SPAN id="receipt-customer-name"></SPAN>' .
'Customer: <SPAN id="receipt-customer-name"></SPAN>' .
/* '<DIV CLASS="supporting">' . */
/* '<TABLE>' . */
@@ -303,17 +325,19 @@ echo ('<DIV CLASS="receipt grid-selection-text">' .
echo $this->element('statement_entries', array
(// Element configuration
'account_ftype' => 'credit',
'limit' => 8,
// Grid configuration
(// Grid configuration
'config' => array
(
'grid_div_id' => 'charge-entries',
'grid_div_class' => 'text-below',
'grid_events' => array('loadComplete' => 'onGridLoadComplete()'),
'grid_setup' => array('hiddengrid' => true),
'caption' => '<SPAN id="receipt-charges-caption"></SPAN>',
'rows' => $charges,
'action' => 'unreconciled',
'exclude' => array('Customer', 'Type', 'Debit', 'Credit'),
'include' => array('Applied', 'Balance'),
'remap' => array('Received' => 'Paid'),
'limit' => 8,
),
));
@@ -386,30 +410,15 @@ Configure::write('debug', '0');
<script type="text/javascript"><!--
$(document).ready(function(){
$("#TransactionStamp")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
datepicker('TransactionStamp');
datepickerNow('TransactionStamp');
$("#receipt-customer-id").html("INTERNAL ERROR");
$("#customer-id").val(0);
$("#receipt-customer-name").html("INTERNAL ERROR");
$("#receipt-balance").html("INTERNAL ERROR");
$("#receipt-charges-caption").html("Outstanding Charges");
resetForm();
<?php if (isset($customer['id'])): ?>
$("#customer-id").val(<?php echo $customer['id']; ?>);
//$("#receipt-customer-id").html("<?php echo '#'.$customer['id']; ?>");
$("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
"<?php echo $customer['id']; ?>" +
'">#' +
"<?php echo $customer['id']; ?>" +
'</A>');
$("#receipt-customer-name").html("<?php echo $customer['name']; ?>");
$("#receipt-balance").html(fmtCurrency("<?php echo $stats['balance']; ?>"));
onGridState(null, 'hidden');
@@ -417,6 +426,14 @@ Configure::write('debug', '0');
onGridState(null, 'visible');
<?php endif; ?>
resetForm();
datepickerNow('TransactionStamp');
<?php if ($this->params['dev']): ?>
$('#output-debug').html('Post Output');
$('#output-debug').show();
<?php endif; ?>
});
--></script>

View File

@@ -53,44 +53,35 @@ echo '<div CLASS="detail supporting">' . "\n";
/**********************************************************************
* Contacts
*/
echo $this->element('contacts', array
(// Grid configuration
'config' => array
('caption' => 'Customer Contacts',
'filter' => array('Customer.id' => $customer['Customer']['id']),
'include' => array('Type', 'Active'),
)));
/**********************************************************************
* Lease History
*/
echo $this->element('leases', array
(// Grid configuration
'config' => array
('caption' => 'Lease History',
'filter' => array('Customer.id' => $customer['Customer']['id']),
'exclude' => array('Customer'),
)));
/**********************************************************************
* Customer Account History
* Unpaid Charges
*/
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Customer Statement',
'filter' => array('Customer.id' => $customer['Customer']['id'],
'type !=' => 'VOID'),
('caption' => 'Outstanding Charges',
'limit' => 10,
'action' => 'unreconciled',
'filter' => array('StatementEntry.customer_id' => $customer['Customer']['id']),
'exclude' => array('Customer'),
'sort_column' => 'Effective',
'sort_order' => 'DESC',
)));
/**********************************************************************
* Customer Credits
*/
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Oustanding Credits',
'grid_div_id' => 'surplus',
'limit' => 10,
'filter' => array('Customer.id' => $customer['Customer']['id'],
'StatementEntry.type' => 'SURPLUS'),
'exclude' => array('Entry', 'Effective', 'Customer', 'Unit', 'Account', 'Debit', 'Credit'),
'include' => array('Transaction', 'Amount'),
'remap' => array('Transaction' => 'Receipt'),
)));
@@ -102,17 +93,107 @@ echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('caption' => 'Receipts',
'limit' => 5,
'filter' => array('Customer.id' => $customer['Customer']['id'],
'Transaction.type' => 'RECEIPT',
'Tender.id !=' => null,
//'Account.id !=' => '-AR-'
),
'exclude' => array('Account', 'Cr/Dr'),
'sort_column' => 'Date',
'include' => array('Transaction'),
'exclude' => array('Entry', 'Account', 'Cr/Dr'),
'remap' => array('Transaction' => 'Receipt'),
)));
/**********************************************************************
* Invoice History
*/
/* NOT COMPLETED
echo $this->element('transactions', array
(// Grid configuration
'config' => array
('caption' => 'Invoices',
'limit' => 5,
'filter' => array('Customer.id' => $customer['Customer']['id'],
'Transaction.type' => 'INVOICE',
),
//'include' => array(),
'exclude' => array('Type'),
'remap' => array('ID' => 'Invoice',
//'Timestamp' => 'Date',
'Entries' => 'Charges'),
)));
NOT COMPLETED */
/**********************************************************************
* Lease History
*/
echo $this->element('leases', array
(// Grid configuration
'config' => array
('caption' => 'Lease History',
'limit' => 5,
'filter' => array('Customer.id' => $customer['Customer']['id']),
'exclude' => array('Customer'),
'sort_column' => 'Move-In',
'sort_order' => 'DESC',
)));
/**********************************************************************
* Contacts
*/
echo $this->element('contacts', array
(// Grid configuration
'config' => array
('caption' => 'Customer Contacts',
'limit' => 5,
'filter' => array('Customer.id' => $customer['Customer']['id']),
'include' => array('Relationship'),
)));
/**********************************************************************
* Customer Statement History
*/
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Customer Statement',
'grid_setup' => array('hiddengrid' => true),
'filter' => array('Customer.id' => $customer['Customer']['id'],
'type !=' => 'VOID'),
//'include' => array('Sub-Total'),
'exclude' => array('Customer'),
)));
/**********************************************************************
* Customer Transaction History
*/
echo $this->element('transactions', array
(// Grid configuration
'config' => array
('caption' => 'Balance History',
'limit' => 10000,
'limitOptions' => array('10000'),
'sort_column' => 'Timestamp',
'sort_order' => 'ASC',
'grid_setup' => array('hiddengrid' => true),
'filter' => array('Customer.id' => $customer['Customer']['id']),
'include' => array('Comment', 'PosNeg', 'Balance'),
'exclude' => array('Amount', 'Entries'),
'remap' => array(//'ID' => 'Invoice',
'PosNeg' => 'Amount',
//'Entries' => 'Charges',
),
)));
/* End "detail supporting" div */
echo '</div>' . "\n";

View File

@@ -1,50 +1,17 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="ledger-entry view">' . "\n";
echo '<div class="double-entry view">' . "\n";
// The two entry ids, debit and credit, are actually individual
// The two entries, debit and credit, are actually individual
// entries in separate accounts (each make up one of the two
// entries required for "double entry"). This, when we provide
// reconcile information, we're really providing reconcile info
// for two independent accounts. The reconciling entries,
// therefore, are those on the opposite side of the ledger in
// each account. For example, assume this "double" entry is
//
// debit: A/R credit: Cash amount: 55
//
// Then, our accounts might look like:
//
// RENT TAX A/R CASH BANK
// ------- ------- ------- ------- -------
// |20 | 20| | | <-- Unrelated
// | | |20 20| | <-- Unrelated
// | | | | |
// |50 | 50| | | <-- Rent paid by this entry
// | |5 5| | | <-- Tax paid by this entry
// | | |55 55| | <-- THIS ENTRY
// | | | | |
// | | | |75 75| <-- Deposit includes this entry
// | | | | |
//
// In this case, we're looking to provide reconcile information
// of A/R for (the credit side of) this entry, and also of Cash
// (for the debit side). Taking the accounts as individual
// entries, instead of the "double entry" representation in the
// database, we're actually providing information on the two
// A/R entries, 50 & 5, which are both debits, i.e. opposite
// entries to the credit of A/R. The cash account entry
// reconciles against the credit of 75. Again, this is the
// opposite entry to the debit of Cash.
//
// Thus, for our debit_ledger_id, we're reconciling against
// credits, and for our credit_ledger_id, against debits.
// entries required for "double entry").
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* LedgerEntry Detail Main Section
* DoubleEntry Detail Main Section
*/
$transaction = $entry['Transaction'];
@@ -52,92 +19,61 @@ $ledgers = array('debit' => $entry['DebitLedger'],
'credit' => $entry['CreditLedger']);
$entries = array('debit' => $entry['DebitEntry'],
'credit' => $entry['CreditEntry']);
$customer = $entry['Customer'];
$lease = $entry['Lease'];
$entry = $entry['DoubleEntry'];
$rows = array();
$rows[] = array('ID', $entry['id']);
$rows[] = array('Transaction', $html->link('#'.$transaction['id'],
array('controller' => 'transactions',
'action' => 'view',
$transaction['id'])));
$rows[] = array('Timestamp', FormatHelper::datetime($transaction['stamp']));
$rows[] = array('Effective', FormatHelper::date($entry['effective_date']));
//$rows[] = array('Through', FormatHelper::date($entry['through_date']));
$rows[] = array('Customer', (isset($customer['name'])
? $html->link($customer['name'],
array('controller' => 'customers',
'action' => 'view',
$customer['id']))
: null));
$rows[] = array('Lease', (isset($lease['id'])
? $html->link('#'.$lease['id'],
array('controller' => 'leases',
'action' => 'view',
$lease['id']))
: null));
$rows[] = array('Comment', $entry['comment']);
$rows[] = array('Comment', $entry['comment']);
echo $this->element('table',
array('class' => 'item ledger-entry detail',
'caption' => 'Double Ledger Entry Detail',
array('class' => 'item double-entry detail',
'caption' => 'Double Ledger Entry',
'rows' => $rows,
'column_class' => array('field', 'value')));
/**********************************************************************
* LedgerEntry Info Box
* Debit/Credit Entries
*/
/* echo '<div class="infobox">' . "\n"; */
/* foreach ($ledgers AS $type => $ledger) { */
/* //pr($ledger); */
/* if (!$ledger['Account']['trackable']) */
/* continue; */
/* $applied_caption = "Transfers applied"; */
/* $remaining_caption = "Unapplied amount"; */
/* $rows = array(); */
/* $rows[] = array($applied_caption, */
/* FormatHelper::currency($stats[$type]['amount_reconciled'])); */
/* $rows[] = array($remaining_caption, */
/* FormatHelper::currency($stats[$type]['amount_remaining'])); */
/* echo $this->element('table', */
/* array('class' => 'item summary', */
/* 'caption' => "{$ledger['Account']['name']} Ledger Entry", */
/* 'rows' => $rows, */
/* 'column_class' => array('field', 'value'), */
/* //'suppress_alternate_rows' => true, */
/* )); */
/* } */
/* echo '</div>' . "\n"; */
echo ('<DIV CLASS="ledger-double-entry">' . "\n");
foreach ($ledgers AS $type => $ledger) {
$rows = array();
$rows[] = array('ID', $html->link('#' . $entries[$type]['id'],
array('controller' => 'entries',
'action' => 'view',
$entries[$type]['id'])));
$rows[] = array('Account', $html->link($ledger['Account']['name'],
array('controller' => 'accounts',
'action' => 'view',
$ledger['Account']['id'])));
$rows[] = array('Ledger', $html->link('#' . $ledger['Account']['id']
. '-' . $ledger['sequence'],
array('controller' => 'ledgers',
'action' => 'view',
$ledger['id'])));
$rows[] = array('Amount', FormatHelper::currency($entry['amount']));
$rows[] = array('Effect', $ledger['Account']['ftype'] == $type ? 'INCREASE' : 'DECREASE');
// REVISIT <AP>: 20090816
// Due to low priority, the ledger_entry/double_entry stuff
// is a bit piecemeal at the moment (trying to reuse old
// code as much as possible). So, LedgerEntry view is just
// redirecting here. Of course, presenting a link for the
// LedgerEntry then is, well, quite pointless.
$rows[] = array('ID', '#' . $entries[$type]['id']);
/* $rows[] = array('ID', $html->link('#' . $entries[$type]['id'], */
/* array('controller' => 'entries', */
/* 'action' => 'view', */
/* $entries[$type]['id']))); */
$rows[] = array('Account', ($ledger['link']
? $html->link($ledger['Account']['name'],
array('controller' => 'accounts',
'action' => 'view',
$ledger['Account']['id']))
: $ledger['Account']['name']));
$rows[] = array('Ledger', ($ledger['link']
? $html->link('#' . $ledger['sequence'],
array('controller' => 'ledgers',
'action' => 'view',
$ledger['id']))
: '#' . $ledger['sequence']));
$rows[] = array('Amount', FormatHelper::currency($entries[$type]['amount']));
//$rows[] = array('Effect', $ledger['Account']['ftype'] == $type ? 'INCREASE' : 'DECREASE');
echo $this->element('table',
array('class' => array('item', $type, 'detail'),
'caption' => ucfirst($type) . ' Ledger Entry',
'caption' => ucfirst($type) . ' Entry',
'rows' => $rows,
'column_class' => array('field', 'value')));
}

View File

@@ -2,7 +2,6 @@
// Define the table columns
$cols = array();
$cols['ID'] = array('index' => 'Account.id', 'formatter' => 'id');
$cols['Name'] = array('index' => 'Account.name', 'formatter' => 'longname');
$cols['Type'] = array('index' => 'Account.type', 'formatter' => 'enum');
$cols['Entries'] = array('index' => 'entries', 'formatter' => 'number');
@@ -15,7 +14,7 @@ $cols['Comment'] = array('index' => 'Account.comment', 'formatter' => 'comment
$grid
->columns($cols)
->sortField('Name')
->defaultFields(array('ID', 'Name'))
->defaultFields(array('Name'))
->searchFields(array('Name'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Comment')));

View File

@@ -2,19 +2,19 @@
// Define the table columns
$cols = array();
$cols['ID'] = array('index' => 'Contact.id', 'formatter' => 'id');
$cols['Last Name'] = array('index' => 'Contact.last_name', 'formatter' => 'name');
$cols['First Name'] = array('index' => 'Contact.first_name', 'formatter' => 'name');
$cols['Company'] = array('index' => 'Contact.company_name', 'formatter' => 'longname');
$cols['Type'] = array('index' => 'ContactsCustomer.type', 'formatter' => 'enum');
$cols['Active'] = array('index' => 'ContactsCustomer.active', 'formatter' => 'enum');
$cols['Comment'] = array('index' => 'Contact.comment', 'formatter' => 'comment');
$cols['Relationship'] = array('index' => 'ContactsCustomer.type', 'formatter' => 'enum');
$cols['Name'] = array('index' => 'Contact.display_name', 'formatter' => 'longname');
$cols['Last Name'] = array('index' => 'Contact.last_name', 'formatter' => 'name');
$cols['First Name'] = array('index' => 'Contact.first_name', 'formatter' => 'name');
$cols['License'] = array('index' => 'Contact.id_local', 'formatter' => 'name');
$cols['Company'] = array('index' => 'Contact.company_name', 'formatter' => 'longname');
$cols['Comment'] = array('index' => 'Contact.comment', 'formatter' => 'comment');
// Render the grid
$grid
->columns($cols)
->sortField('Last Name')
->defaultFields(array('ID', 'Last Name', 'First Name'))
->defaultFields(array('Last Name', 'First Name'))
->searchFields(array('Last Name', 'First Name', 'Company'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Type', 'Active', 'Comment')));
array_diff(array_keys($cols), array('Relationship', 'License', 'Comment')));

View File

@@ -2,25 +2,22 @@
// Define the table columns
$cols = array();
$cols['ID'] = array('index' => 'Customer.id', 'formatter' => 'id');
$cols['Customer'] = array('index' => 'Customer.id', 'formatter' => 'id');
$cols['Relationship'] = array('index' => 'ContactsCustomer.type', 'formatter' => 'enum');
$cols['Name'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Last Name'] = array('index' => 'PrimaryContact.last_name', 'formatter' => 'name');
$cols['First Name'] = array('index' => 'PrimaryContact.first_name', 'formatter' => 'name');
$cols['Leases'] = array('index' => 'current_lease_count', 'formatter' => 'number');
$cols['Units'] = array('index' => 'current_lease_count', 'formatter' => 'number');
$cols['Past Leases'] = array('index' => 'past_lease_count', 'formatter' => 'number');
$cols['Leases'] = array('index' => 'lease_count', 'formatter' => 'number');
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
$cols['Comment'] = array('index' => 'Customer.comment', 'formatter' => 'comment');
// Certain fields are only valid with a particular context
if (!isset($config['filter']['Contact.id']))
$grid->invalidFields('Relationship');
// Render the grid
$grid
->columns($cols)
->sortField('Name')
->defaultFields(array('ID', 'Name'))
->defaultFields(array('Name'))
->searchFields(array('Name', 'Last Name', 'First Name'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Comment')));
array_diff(array_keys($cols), array('Relationship', 'Past Leases', 'Comment')));

View File

@@ -1,116 +0,0 @@
<?php /* -*- mode:PHP -*- */
// Define the table columns
$cols = array();
$cols['Transaction'] = array('index' => 'Transaction.id', 'formatter' => 'id');
$cols['Entry'] = array('index' => 'LedgerEntry.id', 'formatter' => 'id');
$cols['Date'] = array('index' => 'Transaction.stamp', 'formatter' => 'date');
$cols['Effective'] = array('index' => 'LedgerEntry.effective_date', 'formatter' => 'date');
$cols['Through'] = array('index' => 'LedgerEntry.through_date', 'formatter' => 'date');
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name');
$cols['Debit Account'] = array('index' => 'DebitAccount.name', 'formatter' => 'name');
$cols['Credit Account'] = array('index' => 'CreditAccount.name', 'formatter' => 'name');
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id');
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'name');
$cols['Source'] = array('index' => 'MonetarySource.name', 'formatter' => 'name');
$cols['Comment'] = array('index' => 'LedgerEntry.comment', 'formatter' => 'comment', 'width'=>150);
$cols['Amount'] = array('index' => 'LedgerEntry.amount', 'formatter' => 'currency');
$cols['Debit'] = array('index' => 'debit', 'formatter' => 'currency');
$cols['Credit'] = array('index' => 'credit', 'formatter' => 'currency');
$cols['Last Payment'] = array('index' => 'last_paid', 'formatter' => 'date');
$cols['Applied'] = array('index' => "applied", 'formatter' => 'currency');
$cols['Sub-Total'] = array('index' => 'subtotal-LedgerEntry.amount', 'formatter' => 'currency', 'sortable' => false);
if (isset($transaction_id) || isset($reconcile_id))
$grid->invalidFields('Transaction');
if (!isset($collected_account_id))
$grid->invalidFields('Last Payment');
if (isset($account_ftype) || isset($ledger_id) || isset($account_id) || isset($ar_account) || isset($customer_id))
$grid->invalidFields(array('Debit Account', 'Credit Account'));
else
$grid->invalidFields('Account');
if (isset($no_account) || $group_by_tx || isset($collected_account_id))
$grid->invalidFields(array('Account', 'Debit Account', 'Credit Account'));
if (isset($ledger_id) || isset($account_id) || isset($ar_account) || isset($customer_id)) {
$grid->invalidFields('Amount');
$cols['Sub-Total']['index'] = 'subtotal-balance';
} else {
$grid->invalidFields(array('Debit', 'Credit'));
$cols['Sub-Total']['index'] = 'subtotal-LedgerEntry.amount';
}
// group_by_tx SHOULD wipe out Customer, but the reality
// is that it works good at the present, so we'll leave it.
if (isset($lease_id) || isset($customer_id))
$grid->invalidFields(array('Customer'));
if (isset($lease_id) || $group_by_tx)
$grid->invalidFields(array('Lease', 'Unit'));
if (!isset($reconcile_id) && !isset($collected_account_id))
$grid->invalidFields('Applied');
else
$cols['Sub-Total']['index'] = 'subtotal-applied';
if (isset($account_ftype) || isset($collected_account_id))
$grid->invalidFields('Sub-Total');
// Now that columns are defined, establish basic grid parameters
$grid
->columns($cols)
->sortField('Date')
->defaultFields(array('Entry', 'Date', 'Amount', 'Credit', 'Debit'));
if (!isset($config['rows']) && !isset($collected_account_id)) {
$config['action'] = 'ledger';
$grid->limit(50);
}
if (isset($reconcile_id)) {
$config['action'] = 'reconcile';
$grid->customData(compact('reconcile_id'))->limit(20);
}
if (isset($collected_account_id)) {
$config['action'] = 'collected';
$account_id = $collected_account_id;
$grid->limit(50);
$grid->sortField('Last Payment');
}
if (isset($entry_ids))
$grid->id_list($entry_ids);
// Set up search fields if requested by caller
if (isset($searchfields))
$grid->searchFields(array('Customer', 'Unit'));
// Include custom data
$grid->customData(compact('ledger_id', 'account_id', 'ar_account',
'account_type', 'account_ftype', 'monetary_source_id',
'customer_id', 'lease_id', 'transaction_id', 'group_by_tx'));
// Render the grid
$grid
->render($this, isset($config) ? $config : null,
array('Transaction', 'Entry', 'Date', 'Effective', 'Last Payment',
'Account', 'Debit Account', 'Credit Account',
'Customer', 'Unit',
'Comment',
'Amount', 'Debit', 'Credit',
'Applied', 'Sub-Total')
);

View File

@@ -32,8 +32,8 @@ foreach ($fields AS $field => $config) {
$include_after = true;
}
$column_class = array();
if (empty($column_class))
$column_class = array();
if ($include_before)
$column_class[] = 'before';
$column_class[] = 'field';
@@ -79,7 +79,13 @@ foreach ($fields AS $field => $config) {
$cells[] = null;
}
$name = $config['name'];
if (empty($config['opts']['label']))
$name = $form->label($field, $config['name'],
empty($config['label_attributes'])
? null : $config['label_attributes']);
else
$name = $config['name'];
if (isset($config['with_name_before']))
$name = $config['with_name_before'] . $name;
elseif (isset($with_name_before))
@@ -107,7 +113,7 @@ foreach ($fields AS $field => $config) {
if (isset($config['with_value_after']))
$value = $value . $config['with_value_after'];
elseif (isset($with_value_after))
$value = $valeu . $with_value_after;
$value = $value . $with_value_after;
$cells[] = $value;
if ($include_after) {

View File

@@ -19,6 +19,7 @@ if (!isset($limitOptions)) {
}
sort($limitOptions, SORT_NUMERIC);
$limitOptions = array_unique($limitOptions, SORT_NUMERIC);
//$limitOptions[] = 'ALL'; // Would be nice... jqGrid shows 'NaN of NaN'
if (!isset($height))
$height = 'auto';
@@ -46,12 +47,10 @@ if (!isset($grid_setup))
$grid_setup = array();
// Do some prework to bring in the appropriate libraries
$html->css('jqGrid/ui.jqgrid', null, null, false);
//$html->css('jqGrid/jqModal', null, null, false);
$html->css('ui.jqgrid', null, null, false);
$javascript->link('jqGrid/grid.locale-en', false);
$javascript->link('jqGrid/jquery.jqGrid.min', false);
//$javascript->link('jqGrid/js/jqModal', false);
//$javascript->link('jqGrid/js/jqDnR', false);
$javascript->link('jqGrid/grid.postext', false);
$javascript->link('pmgr_jqGrid', false);
@@ -63,7 +62,6 @@ $javascript->link('pmgr_jqGrid', false);
// as part of the data fetch.
$url = $html->url(array('controller' => $controller,
'action' => 'gridData',
'debug' => 0,
));
// Create extra parameters that jqGrid will pass to our
@@ -124,15 +122,20 @@ foreach ($jqGridColumns AS $header => &$col) {
// No special formatting for number
unset($col['formatter']);
}
elseif ($col['formatter'] === 'percentage') {
$col['formatter'] = array('--special' => 'percentageFormatter');
$default['width'] = 60;
$default['align'] = 'right';
}
elseif ($col['formatter'] === 'currency') {
// Use our custom formatting for currency
$col['formatter'] = array('--special' => 'currencyFormatter');
$default['width'] = 85;
$default['width'] = 65;
$default['align'] = 'right';
}
elseif ($col['formatter'] === 'date') {
$default['formatoptions'] = array('newformat' => 'm/d/Y');
$default['width'] = 95;
$default['width'] = 90;
$default['align'] = 'center';
}
elseif (preg_match("/^(long|short)?name$/",
@@ -146,8 +149,14 @@ foreach ($jqGridColumns AS $header => &$col) {
// No special formatting for name
unset($col['formatter']);
}
elseif ($col['formatter'] === 'enum') {
elseif (preg_match("/^(long|short)?enum$/",
$col['formatter'], $matches)) {
$default['width'] = 60;
if (!empty($matches[1]) && $matches[1] === 'long')
$default['width'] *= 1.5;
if (!empty($matches[1]) && $matches[1] === 'short')
$default['width'] *= 0.7;
//$default['align'] = 'right';
// No special formatting for enum
@@ -164,7 +173,8 @@ foreach ($jqGridColumns AS $header => &$col) {
// Just a rough approximation to ensure columns
// are wide enough to fully display their header.
$min_width = strlen($header) * 10;
$min_width = strlen($header) * 7;
$min_width = 0; // REVISIT <AP>: 20090829; if/while jqGrid is fixed width
if ((!isset($default['width']) || $default['width'] < $min_width) && !$default['force'])
$default['width'] = $min_width;
}
@@ -188,9 +198,12 @@ if (isset($sort_order)) {
$sortorder = 'ASC';
}
if (1) { // debug
$debug = !empty($this->params['dev']);
if ($debug)
$caption .= '<span class="debug grid-query"> :: <span id="'.$grid_id.'-query"></span></span>';
}
$caption .= ('<span class="grid-error" id="'.$grid_id.'-error"' .
' style="display:none"> :: Error (Please Reload)</span>');
foreach (array_merge(array('loadComplete' => '', 'loadError' => ''),
$grid_events) AS $event => $statement) {
@@ -200,13 +213,21 @@ foreach (array_merge(array('loadComplete' => '', 'loadError' => ''),
$statement = current($statement);
}
if ($event == 'loadComplete') {
if ($event == 'loadComplete' && $debug) {
$grid_events[$event] =
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url.replace(/\/debug.*$/,'?'); pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Query</A><BR>'); $statement;}");
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url+'/debug:1?'; pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Query</A><BR>'); $statement;}");
}
elseif ($event == 'loadError') {
elseif ($event == 'loadError' && $debug) {
$grid_events[$event] =
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url.replace(/\/debug.*$/,'?'); pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Error Query</A><BR>'); $statement;}");
array('--special' => "function($params) {url=jQuery('#{$grid_id}').getGridParam('url');url=url+'/debug:1?'; pd=jQuery('#{$grid_id}').getPostData();$.each(pd,function(i){ url+=i+'='+escape(pd[i])+'&'; }); jQuery('#{$grid_id}-query').html('<A HREF=\"'+url+'\">Grid Error Query</A><BR>'); $statement;}");
}
elseif ($event == 'loadComplete' && !$debug) {
$grid_events[$event] =
array('--special' => "function($params) {jQuery('#{$grid_id}-error').hide(); $statement;}");
}
elseif ($event == 'loadError' && !$debug) {
$grid_events[$event] =
array('--special' => "function($params) {jQuery('#{$grid_id}-error').show(); $statement;}");
}
else {
$grid_events[$event] =
@@ -226,6 +247,7 @@ $jqGrid_setup = array_merge
'colNames' => array_keys($jqGridColumns),
'colModel' => array('--special' => $jqGridColumns),
'height' => $height,
'width' => 700,
'rowNum' => $limit,
'rowList' => $limitOptions,
'sortname' => $sortname,
@@ -245,37 +267,46 @@ $jqGrid_setup = array_merge
// to kick this thing off.
?>
<?php if ($first_grid): ?>
<script type="text/javascript"><!--
var currencyFormatter = function(cellval, opts, rowObject) {
if (!cellval)
return "";
return fmtCurrency(cellval);
}
var percentageFormatter = function(cellval, opts, rowObject) {
var precision;
if (typeof(opts.colModel) != 'undefined' &&
typeof(opts.colModel.formatoptions) != 'undefined' &&
typeof(opts.colModel.formatoptions.precision) != 'undefined')
precision = opts.colModel.formatoptions.precision;
else
precision = 0;
amount = cellval.toString().replace(/\%/g,'');
amount = (amount*100).toFixed(precision);
return amount+'%';
}
var idFormatter = function(cellval, opts, rowObject) {
if (!cellval)
return cellval;
return '#'+cellval;
}
--></script>
<?php endif; ?>
<DIV ID="<?php echo $grid_div_id; ?>" CLASS="<?php echo $grid_div_class; ?>">
<table id="<?php echo $grid_id; ?>" class="scroll"></table>
<div id="<?php echo $grid_id; ?>-pager" class="scroll" style="text-align:right"></div>
<script type="text/javascript"><!--
jQuery(document).ready(function(){
currencyFormatter = function(cellval, opts, rowObject) {
if (!cellval)
return "";
return fmtCurrency(cellval);
}
idFormatter = function(cellval, opts, rowObject) {
if (!cellval)
return cellval;
return '#'+cellval;
}
jQuery('#<?php echo $grid_id; ?>').jqGrid(
<?php echo FormatHelper::phpVarToJavascript($jqGrid_setup); ?>
).navGrid('#<?php echo $grid_id; ?>-pager',
{ view:false,
edit:false,
add:false,
del:false,
search:true,
refresh:true});
<?php echo FormatHelper::phpVarToJavascript($jqGrid_setup) . "\n"; ?>
).navGrid('#<?php echo $grid_id; ?>-pager', { view:false,edit:false,add:false,del:false,search:true,refresh:true});
});
--></script>
<?php
if (count($search_fields) > 0) {
echo('<div>Search By:<BR>' . "\n");

View File

@@ -2,24 +2,36 @@
// Define the table columns
$cols = array();
$cols['LeaseID'] = array('index' => 'Lease.id', 'hidden' => true);
$cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id');
$cols['Unit'] = array('index' => 'Unit.name', 'width' => '50', 'align' => 'center');
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname', 'align' => 'center');
$cols['Customer id'] = array('index' => 'Customer.id', 'hidden' => true);
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Rent'] = array('index' => 'Lease.rent', 'formatter' => 'currency', 'hiddenz' => true);
$cols['Deposit'] = array('index' => 'Lease.deposit', 'formatter' => 'currency', 'hiddenz' => true);
$cols['Rent'] = array('index' => 'Lease.rent', 'formatter' => 'currency');
$cols['Deposit'] = array('index' => 'Lease.deposit', 'formatter' => 'currency');
$cols['Signed'] = array('index' => 'Lease.lease_date', 'formatter' => 'date');
$cols['Move-In'] = array('index' => 'Lease.movein_date', 'formatter' => 'date');
$cols['Move-Out'] = array('index' => 'Lease.moveout_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['Status'] = array('index' => 'status', 'formatter' => 'longenum');
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
$cols['Comment'] = array('index' => 'Lease.comment', 'formatter' => 'comment');
if (!empty($this->params['action'])) {
if ($this->params['action'] === 'closed')
$grid->invalidFields(array('Charge-Thru', 'Paid-Thru', 'Status'));
elseif ($this->params['action'] === 'active')
$grid->invalidFields(array('Closed'));
elseif ($this->params['action'] === 'delinquent')
$grid->invalidFields(array('Closed'));
}
// Render the grid
$grid
->columns($cols)
->sortField('LeaseID')
->defaultFields(array('LeaseID', 'Lease'))
->sortField('Lease')
->defaultFields(array('Lease'))
->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Comment')));
array_diff(array_keys($cols), array('Signed', 'Charge-Thru', 'Status', 'Comment')));

View File

@@ -20,11 +20,11 @@ $cols['Sub-Total'] = array('index' => 'subtotal-balance', 'formatter' =>
// Render the grid
$grid
->limit(50)
->columns($cols)
->sortField('Date')
->sortField('Date', 'DESC')
->defaultFields(array('Entry', 'Date', 'Amount'))
->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Debit', 'Credit', 'Balance', 'Sub-Total', 'Comment')));
array_diff(array_keys($cols), array('Transaction', 'Debit', 'Credit',
'Balance', 'Sub-Total', 'Comment')));

View File

@@ -2,9 +2,8 @@
// Define the table columns
$cols = array();
$cols['ID'] = array('index' => 'id_sequence', 'formatter' => 'id');
$cols['Name'] = array('index' => 'Ledger.name', 'formatter' => 'name');
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'longname');
$cols['Sequence'] = array('index' => 'Ledger.sequence', 'formatter' => 'id');
$cols['Open Date'] = array('index' => 'PriorCloseTransaction.stamp', 'formatter' => 'date');
$cols['Close Date'] = array('index' => 'CloseTransaction.stamp', 'formatter' => 'date');
$cols['Comment'] = array('index' => 'Ledger.comment', 'formatter' => 'comment');
@@ -16,8 +15,8 @@ $cols['Balance'] = array('index' => 'balance', 'formatter' => 'c
// Render the grid
$grid
->columns($cols)
->sortField('ID', 'ASC')
->defaultFields(array('ID', 'Name', 'Account'))
->searchFields(array('Account', 'Comment'))
->sortField('Sequence')
->defaultFields(array('Sequence'))
->searchFields(array('Comment'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Open Date', 'Comment')));
array_diff(array_keys($cols), array('Account', 'Open Date', 'Comment')));

View File

@@ -0,0 +1,20 @@
<?php /* -*- mode:PHP -*- */
// Define the table columns
$cols = array();
$cols['Name'] = array('index' => 'name', 'formatter' => 'name');
$cols['Comment'] = array('index' => 'comment', 'formatter' => 'comment');
$cols['Key/Combo'] = array('index' => 'key', 'formatter' => 'number');
$cols['Previous Key'] = array('index' => 'key_last', 'formatter' => 'number');
$cols['Quantity'] = array('index' => 'qty', 'formatter' => 'number');
$cols['In Use'] = array('index' => 'inuse', 'formatter' => 'number');
$cols['Available'] = array('index' => 'avail', 'formatter' => 'number');
// Render the grid
$grid
->columns($cols)
->sortField('Name')
->defaultFields(array('Name'))
->searchFields(array('Name'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Previous Key')));

View File

@@ -2,7 +2,6 @@
// Define the table columns
$cols = array();
$cols['ID'] = array('index' => 'Map.id', 'formatter' => 'id');
$cols['Name'] = array('index' => 'Map.name', 'formatter' => 'longname');
$cols['Site Area'] = array('index' => 'SiteArea.name', 'formatter' => 'longname');
$cols['Width'] = array('index' => 'Map.width', 'formatter' => 'number');
@@ -13,7 +12,7 @@ $cols['Comment'] = array('index' => 'Map.comment', 'formatter' => 'comment
$grid
->columns($cols)
->sortField('Name')
->defaultFields(array('ID', 'Name'))
->defaultFields(array('Name'))
->searchFields(array('Name'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array()));

View File

@@ -8,17 +8,78 @@
* @package pmgr
*/
foreach ($menu AS $item) {
if (isset($item['header']))
echo('<DIV CLASS="header">' . $item['name'] . '</DIV>' . "\n");
elseif (isset($item['hr']))
echo('<HR>' . "\n");
elseif (isset($item['url']))
echo('<DIV CLASS="item">'
. $html->link($item['name'], $item['url'],
isset($item['htmlAttributes']) ? $item['htmlAttributes'] : null,
isset($item['confirmMessage']) ? $item['confirmMessage'] : null,
isset($item['escapeTitle']) ? $item['escapeTitle'] : null)
// REVISIT <AP>: 20090823
// Add way to slide the entire menu off the page
. '</DIV>' . "\n");
// The sidemenu-container is necessary to define the
// bounds as the parent of the sidemenu div, which will
// be heavily manipulated by the accordion module. If
// we don't have good control over the parent, the
// accordion will get confused and behave poorly.
echo('<DIV ID="sidemenu-container">' . "\n");
echo('<DIV ID="sidemenu">' . "\n");
$section = 0;
$active_section = null;
foreach ($menu['areas'] AS $area_name => $area) {
if (empty($area['subareas']))
continue;
foreach ($area['subareas'] AS $subarea_name => $subarea) {
if (empty($subarea['priorities']))
continue;
if (!isset($active_section) &&
!empty($menu['active']['area']) && $area_name == $menu['active']['area'] &&
(empty($menu['active']['subarea']) || $subarea_name == $menu['active']['subarea']))
$active_section = $section;
++$section;
echo('<H3' .
//' id="sidemenu-section-'.$area_name.'-'.$subarea_name.'"' .
' class="sidemenu-header">' .
$subarea['name'] .
"</H3>\n");
echo('<DIV class="sidemenu-content">' . "\n");
foreach ($subarea['priorities'] AS $priority) {
foreach ($priority AS $item) {
if (isset($item['url'])) {
echo('<DIV CLASS="sidemenu-item">'
. $html->link($item['name'], $item['url'],
isset($item['htmlAttributes']) ? $item['htmlAttributes'] : null,
isset($item['confirmMessage']) ? $item['confirmMessage'] : null,
isset($item['escapeTitle']) ? $item['escapeTitle'] : null)
. '</DIV>' . "\n");
}
}
}
echo('</DIV>' . "\n");
}
}
echo('</DIV>' . "\n"); // End #sidemenu
echo('</DIV>' . "\n"); // End #sidemenu-container
// Uses both hoverintent, which is a more user friendly mechanism
// than mouseover, as well as click. This provides 1) a workable
// solution for those browsers that don't use pointers, such as
// a touchscreen, and 2) a means to open the menu if the animation
// was running while the user moved the pointer to a new menu area.
$javascript->codeBlock(
<<<JSCB
jQuery(document).ready(function(){
if (jQuery("#sidemenu").accordion != null) {
jQuery("#sidemenu").accordion
({ fillSpace : true,
event : "click hoverintent",
animated : "bounceslide"
JSCB
. (isset($active_section) ? ",\n\t active : $active_section\n" : '') .
<<<JSCB
});
}
});
JSCB
, array('inline' => false));

View File

@@ -9,19 +9,22 @@ $cols['Date'] = array('index' => 'Transaction.stamp', 'formatter' =>
$cols['Effective'] = array('index' => 'StatementEntry.effective_date', 'formatter' => 'date');
$cols['Through'] = array('index' => 'StatementEntry.through_date', 'formatter' => 'date');
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name');
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id');
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname');
$cols['Comment'] = array('index' => 'StatementEntry.comment', 'formatter' => 'comment', 'width'=>150);
$cols['Type'] = array('index' => 'StatementEntry.type', 'formatter' => 'enum', 'width'=>120);
$cols['Type'] = array('index' => 'StatementEntry.type', 'formatter' => 'longenum');
$cols['Account'] = array('index' => 'Account.name', 'formatter' => 'name');
$cols['Debit'] = array('index' => 'charge', 'formatter' => 'currency');
$cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency');
$cols['Applied'] = array('index' => "applied", 'formatter' => 'currency');
$cols['Amount'] = array('index' => "StatementEntry.amount", 'formatter' => 'currency');
$cols['Received'] = array('index' => "applied", 'formatter' => 'currency');
// 'balance' is already in use as part of charge/disbursement/balance.
// 'unapplied' isn't quite the right term, but it's not customer visible.
$cols['Balance'] = array('index' => "unapplied", 'formatter' => 'currency');
$cols['Sub-Total'] = array('index' => 'subtotal-balance', 'formatter' => 'currency', 'sortable' => false);
@@ -29,17 +32,30 @@ if (isset($subtotal_column))
$cols['Sub-Total']['index'] =
'subtotal-' . $cols[$subtotal_column]['index'];
if ((isset($action) && $action == 'unreconciled') ||
(isset($config) && isset($config['action']) && $config['action'] == 'unreconciled')) {
if (isset($config) && !isset($config['grid_div_id']))
$config['grid_div_id'] = 'unpaid';
$include_columns = array('Entry', 'Date',
'Effective', 'Customer', 'Unit',
'Account', 'Amount', 'Received', 'Balance');
}
else {
$include_columns =
array_diff(array_keys($cols),
array('Transaction', 'Through', 'Lease',
'Amount', 'Received', 'Balance', 'Sub-Total',
'Comment'));
}
// Include custom data
$grid->customData(compact('statement_entry_id'));
// Render the grid
$grid
->columns($cols)
->sortField('Date')
->sortField('Date', 'DESC')
->defaultFields(array('Entry', 'Date', 'Charge', 'Payment'))
->searchFields(array('Customer', 'Unit'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Through', 'Lease',
'Applied', 'Sub-Total',
'Comment')));
->render($this, isset($config) ? $config : null, $include_columns);

View File

@@ -52,8 +52,8 @@ if (isset($rows) && is_array($rows) && count($rows)) {
foreach ($rows AS $r => &$row) {
foreach ($row AS $c => $col) {
$cell_class = implode(" ", array_merge(isset( $row_class[$r]) ? $row_class[$r] : array(),
isset($column_class[$c]) ? $column_class[$c] : array()));
$cell_class = implode(" ", array_merge(empty( $row_class[$r]) ? array() : $row_class[$r],
empty($column_class[$c]) ? array() : $column_class[$c]));
if ($cell_class)
$row[$c] = array($col, array('class' => $cell_class));
}
@@ -65,11 +65,11 @@ if (isset($rows) && is_array($rows) && count($rows)) {
// OK, output the table HTML
echo('<TABLE' .
(isset($id) ? ' ID="'.$id.'"' : '') .
(isset($class) ? ' CLASS="'.$class.'"' : '') .
(empty($id) ? '' : ' ID="'.$id.'"') .
(empty($class) ? '' : ' CLASS="'.$class.'"') .
'>' . "\n");
if (isset($caption))
if (!empty($caption))
echo(' <CAPTION>' . $caption . '</CAPTION>' . "\n");
if (isset($headers) && is_array($headers)) {

View File

@@ -2,11 +2,10 @@
// Define the table columns
$cols = array();
//$cols['ID'] = array('index' => 'Tender.id', 'formatter' => 'id');
$cols['Date'] = array('index' => 'Transaction.stamp', 'formatter' => 'date');
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Item'] = array('index' => 'Tender.name', 'formatter' => 'longname');
$cols['Type'] = array('index' => 'TenderType.name', 'formatter' => 'name');
$cols['Type'] = array('index' => 'TenderType.name', 'formatter' => 'shortname');
$cols['Comment'] = array('index' => 'Tender.comment', 'formatter' => 'comment');
$cols['Amount'] = array('index' => 'LedgerEntry.amount', 'formatter' => 'currency');
$cols['Sub-Total'] = array('index' => 'subtotal-LedgerEntry.amount', 'formatter' => 'currency');
@@ -18,4 +17,4 @@ $grid
->defaultFields(array('Date', 'Name', 'Amount'))
->searchFields(array('Name', 'Type'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Sub-Total')));
array_diff(array_keys($cols), array('Comment', 'Sub-Total')));

View File

@@ -1,20 +1,27 @@
<?php /* -*- mode:PHP -*- */
if (isset($include))
$include = is_array($include) ? $include : array($include);
else
$include = array();
// Define the table columns
$cols = array();
$cols['ID'] = array('index' => 'Transaction.id', 'formatter' => 'id');
$cols['Type'] = array('index' => 'Transaction.type', 'formatter' => 'enum');
//$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Customer'] = array('index' => 'Customer.name', 'formatter' => 'longname');
$cols['Timestamp'] = array('index' => 'Transaction.stamp', 'formatter' => 'date');
$cols['Comment'] = array('index' => 'Transaction.comment', 'formatter' => 'comment', 'sortable' => false);
$cols['Entries'] = array('index' => 'entries', 'formatter' => 'number');
$cols['Amount'] = array('index' => 'Transaction.amount', 'formatter' => 'currency');
$cols['entries'] = array('index' => 'entries', 'formatter' => 'number');
$cols['Comment'] = array('index' => 'Transaction.comment', 'formatter' => 'comment');
$cols['PosNeg'] = array('index' => 'balance', 'formatter' => 'currency');
$cols['Balance'] = array('index' => 'subtotal-balance', 'formatter' => 'currency', 'sortable' => false);
// Render the grid
$grid
->columns($cols)
->sortField('Timestamp')
->sortField('Timestamp', 'DESC')
->defaultFields(array('ID', 'Timestamp'))
->searchFields(array('Type', 'Comment'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Comment')));
array_merge($include, array_diff(array_keys($cols), array('Customer', 'PosNeg', 'Balance', 'Comment'))));

View File

@@ -0,0 +1,40 @@
<?php /* -*- mode:PHP -*- */
// Define the table columns
$cols = array();
$cols['Size'] = array('index' => 'UnitSize.name', 'formatter' => 'shortname');
$cols['Type'] = array('index' => 'UnitType.name', 'formatter' => 'shortname');
$cols['Width'] = array('index' => 'UnitSize.width', 'formatter' => 'number');
$cols['Depth'] = array('index' => 'UnitSize.depth', 'formatter' => 'number');
$cols['Height'] = array('index' => 'UnitSize.height', 'formatter' => 'number');
$cols['Area'] = array('index' => 'sqft', 'formatter' => 'number');
$cols['Volume'] = array('index' => 'cuft', 'formatter' => 'number');
$cols['Deposit'] = array('index' => 'UnitSize.deposit', 'formatter' => 'currency');
$cols['Rent'] = array('index' => 'UnitSize.rent', 'formatter' => 'currency');
$cols['Per Foot'] = array('index' => 'sqcost', 'formatter' => 'currency');
$cols['Per Cubic Ft'] = array('index' => 'cucost', 'formatter' => 'currency');
$cols['Unavailable'] = array('index' => 'unavailable', 'formatter' => 'number');
$cols['Occupied'] = array('index' => 'occupied', 'formatter' => 'number');
$cols['Available'] = array('index' => 'available', 'formatter' => 'number');
$cols['Total'] = array('index' => 'units', 'formatter' => 'number');
$cols['Occupancy'] = array('index' => 'occupancy', 'formatter' => 'percentage', 'formatoptions' => array('precision' => 0));
$cols['Vacancy'] = array('index' => 'vacancy', 'formatter' => 'percentage', 'formatoptions' => array('precision' => 0));
$cols['Comment'] = array('index' => 'Unit.comment', 'formatter' => 'comment');
// Render the grid
$grid
->columns($cols)
->sortField('Area')
->defaultFields(array('Size', 'Area'))
->searchFields(array('Size', 'Width', 'Depth', 'Area', 'Deposit', 'Rent'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Width', 'Depth',
'Deposit',
'Height', 'Volume',
//'Per Foot',
'Per Cubic Ft',
'Occupied',
//'Total',
'Occupancy',
//'Vacancy',
'Comment')));

View File

@@ -4,20 +4,23 @@
$cols = array();
$cols['Sort'] = array('index' => 'Unit.sort_order', 'hidden' => true);
$cols['Walk'] = array('index' => 'Unit.walk_order', 'formatter' => 'number');
$cols['ID'] = array('index' => 'Unit.id', 'formatter' => 'id');
$cols['Unit'] = array('index' => 'Unit.name', 'formatter' => 'shortname');
$cols['Size'] = array('index' => 'UnitSize.name', 'formatter' => 'shortname');
$cols['Area'] = array('index' => 'sqft', 'formatter' => 'number');
$cols['Rent'] = array('index' => 'Unit.rent', 'formatter' => 'currency');
$cols['Deposit'] = array('index' => 'Unit.deposit', 'formatter' => 'currency');
$cols['Status'] = array('index' => 'Unit.status', 'formatter' => 'name'); // We have enough real estate
$cols['Status'] = array('index' => 'Unit.status', 'formatter' => 'enum');
$cols['Balance'] = array('index' => 'balance', 'formatter' => 'currency');
$cols['Comment'] = array('index' => 'Unit.comment', 'formatter' => 'comment');
if (in_array($this->params['action'], array('vacant', 'unavailable')))
$grid->invalidFields('Balance');
// Render the grid
$grid
->columns($cols)
->sortField('Sort')
->defaultFields(array('Sort', 'ID', 'Unit'))
->defaultFields(array('Sort', 'Unit'))
->searchFields(array('Unit', 'Size', 'Status'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Walk', 'Deposit', 'Comment')));

View File

@@ -0,0 +1,3 @@
<?php /* -*- mode:PHP -*- */
if (!empty($message))
echo $message;

View File

@@ -24,9 +24,21 @@ class FormatHelper extends AppHelper {
return '-';
//return null;
$currency = self::$number->currency($amount,
isset($dollar_sign) ? $dollar_sign : 'USD',
$spans ? array('before'=>'', 'after'=>'') : array());
// Use of the $number->currency() function results in the clever,
// but problematic, use of cents for amounts less than $1. For
// example, 50 cents is shown as '50c', not '$0.50'. We want to
// keep everything in terms of dollars, especially for the cases
// where this result is placed into a form for input. 50 cents
// will end up as 50 dollars upon submission :-(
$currency = self::$number->format
(abs($amount),
array('places' => 2,
'before' => $spans ? '' : (isset($dollar_sign) ? $dollar_sign : '$'),
'after' => $spans ? '' : null,
));
if ($amount < 0)
$currency = '(' . $currency . ')';
if ($spans)
return ('<SPAN CLASS="dollar-sign">$</SPAN>' .
@@ -35,22 +47,36 @@ class FormatHelper extends AppHelper {
return $currency;
}
function date($date, $age = false) {
if (!$date) return null;
function percent($amount, $precision = 2) {
if (!isset($amount))
return '-';
$date_fmt = 'm/d/Y';
return (self::$time->format($date_fmt, $date) .
($age
? ' (' . self::age($date, 60*60*24) . ')'
: ''));
return self::$number->toPercentage($amount*100, $precision);
}
function datetime($datetime, $age = false) {
if (!$datetime) return null;
return (self::$time->nice($datetime) .
($age
? ' (' . self::age($datetime) . ')'
: ''));
function date($date, $age = false, $class = null, $time = false) {
if (!$date) return null;
if (empty($class))
$class = '';
if ($time)
$date_html = self::$time->nice($date);
else
$date_html = self::$time->format('m/d/Y', $date);
$date_html = '<span class="fmt-date '.$class.'">'.$date_html.'</span>';
if ($age) {
$date_html .= ' (' . self::age($date, $class, true, $time ? 0 : 60*60*24) . ')';
$date_html = '<span class="fmt-dateage '.$class.'">'.$date_html.'</span>';
}
return $date_html;
}
function datetime($datetime, $age = false, $class = null) {
return self::date($datetime, $age, $class, true);
}
function phone($phone, $ext = null) {
@@ -81,10 +107,13 @@ class FormatHelper extends AppHelper {
return $comment;
}
function age($datetime, $min_span = 0) {
function age($datetime, $class, $suffix = false, $min_span = 0) {
if (!isset($datetime))
return null;
if (empty($class))
$class = '';
$now = time();
$seconds = self::$time->fromString($datetime);
$backwards = ($seconds > $now);
@@ -95,9 +124,11 @@ class FormatHelper extends AppHelper {
//pr(compact('now', 'seconds', 'backwards', 'timefrom', 'timeto', 'span', 'min_span'));
// If now, just return so
if ($span === 0)
return __('now', true);
// If now, just use 'now'
if ($span === 0) {
$approx = 0;
$unit = 'now';
}
// Display seconds if under 45 seconds
if ($span < 45 && $span >= $min_span) {
@@ -164,20 +195,36 @@ class FormatHelper extends AppHelper {
//pr(compact('span', 'min_span', 'approx', 'unit'));
if ($approx == 0) {
if ($unit == 'day')
return __('today', true);
return __('this ' . $unit, true);
if ($unit == 'now')
$age = 'now';
elseif ($unit == 'day')
$age = 'today';
else
$age = 'this ' . $unit;
}
else {
if (isset($relative))
$age = $relative;
elseif ($approx > $span)
$age = 'almost';
elseif ($approx < $span)
$age = 'over';
else
$age = '';
return (__(isset($relative)
? $relative
: ($approx == $span
? ''
: ($approx > $span ? 'almost' : 'over')), true)
. ' '
. self::_n($approx, $unit)
. ($backwards ? '' : __(' ago', true)));
$age .= ' ' . self::_n($approx, $unit);
if ($suffix) {
if ($backwards)
$age .= ' from now';
else
$age .= ' ago';
}
}
$age = '<span class="fmt-age '.$class.'">'.__($age, true).'</span>';
return $age;
}
/*****************************
@@ -228,14 +275,21 @@ class FormatHelper extends AppHelper {
// Helper function to convert PHP vars to javascript
function phpVarToJavascript($var, $name = '', $depth='', $special = false) {
function phpVarToJavascript($var, $name = '', $depth='', $special = false, $pretty = false) {
// Establish a prefix to use before printing $var
$prefix = $depth;
if ($pretty) {
$prefix = $depth;
$pretty_sp = " ";
$pretty_nl = "\n";
}
else {
$prefix = $pretty_sp = $pretty_nl = '';
}
// If given a name, set it up JS style
if ($name)
$prefix .= $name . ": ";
$prefix .= $name . ":" . $pretty_sp;
if (!isset($var))
return $prefix . 'null';
@@ -288,22 +342,22 @@ class FormatHelper extends AppHelper {
// PHP array indices can be a mix of integer and string based.
// Just guess here, unless flagged as a special case.
if (isset($var[0]) || $special)
return ($prefix . "[\n"
. implode(",\n",
return ($prefix . "[" . $pretty_nl
. implode("," . $pretty_nl,
array_map(array('FormatHelper', 'phpVarToJavascript'),
array_values($var),
array(),
array_fill(0, count($var), $depth.' ')
))
. "\n$depth]");
. ($pretty ? "\n$depth" : '') . "]");
return ($prefix . "{\n"
. implode(",\n",
return ($prefix . "{" . $pretty_nl
. implode("," . $pretty_nl,
array_map(array('FormatHelper', 'phpVarToJavascript'),
array_values($var), array_keys($var),
array_fill(0, count($var), $depth.' ')
))
. "\n$depth}");
. ($pretty ? "\n$depth" : '') . "}");
}
}

View File

@@ -6,6 +6,7 @@ class GridHelper extends AppHelper {
var $included, $invalid;
var $columns;
var $controller;
static $first_grid = true;
function __construct() {
$this->reset();
@@ -166,9 +167,14 @@ class GridHelper extends AppHelper {
$included = array_diff(array_merge($this->included, $included),
array_merge($this->invalid, $excluded));
// Extract the columns that correspond to the inclusion set
$this->jqGrid_options['jqGridColumns']
= array_intersect_key($this->columns, array_flip($included));
// Defined the columns, based on the inclusion set,
// remapping column names as necessary.
$this->jqGrid_options['jqGridColumns'] = array();
foreach (array_intersect_key($this->columns, array_flip($included)) AS $name => $col) {
if (!empty($config['remap'][$name]))
$name = $config['remap'][$name];
$this->jqGrid_options['jqGridColumns'][$name] = $col;
}
// Make sure search fields are all part of the inclusion set
$this->jqGrid_options['search_fields']
@@ -209,12 +215,22 @@ class GridHelper extends AppHelper {
}
$this->jqGrid_options['controller'] = $controller;
// Add in any custom variables requested
if (isset($config['custom'])) {
$this->customData($config['custom']);
unset($config['custom']);
}
// Incorporate all other user options
if (isset($config))
$this->jqGrid_options = array_merge($this->jqGrid_options, $config);
// Set flag whether or not this is the first grid
$this->jqGrid_options['first_grid'] = self::$first_grid;
//pr(compact('config') + array('jqGrid_options' => $this->jqGrid_options));
echo $view->element('jqGrid', $this->jqGrid_options);
self::$first_grid = false;
// Since we only have one instance of this class
// as a helper, we must assume it could be used
@@ -224,4 +240,4 @@ class GridHelper extends AppHelper {
return $this;
}
}
}

View File

@@ -24,27 +24,80 @@
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<?php
/* print("<!--\n"); */
/* print("SERVER = "); print_r($_SERVER); print("\n"); */
/* print("REQUEST = "); print_r($_REQUEST); print("\n"); */
/* print("COOKIE = "); print_r($_COOKIE); print("\n"); */
/* print("-->\n"); */
?>
<head>
<?php echo $html->charset(); ?>
<title>
<?php if (devbox()) echo "*DEVBOX* "; ?>
<?php if (sandbox()) echo "*SANDBOX* "; ?>
Property Manager: <?php echo $title_for_layout; ?>
<?php if (sandbox()) echo " *SANDBOX*"; ?>
<?php if (devbox()) echo " *DEVBOX*"; ?>
</title>
<?php
// Reset the __scripts variable, which has already been dumped to
// $scripts_for_layout. Elements/Helpers used in the layout may
// also have some scripts to add. They cannot be put into the head
// but we can at least put them into a relatively benign place, so
// scripts don't have to be dumped inline in possibly awkward spots.
// Oh, and yes... I know we're not supposed to be using this variable
// directly, and will possibly get burned someday. Oh well, Cake
// hasn't left us a lot of choice, besides writing our own scripts
// mechanism _additional_ to what Cake has provided :-/
$this->__scripts = array();
if (!empty($_SERVER['HTTPS']))
$protocol = 'https://';
else
$protocol = 'http://';
echo $html->meta('icon') . "\n";
$theme = 'smoothness';
$theme = 'base';
$theme = 'dotluv';
$theme = 'dark-hive';
$theme = 'start';
if (devbox())
$theme = 'dotluv';
if (sandbox())
$theme = 'darkness';
echo $html->css('cake.generic') . "\n";
echo $html->css('themes/'.$theme.'/ui.all') . "\n";
echo $html->css('layout') . "\n";
echo $html->css('print', null, array('media' => 'print')) . "\n";
echo $html->css('sidemenu') . "\n";
echo $javascript->link('http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js') . "\n";
echo $javascript->link('http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js') . "\n";
//echo $html->css('themes/base/ui.all') . "\n";
//echo $html->css('themes/smoothness/ui.all') . "\n";
//echo $html->css('themes/dotluv/ui.all') . "\n";
echo $html->css('themes/start/ui.all') . "\n";
echo $javascript->link('jquery-1.7.2.min') . "\n";
echo $javascript->link('jquery-ui-1.7.2.custom.min') . "\n";
//echo $javascript->link($protocol . 'ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js') . "\n";
//echo $javascript->link($protocol . 'ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.js') . "\n";
//echo $javascript->link($protocol . 'ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js') . "\n";
//echo $javascript->link($protocol . 'ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js') . "\n";
echo $javascript->link('jquery.form') . "\n";
echo $javascript->link('jquery.hoverIntent') . "\n";
echo $javascript->link('pmgr') . "\n";
echo $scripts_for_layout . "\n";
?>
<?php if ($this->params['action'] !== 'INTERNAL_ERROR'): ?>
<script type="text/javascript"><!--
if (typeof(jQuery) == 'undefined') {
window.location.href =
"<?php echo $html->url(array('controller' => 'util',
'action' => 'INTERNAL_ERROR',
'jQuery NOT LOADED!')); ?>";
}
--></script>
<?php endif; ?>
</head>
<body>
@@ -89,5 +142,7 @@
<?php echo $cakeDebug; ?>
<?php /* pr($this); */ ?>
<?php echo implode("\n", $this->__scripts) . "\n"; ?>
</body>
</html>

View File

@@ -10,6 +10,7 @@ $customer = $lease['Customer'];
if (isset($lease['Lease']))
$lease = $lease['Lease'];
//pr(compact('unit', 'customer', 'lease', 'movein'));
/**********************************************************************
**********************************************************************
@@ -25,27 +26,72 @@ Configure::write('debug', '0');
<script type="text/javascript"><!--
var lease_charge_through;
// prepare the form when the DOM is ready
$(document).ready(function() {
var options = {
var options = {
target: '#output-debug', // target element(s) to be updated with server response
beforeSubmit: verifyRequest, // pre-submit callback
success: showResponse, // post-submit callback
// other available options:
//clearForm: true, // clear all form fields after successful submit
//resetForm: true, // reset the form after successful submit
};
// bind form using 'ajaxForm'
url: "<?php echo $html->url(array('controller' => 'transactions',
'action' => 'postInvoice', 0)); ?>"
};
// bind form using 'ajaxForm'
if ($('#invoice-form').ajaxForm != null)
$('#invoice-form').ajaxForm(options);
});
else
$('#repeat, label[for=repeat]').remove();
});
// pre-submit callback
function verifyRequest(formData, jqForm, options) {
//$("#debug").html('');
for (var i = 0; i < formData.length; ++i) {
//$("#debug").append(i + ') ' + dump(formData[i]) + '<BR>');
if (formData[i]['name'] == "data[Lease][id]" &&
!(formData[i]['value'] > 0)) {
//$("#debug").append('<P>Missing Lease ID');
alert("Must select a lease first");
return false;
}
if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') {
//$("#debug").append('<P>Bad 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;
}
// Terrible way to accomplish this...
for (var j = 0; j < 20; ++j) {
if (formData[i]['name'] == "data[Entry]["+j+"][amount]") {
var val = formData[i]['value'].replace(/\$/,'');
//$("#debug").append('<P>Bad Amount');
if (!(val > 0)) {
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');
//return false;
$('#results').html('Working <BLINK>...</BLINK>');
// here we could return false to prevent the form from being submitted;
// returning anything other than false will allow the form submit to continue
return true;
}
@@ -64,14 +110,20 @@ function showResponse(responseText, statusText) {
if (!$("#repeat").attr("checked")) {
window.location.href =
"<?php echo $html->url(array('controller' => 'leases',
<?php if (empty($movein)): ?>
"<?php echo $html->url(array('controller' => 'customers',
'action' => 'view')); ?>"
+ "/" + $("#lease-id").val();
+ "/" + $("#customer-id").val();
<?php else: ?>
"<?php echo $html->url(array('controller' => 'customers',
'action' => 'receipt')); ?>"
+ "/" + $("#customer-id").val();
<?php endif; ?>
return;
}
// get a clean slate
//resetForm();
resetForm();
}
else {
$('#results').html('<H2>Failed to save invoice!</H2>');
@@ -92,18 +144,9 @@ function resetForm(nocharge) {
function onRowSelect(grid_id, lease_id) {
// Set the item id that will be returned with the form
$("#lease-id").val(lease_id);
$("#customer-id").val($(grid_id).getCell(lease_id, 'Customer-id'));
// Get the item names from the grid
//$("#invoice-lease").html($(grid_id).getCell(lease_id, 'Lease-number'));
// REVISIT <AP>: 20090708
// This is not intended as a long term solution,
// but I need a way to enter data and then view
// the results. This link will help.
$("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
$(grid_id).getCell(lease_id, 'Lease-id').replace(/^#/,'') +
'">' +
$(grid_id).getCell(lease_id, 'Lease-number') +
'</A>');
$("#invoice-lease").html($(grid_id).getCell(lease_id, 'Lease-number'));
$("#invoice-unit").html($(grid_id).getCell(lease_id, 'Unit-name'));
$("#invoice-customer").html($(grid_id).getCell(lease_id, 'Customer-name'));
$("#invoice-rent").html($(grid_id).getCell(lease_id, 'Lease-rent'));
@@ -111,6 +154,7 @@ function onRowSelect(grid_id, lease_id) {
$("#invoice-deposit").html($(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
$(".lease-selection-invalid").hide();
@@ -136,6 +180,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) {
var id = $("#charge-entry-id").val();
addDiv('charge-entry-id', 'charge', 'charges', flash,
@@ -147,26 +263,32 @@ function addChargeSource(flash) {
echo FormatHelper::phpVarToJavascript
($this->element('form_table',
array('id' => 'Entry%{id}Form',
'class' => "item invoice ledger-entry entry",
'class' => "ChargeForm item invoice ledger-entry entry",
//'with_name_after' => ':',
'field_prefix' => 'Entry.%{id}',
'fields' => array
("account_id" => array('name' => 'Account',
'opts' =>
array('options' => $chargeAccounts,
array('class' => 'ChargeFormAccount',
'options' => $chargeAccounts,
'value' => $defaultAccount,
),
'between' => '<A HREF="#" ONCLICK="setNextRent(\'%{id}\'); return false;">Rent</A>',
),
"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>',
),
"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>',
),
"amount" => array('opts' => array('class' => 'invoice amount')),
"comment" => array('opts' => array('size' => 50)),
"amount" => array('opts' => array('class' => 'ChargeFormAmount invoice amount'),
'between' => '<A HREF="#" ONCLICK="prorate(\'%{id}\'); return false;">Prorate</A>',
),
"comment" => array('opts' => array('class' => 'ChargeFormComment', 'size' => 50)),
),
))) . "+\n";
?>
@@ -174,19 +296,8 @@ function addChargeSource(flash) {
'</FIELDSET>'
);
$("#Entry"+id+"EffectiveDate")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
$("#Entry"+id+"ThroughDate")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
datepicker("Entry"+id+"EffectiveDate");
datepicker("Entry"+id+"ThroughDate");
return id;
}
@@ -198,23 +309,27 @@ function addChargeSource(flash) {
// Re-Enable warnings
Configure::write('debug', $saved_debug_state);
echo $this->element('leases', array
('config' => array
('grid_div_id' => 'leases-list',
'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
' return false;">Select Lease</A>'),
'grid_setup' => array('hiddengrid' => isset($lease['id'])),
'grid_events' => array('onSelectRow' =>
array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
'onHeaderClick' =>
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'nolinks' => true,
'limit' => 10,
)));
if (empty($movein))
echo $this->element('leases', array
('config' => array
('grid_div_id' => 'leases-list',
'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
' return false;">Select Lease</A>'),
'grid_setup' => array('hiddengrid' => isset($lease['id'])),
'grid_events' => array('onSelectRow' =>
array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
'onHeaderClick' =>
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'include' => array('Charge-Thru'),
'exclude' => array('Closed', 'Paid-Thru'),
'action' => 'active',
'nolinks' => true,
'limit' => 10,
)));
echo ('<DIV CLASS="invoice grid-selection-text">' .
@@ -248,6 +363,11 @@ echo $form->input("Lease.id",
'type' => 'hidden',
'value' => 0));
echo $form->input("Customer.id",
array('id' => 'customer-id',
'type' => 'hidden',
'value' => 0));
/* echo '<fieldset CLASS="invoice">' . "\n"; */
/* echo ' <legend>Invoice</legend>' . "\n"; */
@@ -266,10 +386,13 @@ echo $this->element('form_table',
/* echo '</fieldset>' . "\n"; */
echo "<BR>\n";
echo $form->input('repeat', array('type' => 'checkbox',
'id' => 'repeat',
'label' => 'Enter Multiple Invoices')) . "\n";
if (empty($movein)) {
echo "<BR>\n";
echo $form->input('repeat', array('type' => 'checkbox',
'id' => 'repeat',
'label' => 'Enter Multiple Invoices')) . "\n";
}
echo $form->submit('Generate Invoice') . "\n";
?>
@@ -298,20 +421,46 @@ Configure::write('debug', '0');
$('tr td:nth-child('+col+'), tr th:nth-child('+col+')', this).remove();
};
$(document).ready(function(){
$("#TransactionStamp")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
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(){
datepicker('TransactionStamp');
<?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
$("#customer-id").val(<?php echo $customer['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);
$("#customer-id").val(<?php echo empty($movein) ? 0 : $customer['id']; ?>);
$("#invoice-lease").html("INTERNAL ERROR");
$("#invoice-unit").html("INTERNAL ERROR");
$("#invoice-customer").html("INTERNAL ERROR");
$("#invoice-rent").html("INTERNAL ERROR");
$("#invoice-late").html("INTERNAL ERROR");
$("#invoice-deposit").html("INTERNAL ERROR");
<?php endif; ?>
<?php if (empty($movein)): ?>
@@ -323,83 +472,51 @@ Configure::write('debug', '0');
var id;
resetForm(true);
$("#TransactionStamp").datepicker('disable');
$("#TransactionStamp").attr('disabled', true);
$("#TransactionStamp").val("<?php echo date('m/d/Y', $movein['time']); ?>");
$('#TransactionStamp').after
('<input type="hidden"' +
' name="data[Transaction][stamp]"' +
' value="<?php echo date('m/d/Y', $movein['time']); ?>">');
' value="' + $("#TransactionStamp").val() + '">');
$("#TransactionComment").val('Move-In Charges');
<?php if ($movein['deposit'] != 0): ?>
id = addChargeSource(false);
$('#Entry'+id+'Form').removeCol(2);
$('#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').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][effective_date]"' +
' value="<?php echo date('m/d/Y', $movein['effective_time']); ?>">');
addHidden(id, 'EffectiveDate', 'effective_date');
$('#Entry'+id+'AccountId').val(<?php echo $securityDepositAccount; ?>);
$('#Entry'+id+'AccountId').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][account_id]"' +
' value="<?php echo $securityDepositAccount; ?>">');
addHidden(id, 'AccountId', 'account_id');
$('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['deposit']); ?>");
$('#Entry'+id+'Amount').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][amount]"' +
' value="<?php echo FormatHelper::currency($movein['deposit']); ?>">');
//$('#Entry'+id+'Comment').val('Move-In Security Deposit');
addHidden(id, 'Amount', 'amount');
$('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?>
id = addChargeSource(false);
$('#Entry'+id+'Form').removeCol(2);
$('#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').after
('<input type="hidden"' +
' name="data[Entry]['+id+'][effective_date]"' +
' value="<?php echo date('m/d/Y', $movein['effective_time']); ?>">');
$('#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('Move-In Rent'
<?php if ($movein['prorated']) echo "+ ' (Prorated)'" ?>);
setNextRent(id);
addHidden(id, 'EffectiveDate', 'effective_date');
addHidden(id, 'ThroughDate', 'through_date');
addHidden(id, 'AccountId', 'account_id');
addHidden(id, 'Amount', 'amount');
$('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?>
<?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
//$("#invoice-lease").html("<?php echo '#'.$lease['number']; ?>");
$("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
"<?php echo $lease['id']; ?>" +
'">#' +
"<?php echo $lease['number']; ?>" +
'</A>');
$("#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');
<?php else: ?>
onGridState(null, 'visible');
<?php endif; ?>
<?php if ($this->params['dev']): ?>
$('#output-debug').html('Post Output');
$('#output-debug').show();
<?php endif; ?>
});
--></script>

View File

@@ -26,14 +26,53 @@ $move_type = preg_replace("/.*_/", "", $this->action);
// Reset the form
function resetForm() {
$("#customer-id").val(0);
$("#move-customer").html("INTERNAL ERROR");
$("#unit-id").val(0);
$("#lease-id").val(0);
$("#move-customer").html("INTERNAL ERROR");
$("#move-unit").html("INTERNAL ERROR");
$("#move-lease").html("INTERNAL ERROR");
datepickerNow('LeaseMoveDate', false);
}
// pre-submit callback
function verifyRequest() {
//$("#debug").html('');
<?php if ($move_type === 'out'): ?>
if (!($("#lease-id").val() > 0)) {
//$("#debug").append('<P>Missing Lease ID');
alert("Please select the lease");
return false;
}
<?php else: ?>
if (!($("#customer-id").val() > 0)) {
//$("#debug").append('<P>Missing Customer ID');
alert("Please select the customer");
return false;
}
if (!($("#unit-id").val() > 0)) {
//$("#debug").append('<P>Missing Unit ID');
alert("Please select the unit");
return false;
}
<?php endif; ?>
//$("#debug").append('OK');
//return false;
return true;
}
function onRowSelect(grid_id, item_type, item_id) {
cell_name = item_type.charAt(0).toUpperCase() + item_type.substr(1) + "-name";
cell_name = item_type.charAt(0).toUpperCase() + item_type.substr(1);
if (item_type == 'lease')
cell_name += "-number";
else
cell_name += "-name";
// Set the item id that will be returned with the form
$("#"+item_type+"-id").val(item_id);
@@ -47,6 +86,22 @@ function onRowSelect(grid_id, item_type, item_id) {
$("#LeaseDeposit").val($(grid_id).getCell(item_id, 'Unit-deposit'));
}
// If a unit was selected, update the "Create new customer" link
if (item_type == 'unit') {
$("#customer-selection-new-url").attr
('href',
"<?php echo
$html->url(array('controller' => 'customers',
'action' => 'add')); ?>"
+ '/' + $("#unit-id").val());
}
// If a lease was selected, update the customer and unit
if (item_type == 'lease') {
$("#move-unit").html($(grid_id).getCell(item_id, 'Unit-name'));
$("#move-customer").html($(grid_id).getCell(item_id, 'Customer-name'));
}
// Hide the "no customer" message and show the current customer
$("."+item_type+"-selection-invalid").hide();
$("."+item_type+"-selection-valid").show();
@@ -56,12 +111,12 @@ function onRowSelect(grid_id, item_type, item_id) {
function onGridState(grid_id, item_type, state) {
if (state == 'visible') {
$("."+item_type+"-selection-new").show();
$("."+item_type+"-selection-invalid").hide();
$("."+item_type+"-selection-valid").hide();
}
else {
//if ($(grid_id).getGridParam("selrow"))
//alert("id:" + $("#"+item_type+"-id").val());
$("."+item_type+"-selection-new").hide();
if ($("#"+item_type+"-id").val() > 0) {
$("."+item_type+"-selection-invalid").hide();
$("."+item_type+"-selection-valid").show();
@@ -78,7 +133,42 @@ function onGridState(grid_id, item_type, state) {
<?php
; // align
if ($move_type !== 'out') {
if ($move_type === 'out') {
echo $this->element('leases', array
('config' => array
('grid_div_id' => 'leases-list',
'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
' return false;">Select Lease</A>'),
'grid_setup' => array('hiddengrid' => isset($lease['id'])),
'grid_events' => array('onSelectRow' =>
array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), "lease", ids);}'),
'onHeaderClick' =>
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), "lease", gridstate)'),
),
'exclude' => array('Closed'),
'action' => 'active',
'nolinks' => true,
'limit' => 10,
)));
echo ('<DIV CLASS="move-inout grid-selection-text">' .
'<DIV CLASS="lease-selection-valid" style="display:none">' .
'Lease <SPAN id="move-lease"></SPAN>' . ' / ' .
'Unit: <SPAN id="move-unit"></SPAN>' . ' / ' .
'Customer: <SPAN id="move-customer"></SPAN>' .
'</DIV>' .
'<DIV CLASS="lease-selection-invalid" style="display:none">' .
'Please select lease' .
'</DIV>' .
'</DIV>' . "\n");
}
else {
echo $this->element('customers', array
('config' => array
('grid_div_id' => 'customers-list',
@@ -96,22 +186,27 @@ if ($move_type !== 'out') {
'nolinks' => true,
'limit' => 10,
)));
}
echo ('<DIV CLASS="move-inout grid-selection-text">' .
echo ('<DIV CLASS="move-inout grid-selection-text">' .
'<DIV CLASS="customer-selection-valid" style="display:none">' .
'Customer: <SPAN id="move-customer"></SPAN>' .
'</DIV>' .
'<DIV CLASS="customer-selection-new" style="display:none">' .
$html->link('Create a new Customer',
array('controller' => 'customers',
'action' => 'add',
(empty($unit['id']) ? null : $unit['id'])),
array('id' => 'customer-selection-new-url')) .
'</DIV>' .
'<DIV CLASS="customer-selection-invalid" style="display:none">' .
'Please select customer' .
'</DIV>' .
'<DIV CLASS="customer-selection-valid" style="display:none">' .
'Customer: <SPAN id="move-customer"></SPAN>' .
'</DIV>' .
'</DIV>' . "\n");
'<DIV CLASS="customer-selection-invalid" style="display:none">' .
'Please select customer' .
'</DIV>' .
'</DIV>' . "\n");
if ($move_type !== 'out') {
echo $this->element('units', array
('config' => array
('grid_div_id' => 'units-list',
@@ -128,43 +223,45 @@ if ($move_type !== 'out') {
),
'include' => array('Deposit'),
'exclude' => array('Balance'),
'action' => 'unoccupied',
'action' => 'vacant',
'nolinks' => true,
'limit' => 10,
)));
echo ('<DIV CLASS="move-inout grid-selection-text">' .
'<DIV CLASS="unit-selection-valid" style="display:none">' .
'Unit: <SPAN id="move-unit"></SPAN>' .
'</DIV>' .
'<DIV CLASS="unit-selection-invalid" style="display:none">' .
'Please select unit' .
'</DIV>' .
'</DIV>' . "\n");
}
echo ('<DIV CLASS="move-inout grid-selection-text">' .
'<DIV CLASS="unit-selection-valid" style="display:none">' .
'Unit: <SPAN id="move-unit"></SPAN>' .
'</DIV>' .
'<DIV CLASS="unit-selection-invalid" style="display:none">' .
'Please select unit' .
'</DIV>' .
'</DIV>' . "\n");
echo $form->create(null, array('id' => 'move-inout-form',
'onsubmit' => 'return verifyRequest();',
'url' => array('controller' => 'leases',
'action' => $move_action)));
echo $form->input("Lease.customer_id",
array('id' => 'customer-id',
'type' => 'hidden',
'value' => 0));
echo $form->input("Lease.unit_id",
array('id' => 'unit-id',
'type' => 'hidden',
'value' => 0));
if ($move_type === 'out') {
echo $form->input('Lease.id',
array('type' => 'hidden',
'value' => $lease['id'],
));
array('id' => 'lease-id',
'type' => 'hidden',
'value' => 0));
}
else {
echo $form->input("Lease.customer_id",
array('id' => 'customer-id',
'type' => 'hidden',
'value' => 0));
echo $form->input("Lease.unit_id",
array('id' => 'unit-id',
'type' => 'hidden',
'value' => 0));
}
echo $this->element('form_table',
@@ -219,15 +316,23 @@ echo $form->end('Perform Move ' . ucfirst($move_type));
<script type="text/javascript"><!--
$(document).ready(function(){
$("#LeaseMoveDate")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
datepicker('LeaseMoveDate');
resetForm();
<?php if ($move_type === 'out') { ?>
<?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
$("#move-lease").html("#<?php echo $lease['number']; ?>");
$("#move-customer").html("<?php echo $customer['name']; ?>");
$("#move-unit").html("<?php echo $unit['name']; ?>");
onGridState(null, 'lease', 'hidden');
<?php else: ?>
onGridState(null, 'lease', 'visible');
<?php endif; ?>
<?php } else { /* end (move_type === 'out') */ ?>
<?php if (isset($customer['id'])): ?>
$("#customer-id").val(<?php echo $customer['id']; ?>);
$("#move-customer").html("<?php echo $customer['name']; ?>");
@@ -243,6 +348,10 @@ echo $form->end('Perform Move ' . ucfirst($move_type));
<?php else: ?>
onGridState(null, 'unit', 'visible');
<?php endif; ?>
<?php } /* end (move_type === 'out') */ ?>
});
--></script>

View File

@@ -0,0 +1,74 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="lease overview">' . "\n";
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Overview Main Section
*/
/*
$rows = array();
$rows[] = array('', FormatHelper::currency($overview['']));
echo $this->element('table',
array('class' => 'item lease detail',
'caption' => '',
'rows' => $rows,
'column_class' => array('field', 'value')));
*/
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Supporting Elements Section
*/
echo '<div CLASS="detail supporting">' . "\n";
$headers = array('', 'Count');
$row_class = array();
$rows = array();
foreach ($overview['months'] AS $month) {
$row_class[] = 'subheader';
$rows[] = array($month['name']);
$odd = 1;
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array('Beginning of Month', $month['start']); $odd = !$odd;
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array('+ Move-Ins', $month['movein']); $odd = !$odd;
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array('- Move-Outs', $month['moveout']); $odd = !$odd;
$row_class[] = 'grand';
$rows[] = array('End of ' . $month['name'], $month['finish']);
}
echo $this->element('table',
array('class' => 'item lease-overview overview list',
'caption' => 'Leased Units By Month',
'headers' => $headers,
'rows' => $rows,
'row_class' => $row_class,
'suppress_alternate_rows' => true
));
?>
<script type="text/javascript"><!--
jQuery(document).ready(function(){
jQuery('table.overview td.subheader').attr('colSpan', 2);
});
--></script>
<?php
/* End "detail supporting" div */
echo '</div>' . "\n";
/* End page div */
echo '</div>' . "\n";

View File

@@ -18,7 +18,6 @@ if (isset($lease['Lease']))
$rows = array();
$rows[] = array('ID', $lease['id']);
$rows[] = array('Number', $lease['number']);
$rows[] = array('Lease Type', $lease_type['name']);
$rows[] = array('Unit', $html->link($unit['name'],
@@ -39,7 +38,6 @@ $rows[] = array('Notice Received', FormatHelper::date($lease['notice_received_d
$rows[] = array('Closed', FormatHelper::date($lease['close_date'], true));
$rows[] = array('Deposit', FormatHelper::currency($lease['deposit']));
$rows[] = array('Rent', FormatHelper::currency($lease['rent']));
$rows[] = array('Paid Through', FormatHelper::date($lease['paid_through'], true));
$rows[] = array('Comment', $lease['comment']);
@@ -58,6 +56,9 @@ echo '<div class="infobox">' . "\n";
$rows = array();
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
$rows[] = array('Balance Owed:', FormatHelper::currency($outstandingBalance));
$rows[] = array('Paid Through:', FormatHelper::date($lease['paid_through_date'], false));
if ($lease['delinquent'])
$rows[] = array('Delinquent:', FormatHelper::age($lease['paid_through_date'], 'delinquent'));
echo $this->element('table',
array('class' => 'summary',
'rows' => $rows,
@@ -77,6 +78,21 @@ echo '</div>' . "\n";
echo '<div CLASS="detail supporting">' . "\n";
/**********************************************************************
* Unpaid Charges
*/
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Outstanding Charges',
'limit' => 10,
'action' => 'unreconciled',
'filter' => array('StatementEntry.lease_id' => $lease['id']),
'exclude' => array('Customer', 'Unit'),
)));
/**********************************************************************
* Lease Account History
*/
@@ -85,30 +101,9 @@ echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Lease Statement',
'filter' => array('Lease.id' => $lease['id']),
'filter' => array('Lease.id' => $lease['id']),
'include' => array('Through'),
'exclude' => array('Customer', 'Lease', 'Unit'),
'sort_column' => 'Effective',
'sort_order' => 'DESC',
)));
/**********************************************************************
* Receipt History
*/
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('caption' => 'Customer Receipts',
'filter' => array('Customer.id' => $customer['id'],
'Transaction.type' => 'RECEIPT',
'Tender.id !=' => null,
//'Account.id !=' => '-AR-'
),
'exclude' => array('Account', 'Cr/Dr'),
'sort_column' => 'Date',
'sort_order' => 'DESC',
)));

View File

@@ -14,6 +14,7 @@ $ledger = $entry['Ledger'];
$account = $ledger['Account'];
$tender = $entry['Tender'];
$matching = $entry['MatchingEntry'];
$double = $entry['DoubleEntry'];
$entry = $entry['LedgerEntry'];
$rows = array();
@@ -32,7 +33,7 @@ $rows[] = array('Account', $html->link($account['name'],
array('controller' => 'accounts',
'action' => 'view',
$account['id'])));
$rows[] = array('Ledger', $html->link($ledger['name'],
$rows[] = array('Ledger', $html->link('#' . $ledger['sequence'],
array('controller' => 'ledgers',
'action' => 'view',
$ledger['id'])));
@@ -43,6 +44,10 @@ $rows[] = array('Cr/Dr', ($entry['crdr'] .
'action' => 'view',
$matching['id'])) .
')'));
$rows[] = array('Double Entry', $html->link('#'.$double['id'],
array('controller' => 'double_entries',
'action' => 'view',
$double['id'])));
$rows[] = array('Comment', $entry['comment']);
echo $this->element('table',

View File

@@ -16,8 +16,6 @@ if (isset($ledger['Ledger']))
$ledger = $ledger['Ledger'];
$rows = array();
$rows[] = array('ID', $ledger['id']);
$rows[] = array('Name', $ledger['name']);
$rows[] = array('Account', $html->link($account['name'],
array('controller' => 'accounts',
'action' => 'view',
@@ -74,6 +72,7 @@ echo $this->element('ledger_entries', array
'Amount', 'Cr/Dr', 'Balance',
empty($account['receipts']) ? 'Tender' : null),
'include' => array('Debit', 'Credit', 'Sub-Total'),
'limit' => 50,
)));

View File

@@ -0,0 +1,18 @@
<?php /* -*- mode:PHP -*- */
; // alignment
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Lock Delete
*/
echo '<div class="lock delete">' . "\n";
echo $form->create('Lock', array('action' => 'delete')) . "\n";
echo $form->input('id') . "\n";
echo $form->submit('Delete Lock') . "\n";
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
echo $form->end() . "\n";
echo '</div>' . "\n";

48
site/views/locks/edit.ctp Normal file
View File

@@ -0,0 +1,48 @@
<?php /* -*- mode:PHP -*- */
//pr($this->data);
?>
<script type="text/javascript"><!--
// Reset the form
function newKey(dig) {
$('#LockKey').val(("000000000" + Math.floor(Math.random()*(Math.pow(10,dig)))) . slice(-1*dig));
}
--></script>
<?php
; // alignment
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Lock Edit
*/
echo '<div class="lock edit">' . "\n";
echo $form->create('Lock', array('action' => 'edit')) . "\n";
echo $form->input('id') . "\n";
echo($this->element
('form_table',
array('class' => 'item lock detail',
'caption' => isset($this->data['Lock']) ? 'Edit Lock' : 'New Lock',
'fields' => array
('name' => array('label_attributes' => array('class' => 'empty'),
'after' => ("Name of the Lock Set")),
'qty' => array('label_attributes' => array('class' => 'empty'),
'after' => ("Quantity")),
'key' => array('label_attributes' => array('class' => 'empty'),
'after' => ('(<A HREF="#" ONCLICK="newKey(4); return false;">New</A>) Key Code / Combination')),
'comment' => array('label_attributes' => array('class' => 'optional empty'),
'after' => 'Optional: Comments about this lock set.'),
))) . "\n");
echo $form->submit(isset($this->data['Lock']) ? 'Update' : 'Add New Lock') . "\n";
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
echo $form->end() . "\n";
echo '</div>' . "\n";

Some files were not shown because too many files have changed in this diff Show More