Compare commits

...

64 Commits
v0.2.4 ... main

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
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
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
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
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
63 changed files with 3065 additions and 359 deletions

View File

@@ -1,25 +1,20 @@
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
RewriteEngine on
RewriteRule ^$ webroot/ [L]
# Need this prevent a 400 error without trailing /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) webroot/$1 [L]
</IfModule>
# Lets deny everyone -- its a clean slate!
order deny,allow
deny from all
# Now allow local access
# Localhost
# allow from 127.0.0
# Local subnet
# allow from 192.168.7
# 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 Digest
AuthName "Property Manager"
AuthUserFile "D:/Website/auth/pmgr.htpasswd"
AuthType Basic
AuthName "Valley Storage"
AuthUserFile "/home/perki2/valley_storage.pmgr.htpasswd"
Require valid-user
# Instead of satisfy all (too restrictive)
# This allows EITHER local domain OR authenticated user
satisfy any

View File

@@ -37,9 +37,9 @@
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');
var $sidemenu = array('areas' => array('SITE' => false, 'CONTROLLER' => false, 'ACTION' => false, 'SANDBOX' => false));
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;
@@ -52,6 +52,15 @@ class AppController extends Controller {
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']); }
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -71,6 +80,8 @@ class AppController extends 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';
@@ -189,6 +200,9 @@ class AppController extends Controller {
$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');
@@ -246,11 +260,50 @@ class AppController extends Controller {
$this->addSideMenuLink('New Deposit',
array('controller' => 'tenders', 'action' => 'deposit'), null,
'SITE', $this->op_area);
if (!empty($this->params['admin']))
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(); */
@@ -308,19 +361,19 @@ class AppController extends Controller {
$this->params['admin'] = $this->Option->enabled('admin');
$this->params['dev'] = devbox();
if ($this->params['dev'] && !$this->Option->enabled('dev'))
if ($this->dev() && !$this->Option->enabled('dev'))
$this->redirect("/");
if (!$this->params['dev'])
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 (empty($this->params['dev']))
if (!$this->dev())
$this->sideMenuEnable($area_name, $this->dev_area, false);
if (empty($this->params['admin']))
if (!$this->admin())
$this->sideMenuEnable($area_name, $this->admin_area, false);
}
@@ -389,6 +442,13 @@ class AppController extends Controller {
$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);
}
@@ -407,7 +467,8 @@ class AppController extends Controller {
App::import('Helper', 'Html');
$url = HtmlHelper::url($url, true);
if (headers_sent()) {
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
@@ -481,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);
@@ -594,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);
if ($params['debug'])
$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) {
@@ -626,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);
@@ -826,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');
}
@@ -857,14 +928,11 @@ class AppController extends Controller {
isset($params['sidx']) ? $params['sidx'] : null,
isset($params['sord']) ? $params['sord'] : null);
if ($params['debug'])
$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) {
@@ -906,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' => '%'),
@@ -961,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;
}
/**************************************************************************
**************************************************************************
@@ -1011,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) {
@@ -1107,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";
@@ -1148,7 +1279,7 @@ 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";

View File

@@ -1,5 +0,0 @@
@echo off
mysqldump --user=pmgr --password=pmgruser --opt property_manager > H:\pmgr_dev.sql
mysql --user=pmgr --password=pmgruser --database=pmgr_dev < H:\pmgr_dev.sql
del H:\pmgr_dev.sql
echo Build Complete!

View File

@@ -1,5 +0,0 @@
@echo off
mysqldump --user=pmgr --password=pmgruser --opt property_manager > H:\pmgr_sand.sql
mysql --user=pmgr --password=pmgruser --database=pmgr_sand < H:\pmgr_sand.sql
del H:\pmgr_sand.sql
echo Build Complete!

View File

@@ -5,17 +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'] = 'pmgr_dev';
$this->default['database'] = 'perki2_pmgr_dev';
if (sandbox())
$this->default['database'] = 'pmgr_sand';
$this->default['database'] = 'perki2_pmgr_sand';
}
}
?>

View File

@@ -2,6 +2,8 @@
class CustomersController extends AppController {
var $components = array('RequestHandler');
// DEBUG FUNCTION ONLY!
// Call without id to update ALL customers
function force_update($id = null) {
@@ -311,6 +313,11 @@ class CustomersController extends AppController {
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'];
$this->set(compact('customer', 'title',
@@ -445,6 +452,41 @@ class CustomersController extends AppController {
$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']));
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -176,16 +176,20 @@ 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']
);
$this->redirect(array('controller' => 'leases',
$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',
$this->data['Lease']['id']));
$lease['Customer']['id']));
}
if (isset($id)) {
@@ -330,15 +334,6 @@ 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...
@@ -351,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));
}
/**************************************************************************
**************************************************************************
@@ -440,6 +450,64 @@ class LeasesController extends AppController {
$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'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -512,13 +580,18 @@ class LeasesController extends AppController {
$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->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

@@ -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

@@ -11,6 +11,7 @@ class StatementEntriesController extends AppController {
*/
function index() { $this->gridView('All Statement Entries'); }
function unpaid() { $this->gridView('Unpaid Charges', 'unreconciled'); }
/**************************************************************************
@@ -123,18 +124,6 @@ class StatementEntriesController extends AppController {
array(array('ChargeEntry.id' => $statement_entry_id),
array('DisbursementEntry.id' => $statement_entry_id)));
if ($params['action'] === 'unreconciled') {
$query = array('conditions' => $conditions);
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
$entries = array();
foreach ($set['entries'] AS $entry)
$entries[] = $entry['StatementEntry']['id'];
$conditions[] = array('StatementEntry.id' => $entries);
$params['userdata']['balance'] = $set['summary']['balance'];
}
return $conditions;
}
@@ -158,33 +147,48 @@ 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 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']);
}
return parent::gridDataCountExecute($params, $model, $query);
}
function gridDataRecordsExecute(&$params, &$model, $query) {
/* if ($params['action'] === '???') { */
/* $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'", */
/* ); */
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'];
}
/* //pr(compact('tquery')); */
/* $total = $model->find('first', $tquery); */
/* $params['userdata']['total'] = $total[0]['applied']; */
/* $params['userdata']['balance'] = $total[0]['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'");
@@ -253,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);
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -54,6 +54,12 @@ class TransactionsController extends AppController {
$this->gridView('Deposits');
}
function gridView($title, $action = null, $element = null) {
if ($title != 'Deposits')
$this->set('include', array('Customer'));
parent::gridView($title, $action, $element);
}
/**************************************************************************
**************************************************************************
@@ -77,6 +83,7 @@ class TransactionsController extends AppController {
$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;
}
@@ -86,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) {
@@ -101,6 +109,7 @@ class TransactionsController extends AppController {
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
? 'deposit_slip' : 'view'));
$links['Customer'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -460,7 +469,7 @@ class TransactionsController extends AppController {
function deposit_slip($id) {
// Find the deposit transaction
$this->Transaction->id = $id;
$deposit = $this->Transaction->find('first', array('contain' => false));
$deposit = $this->Transaction->find('first', array('contain' => array('Account')));
// Get a summary of all forms of tender in the deposit
$tenders = $this->Transaction->find
@@ -495,8 +504,8 @@ class TransactionsController extends AppController {
foreach ($deposit['types'] AS $type)
$deposit_total += $type['total'];
if ($deposit['Transaction']['amount'] != $deposit_total)
$this->INTERNAL_ERROR("Deposit items do not add up to deposit slip total");
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,

View File

@@ -91,8 +91,8 @@ class UnitSizesController extends AppController {
$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';
$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;
}
@@ -148,6 +148,23 @@ class UnitSizesController extends AppController {
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);

View File

@@ -83,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;
}
@@ -213,7 +214,7 @@ class UnitsController extends AppController {
/**************************************************************************
**************************************************************************
**************************************************************************
* action: lock/unlock
* action: lock/unlock/lien
* - Transitions the unit into / out of the LOCKED state
*/
@@ -221,8 +222,136 @@ class UnitsController extends AppController {
$this->Unit->updateStatus($id, $status, true);
$this->redirect(array('action' => 'view', $id));
}
function lock($id) { $this->status($id, 'LOCKED'); }
function unlock($id) { $this->status($id, 'OCCUPIED'); }
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'));
}
/**************************************************************************
@@ -243,6 +372,7 @@ class UnitsController extends AppController {
array('contain' =>
array(// Models
'UnitSize',
'Lock',
'Lease' => array('Customer'),
'CurrentLease' => array('Customer')
),
@@ -268,23 +398,16 @@ class UnitsController extends AppController {
$outstanding_deposit = $this->Unit->Lease->securityDepositBalance($unit['CurrentLease']['id']);
}
// If the unit is occupied, but not locked, provide a
// mechanism to do so. This doesn't have to be restricted
// to past due customers. There are times we need to
// overlock customers in good standing, such as if their
// lock breaks, is cut, or missing for any reason.
if ($this->Unit->occupied($unit['Unit']['status']) &&
!$this->Unit->locked($unit['Unit']['status']))
$this->addSideMenuLink('Lock',
array('action' => 'Lock', $id), null,
'ACTION');
// 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');
// If the unit is locked, provide an option to unlock it,
// unless it's locked due to lien, which is not so simple.
// 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('Unlock',
array('action' => 'unlock', $id), null,
$this->addSideMenuLink('Lien',
array('action' => 'lien', $id), null,
'ACTION');
// If there is a current lease on this unit, then provide

View File

@@ -4,31 +4,6 @@ class UtilController extends AppController {
var $uses = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reset_data
* - Development function. TO BE DELETED
*/
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";
$handle = popen($script . ' 2>&1', 'r');
//echo "<P>Handle: $handle; " . gettype($handle) . "\n";
echo "<P><PRE>\n";
while (($read = fread($handle, 2096))) {
echo $read;
}
echo "</PRE>\n";
pclose($handle);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -40,21 +15,20 @@ class UtilController extends AppController {
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
$script = preg_replace('%/webroot/index.php$%',
'/build_'.$type.'box.cmd',
$_SERVER['SCRIPT_FILENAME']);
// REVISIT <AP>: 20090828
// Just use system call
$handle = popen($script . ' 2>&1', 'r');
$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 = "/";
if (empty($url) || $url == 'undefined')
$url = "/$type";
$this->redirect($url);
}

View File

@@ -91,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;
/**************************************************************************
**************************************************************************
@@ -279,6 +289,116 @@ class Customer extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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

@@ -347,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);
@@ -544,7 +546,7 @@ class Lease extends AppModel {
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 10 DAY))");
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 1 DAY))");
}
function delinquentDaysSQL($table_name = 'Lease') {
@@ -726,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']));
}
/**************************************************************************
**************************************************************************
**************************************************************************

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

@@ -294,7 +294,7 @@ class StatementEntry extends AppModel {
}
return $this->prReturn(array('entries' => $resultset,
'summary' => $this->stats(null, $query)));
'summary' => $this->stats(null, $query)));
}
@@ -338,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'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -359,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';
@@ -375,6 +438,9 @@ class StatementEntry extends AppModel {
$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
@@ -423,23 +489,16 @@ class StatementEntry extends AppModel {
"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['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");
$lquery['conditions'][] = array('StatementEntry.id' => $charge_ids);
$charges = $this->reconciledSet('CHARGE', $query, true);
} else {
$charges = $this->outstandingDebits($query, $customer_id, $lease_id);
}
// Work through all unpaid charges, applying disbursements as we go
@@ -483,14 +542,14 @@ class StatementEntry extends AppModel {
// 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($credit['receipt']) ? ' Credit' : ' Receipt'));
@@ -555,12 +614,12 @@ class StatementEntry extends AppModel {
}
// 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);

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);
@@ -209,6 +214,57 @@ class Unit extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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

@@ -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

@@ -100,7 +100,7 @@ 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

@@ -68,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',
@@ -131,14 +131,18 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
elseif ($stype === 'new') {
$fields = array
('type' => array('label_attributes' => array('class' => 'required'),
'opts' => array('options' => $obj->varstore['phoneTypes']),
'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."),
);
}
@@ -167,17 +171,23 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
elseif ($stype === 'new') {
$fields = array
('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."),
);
}
@@ -208,8 +218,10 @@ function contactMethodTypeDiv($obj, $type, $stype, $values = null) {
elseif ($stype === 'new') {
$fields = array
('email' => array('label_attributes' => array('class' => 'required empty'),
'after' => "Required: E-mail address."),
'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."),
);
}

View File

@@ -66,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',

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

@@ -130,11 +130,11 @@ function updateCharges(id) {
$("#receipt-balance").html("Calculating...");
$("#receipt-charges-caption").html("Please Wait...");
var custom = new Array();
custom['customer_id'] = id;
var filter = new Array();
filter['StatementEntry.customer_id'] = id;
var dynamic_post = new Array();
dynamic_post['custom'] = custom;
dynamic_post['filter'] = filter;
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#charge-entries-jqGrid')
@@ -157,7 +157,10 @@ function onRowSelect(grid_id, customer_id) {
$("#customer-id").val(customer_id);
// Set the customer name, so the user knows who the receipt is for
$("#receipt-customer-name").html($(grid_id).getCell(customer_id, 'Customer-name'));
$("#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();
@@ -298,7 +301,7 @@ echo $this->element('customers', array
),
'action' => 'current',
'nolinks' => true,
'limit' => 10,
'limit' => 20,
)));
echo ('<DIV CLASS="receipt grid-selection-text">' .
@@ -333,7 +336,7 @@ echo $this->element('statement_entries', array
'action' => 'unreconciled',
'exclude' => array('Customer', 'Type', 'Debit', 'Credit'),
'include' => array('Applied', 'Balance'),
'remap' => array('Applied' => 'Paid'),
'remap' => array('Received' => 'Paid'),
'limit' => 8,
),
));

View File

@@ -53,47 +53,38 @@ 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('Relationship'),
)));
/**********************************************************************
* Lease History
*/
echo $this->element('leases', array
(// Grid configuration
'config' => array
('caption' => 'Lease History',
'filter' => array('Customer.id' => $customer['Customer']['id']),
'exclude' => array('Customer'),
'sort_column' => 'Move-In',
'sort_order' => 'DESC',
)));
/**********************************************************************
* 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'),
)));
/**********************************************************************
* 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'),
)));
/**********************************************************************
* Receipt History
*/
@@ -102,6 +93,7 @@ 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,
@@ -109,9 +101,99 @@ echo $this->element('ledger_entries', array
),
'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

@@ -6,6 +6,7 @@ $cols['Relationship'] = array('index' => 'ContactsCustomer.type', 'formatter'
$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');
@@ -16,4 +17,4 @@ $grid
->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('Relationship', 'Comment')));
array_diff(array_keys($cols), array('Relationship', 'License', 'Comment')));

View File

@@ -2,11 +2,14 @@
// Define the table columns
$cols = array();
$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');
@@ -17,4 +20,4 @@ $grid
->defaultFields(array('Name'))
->searchFields(array('Name', 'Last Name', 'First Name'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Relationship', 'Comment')));
array_diff(array_keys($cols), array('Relationship', 'Past Leases', 'Comment')));

View File

@@ -113,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

@@ -50,6 +50,7 @@ if (!isset($grid_setup))
$html->css('ui.jqgrid', null, null, false);
$javascript->link('jqGrid/grid.locale-en', false);
$javascript->link('jqGrid/jquery.jqGrid.min', false);
$javascript->link('jqGrid/grid.postext', false);
$javascript->link('pmgr_jqGrid', false);
@@ -129,12 +130,12 @@ foreach ($jqGridColumns AS $header => &$col) {
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$/",

View File

@@ -4,6 +4,7 @@
$cols = array();
$cols['Lease'] = array('index' => 'Lease.number', 'formatter' => 'id');
$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');
$cols['Deposit'] = array('index' => 'Lease.deposit', 'formatter' => 'currency');

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

@@ -21,7 +21,7 @@ $cols['Debit'] = array('index' => 'charge', 'formatter' =>
$cols['Credit'] = array('index' => 'disbursement', 'formatter' => 'currency');
$cols['Amount'] = array('index' => "StatementEntry.amount", 'formatter' => 'currency');
$cols['Applied'] = array('index' => "applied", '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');
@@ -32,6 +32,22 @@ 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'));
@@ -41,8 +57,5 @@ $grid
->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('Transaction', 'Through', 'Lease',
'Amount', 'Applied', 'Balance', 'Sub-Total',
'Comment')));
->render($this, isset($config) ? $config : null, $include_columns);

View File

@@ -5,7 +5,7 @@ $cols = array();
$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');

View File

@@ -1,14 +1,21 @@
<?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
@@ -17,4 +24,4 @@ $grid
->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

@@ -3,6 +3,7 @@
// 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');
@@ -10,8 +11,8 @@ $cols['Area'] = array('index' => 'sqft', 'formatter' => 'nu
$cols['Volume'] = array('index' => 'cuft', 'formatter' => 'number');
$cols['Deposit'] = array('index' => 'UnitSize.deposit', 'formatter' => 'currency');
$cols['Rent'] = array('index' => 'UnitSize.rent', 'formatter' => 'currency');
$cols['A. Cost'] = array('index' => 'sqcost', 'formatter' => 'currency');
$cols['V. Cost'] = array('index' => 'cucost', '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');
@@ -27,7 +28,13 @@ $grid
->defaultFields(array('Size', 'Area'))
->searchFields(array('Size', 'Width', 'Depth', 'Area', 'Deposit', 'Rent'))
->render($this, isset($config) ? $config : null,
array_diff(array_keys($cols), array('Height', 'Volume',
'A. Cost', 'V. Cost',
'Occupied', 'Total', 'Occupancy', 'Vacancy',
array_diff(array_keys($cols), array('Width', 'Depth',
'Deposit',
'Height', 'Volume',
//'Per Foot',
'Per Cubic Ft',
'Occupied',
//'Total',
'Occupancy',
//'Vacancy',
'Comment')));

View File

@@ -47,6 +47,13 @@ class FormatHelper extends AppHelper {
return $currency;
}
function percent($amount, $precision = 2) {
if (!isset($amount))
return '-';
return self::$number->toPercentage($amount*100, $precision);
}
function date($date, $age = false, $class = null, $time = false) {
if (!$date) return null;

View File

@@ -215,6 +215,12 @@ 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);

View File

@@ -58,10 +58,6 @@
$protocol = 'http://';
echo $html->meta('icon') . "\n";
echo $html->css('cake.generic') . "\n";
echo $html->css('layout') . "\n";
echo $html->css('print', null, array('media' => 'print')) . "\n";
echo $html->css('sidemenu') . "\n";
$theme = 'smoothness';
$theme = 'base';
@@ -73,9 +69,13 @@
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('jquery-1.3.2.min') . "\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";

View File

@@ -111,13 +111,13 @@ function showResponse(responseText, statusText) {
if (!$("#repeat").attr("checked")) {
window.location.href =
<?php if (empty($movein)): ?>
"<?php echo $html->url(array('controller' => 'leases',
"<?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')); ?>"
+ "/" + "<?php echo $customer['id']; ?>";
+ "/" + $("#customer-id").val();
<?php endif; ?>
return;
}
@@ -144,6 +144,7 @@ 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'));
$("#invoice-lease").html($(grid_id).getCell(lease_id, 'Lease-number'));
$("#invoice-unit").html($(grid_id).getCell(lease_id, 'Unit-name'));
@@ -362,11 +363,10 @@ echo $form->input("Lease.id",
'type' => 'hidden',
'value' => 0));
if (!empty($movein))
echo $form->input("Customer.id",
array('id' => 'customer-id',
'type' => 'hidden',
'value' => $customer['id']));
echo $form->input("Customer.id",
array('id' => 'customer-id',
'type' => 'hidden',
'value' => 0));
/* echo '<fieldset CLASS="invoice">' . "\n"; */
/* echo ' <legend>Invoice</legend>' . "\n"; */
@@ -433,6 +433,8 @@ Configure::write('debug', '0');
<?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']; ?>");
@@ -450,6 +452,7 @@ Configure::write('debug', '0');
<?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");

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

@@ -78,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
*/
@@ -86,30 +101,12 @@ 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'),
)));
/**********************************************************************
* 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-'
),
'include' => array('Transaction'),
'exclude' => array('Entry', 'Account', 'Cr/Dr'),
)));
/* End "detail supporting" div */
echo '</div>' . "\n";

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";

60
site/views/locks/view.ctp Normal file
View File

@@ -0,0 +1,60 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="lock view">' . "\n";
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Lock Detail Main Section
*/
$lock = $lock['Lock'];
$rows = array();
$rows[] = array('Name', $lock['name']);
if ($lock['qty'] > 1)
$rows[] = array('Quantity', $lock['qty']);
$rows[] = array('Key', $lock['key']);
if (!empty($lock['key_last'])) {
$rows[] = array('Previous Key', $lock['key_last'] . " (Changed on " . FormatHelper::datetime($lock['key_ts']) . ")");
}
$rows[] = array('Comment', $lock['comment']);
echo $this->element('table',
array('class' => 'item lock detail',
'caption' => 'Lock Information',
'rows' => $rows,
'column_class' => array('field', 'value')));
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Supporting Elements Section
*/
echo '<div CLASS="detail supporting">' . "\n";
/**********************************************************************
* Unit Entries
*/
echo $this->element('units', array
(// Grid configuration
'config' => array
('caption' => "Units locked by " . $lock['name'],
'filter' => array('Lock.id' => $lock['id']),
'include' => array('Comment'),
'exclude' => array('Size', 'Area', 'Rent'),
)));
/* End "detail supporting" div */
echo '</div>' . "\n";
/* End page div */
echo '</div>' . "\n";

View File

@@ -0,0 +1,69 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="statement_entry overview">' . "\n";
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Overview Main Section
*/
$rows = array();
$rows[] = array("$months Month Total", FormatHelper::currency($overview['amount']) . " / (" . FormatHelper::currency($overview['amount'] / $months) . " per month)");
echo $this->element('table',
array('class' => 'item statement_entry detail',
'caption' => $reptype,
'rows' => $rows,
'column_class' => array('field', 'value')));
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Supporting Elements Section
*/
echo '<div CLASS="detail supporting">' . "\n";
$headers = array('Account', 'Amount');
$row_class = array();
$rows = array();
foreach ($overview['months'] AS $month) {
$row_class[] = 'subheader';
$rows[] = array($month['name']);
$odd = 1;
foreach ($month['subs'] AS $sub) {
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array($sub['name'], FormatHelper::currency($sub['amount']));
$odd = !$odd;
}
$row_class[] = 'grand';
$rows[] = array('Total for '.$month['name'], FormatHelper::currency($month['amount']));
}
echo $this->element('table',
array('class' => 'item statement_entry-overview overview list',
'caption' => 'Months',
'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

@@ -2,11 +2,18 @@
//style="display:inline;
echo('<H2 style="display:inline;">Deposit Slip: ' .
FormatHelper::datetime($deposit['Transaction']['stamp'])
. '</H2>' . "\n");
FormatHelper::date($deposit['Transaction']['stamp'])
. '</H2><br>' . "\n");
/* echo('(' . */
/* FormatHelper::age($deposit['Transaction']['stamp'], 60) */
/* . ')<BR>' . "\n"); */
if ($deposit['Account']['external_name'] || $deposit['Account']['external_account']) {
echo('<H2 style="display:inline;">' .
($deposit['Account']['external_name'] ? $deposit['Account']['external_name'] : '') .
($deposit['Account']['external_name'] && $deposit['Account']['external_account'] ? ': ' : '') .
($deposit['Account']['external_account'] ? 'Account #' . $deposit['Account']['external_account'] : '') .
'</H2><br>' . "\n");
}
//pr(compact('deposit'));
@@ -57,6 +64,7 @@ else {
'config' => array
(
'caption' => 'Deposited Items',
'sort_column' => 'Item',
'filter' => array('deposit_transaction_id'
=> $deposit['Transaction']['id'],
),

View File

@@ -95,16 +95,17 @@ if ($transaction['type'] === 'INVOICE' ||
* Ledger Entries
*/
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
(
'caption' => 'Ledger Entries',
'filter' => array('Transaction.id' => $transaction['id'],
'Account.id !=' => $account['id']),
'exclude' => array('Transaction'),
)));
if (0) {
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
(
'caption' => 'Ledger Entries',
'filter' => array('Transaction.id' => $transaction['id'],
'Account.id !=' => $account['id']),
'exclude' => array('Transaction'),
)));
}
/* /\********************************************************************** */
/* * Tenders Deposited */

View File

@@ -68,7 +68,7 @@ echo '<div CLASS="detail supporting">' . "\n";
/**********************************************************************
* Ledger Entries
* Unit Entries
*/
echo $this->element('units', array

132
site/views/units/lock.ctp Normal file
View File

@@ -0,0 +1,132 @@
<?php /* -*- mode:PHP -*- */
/**********************************************************************
* Because we make use of functions here,
* we need to put our top level variables somewhere
* we can access them.
*/
$this->varstore = compact('locks');
function lockDiv($obj) {
$div =
// BEGIN lock-div
'<DIV>' . "\n" .
// BEGIN lock-fieldset
'<FIELDSET CLASS="lock subset">' . "\n" .
'<LEGEND>Lock #%{id} (%{remove})</LEGEND>' . "\n" .
// BEGIN lock-n-div
'<div id="lock-%{id}-div">' . "\n" .
$obj->element
('form_table',
array('class' => "item lock entry",
'field_prefix' => 'Lock.%{id}',
'fields' => array
(
'id' => array('name' => 'Select Lock',
'opts' => array('options' => $obj->varstore['locks'])),
))) . "\n" .
// END lock-n-div
'</div>' . "\n" .
// END lock-fieldset
'</FIELDSET>' . "\n" .
// END lock-div
'</DIV>'
;
return $div;
}
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Javascript
*/
?>
<script type="text/javascript"><!--
function addLock(flash) {
addDiv('lock-entry-id', 'lock', 'locks', flash, <?php
echo FormatHelper::phpVarToJavascript
(lockDiv($this),
null,
' ');
?>
);
}
// Reset the form
function resetForm() {
$('#locks').html('');
$('#lock-entry-id').val(1);
<?php foreach ($this->data['Lock'] AS $lock): ?>
addDiv('lock-entry-id', 'lock', 'locks', false, <?php
echo FormatHelper::phpVarToJavascript
(lockDiv($this),
null,
' ');
?>
);
$('#Lock'+($('#lock-entry-id').val()-1)+'Id').val(<?php echo $lock['id'] ?>);
<?php endforeach; ?>
if ($("#lock-entry-id").val() == 1) {
addDiv('lock-entry-id', 'lock', 'locks', false, <?php
echo FormatHelper::phpVarToJavascript
(lockDiv($this),
null,
' ');
?>
);
}
}
$(document).ready(function(){
resetForm();
});
--></script>
<?php
; // alignment
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Unit-Lock Edit
*/
echo '<div class="unit-lock edit">' . "\n";
echo $form->create('Unit', array('action' => 'lock')) . "\n";
echo $form->hidden('id') . "\n";
?>
<div CLASS="dynamic-set">
<h3>Set Locks on Unit <?php echo $this->data['Unit']['name']; ?></h3>
<input type="hidden" id="lock-entry-id" value="0">
<div id="locks"></div>
<fieldset> <legend>
<a href="#" onClick="addLock(true); return false;">Add a Lock</a>
</legend> </fieldset>
</div>
<?php
; // Alignment
echo $form->submit('Update Locks') . "\n";
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
echo $form->end() . "\n";
echo '</div>' . "\n";

View File

@@ -0,0 +1,128 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="unit overview">' . "\n";
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Overview Main Section
*/
$rows = array();
$rows[] = array('Total Units', $overview['count']);
$rows[] = array('Gross Scheduled Rent', FormatHelper::currency($overview['rents']));
echo $this->element('table',
array('class' => 'item unit detail',
'caption' => 'Unit Overview',
'rows' => $rows,
'column_class' => array('field', 'value')));
/**********************************************************************
* Unit Overview Info Box
echo '<div class="infobox">' . "\n";
$rows = array();
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
$rows[] = array('Balance:', FormatHelper::currency($outstandingBalance));
echo $this->element('table',
array('class' => 'summary',
'rows' => $rows,
'column_class' => array('field', 'value'),
'suppress_alternate_rows' => true,
));
echo '</div>' . "\n";
*/
/**********************************************************************
**********************************************************************
**********************************************************************
**********************************************************************
* Supporting Elements Section
*/
echo '<div CLASS="detail supporting">' . "\n";
/*
foreach ($overview['types'] AS $type) {
$headers = array('Status', 'Count', 'Rent',
'Physical', 'Economic', 'Physical (Facility)', 'Economic (Facility)');
$row_class = array();
$rows = array();
foreach ($type['subs'] AS $sub) {
$row_class[] = array();
$rows[] = array($sub['name'], $sub['count'], FormatHelper::currency($sub['rents']),
FormatHelper::percent($sub['phys_subpct'], 1),
FormatHelper::percent($sub['econ_subpct'], 1),
FormatHelper::percent($sub['phys_totpct'], 1),
FormatHelper::percent($sub['econ_totpct'], 1));
}
$row_class[] = 'grand';
$rows[] = array('Total '.$type['name'], $type['count'], FormatHelper::currency($type['rents']),
FormatHelper::percent(1, 1),
FormatHelper::percent(1, 1),
FormatHelper::percent($type['phys_pct'], 1),
FormatHelper::percent($type['econ_pct'], 1));
echo $this->element('table',
array('class' => 'item unit-overview overview list',
'caption' => $type['name'],
'headers' => $headers,
'rows' => $rows,
'row_class' => $row_class
));
}
*/
$headers = array('Status', 'Count', 'Rent',
'Physical', 'Economic', 'Physical<BR>(Facility)', 'Economic<BR>(Facility)');
$row_class = array();
$rows = array();
foreach ($overview['types'] AS $type) {
$row_class[] = 'subheader';
$rows[] = array($type['name']);
$odd = 1;
foreach ($type['subs'] AS $sub) {
$row_class[] = array('subitem', $odd ? 'oddrow' : 'evenrow');
$rows[] = array($sub['name'], $sub['count'], FormatHelper::currency($sub['rents']),
FormatHelper::percent($sub['phys_subpct'], 1),
FormatHelper::percent($sub['econ_subpct'], 1),
FormatHelper::percent($sub['phys_totpct'], 1),
FormatHelper::percent($sub['econ_totpct'], 1));
$odd = !$odd;
}
$row_class[] = 'grand';
$rows[] = array('Total '.$type['name'], $type['count'], FormatHelper::currency($type['rents']),
FormatHelper::percent(1, 1),
FormatHelper::percent(1, 1),
FormatHelper::percent($type['phys_pct'], 1),
FormatHelper::percent($type['econ_pct'], 1));
}
echo $this->element('table',
array('class' => 'item unit-overview overview list',
'caption' => 'Unit Types',
'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', 7);
});
--></script>
<?php
/* End "detail supporting" div */
echo '</div>' . "\n";
/* End page div */
echo '</div>' . "\n";

View File

@@ -13,12 +13,25 @@ $leases = $unit['Lease'];
$current_lease = $unit['CurrentLease'];
$unit_size = $unit['UnitSize'];
if (isset($unit['Lock']))
$locks = $unit['Lock'];
if (isset($unit['Unit']))
$unit = $unit['Unit'];
$rows = array();
$rows[] = array('Name', $unit['name']);
$rows[] = array('Status', $unit['status']);
if (count($locks) > 0) {
$links = array();
foreach ($locks AS $lock) {
$links[] = $html->link($lock['name'],
array('controller' => 'locks',
'action' => 'view',
$lock['id']));
}
$rows[] = array('Locks', count($locks) . ": " . implode(", ", $links));
}
$rows[] = array('Size', $html->link($unit_size['name'],
array('controller' => 'unit_sizes',
'action' => 'view',
@@ -76,26 +89,6 @@ echo $this->element('leases', array
)));
/**********************************************************************
* Current Customer Lease Account History
*/
if (isset($current_lease['id'])) {
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
(
'caption' =>
('Current Lease Statement ('
. $current_lease['Customer']['name']
. ')'),
'filter' => array('Lease.id' => $current_lease['id']),
'include' => array('Through'),
'exclude' => array('Customer', 'Lease', 'Unit'),
)));
}
/* End "detail supporting" div */
echo '</div>' . "\n";

View File

@@ -19,6 +19,10 @@ td#pagecolumn { padding-left: 4mm; }
td#sidecolumn { width: 1% }
/* Ignore themes that want to increase font size */
.ui-widget { font-size : 1.0em }
/************************************************************
************************************************************
* Panel captions
@@ -266,6 +270,16 @@ form#collected-form input[type=button] { float : left;
/* NSF items */
.nsf-tender { text-decoration: line-through; }
/* Overview lists */
table.overview td.grand { border-top : 4px double #000; }
table.overview td.subheader { padding-top: 1em; padding-left: 0.5em; font-size: 150%; }
table.overview td:first-child.subitem { padding-left: 2em; }
table.overview td:first-child { text-align: left; }
table.overview td { text-align: right; }
table.overview td.oddrow { background : #f4f4f4; }
table.statement_entry-overview { width : 50% }
table.lease-overview { width : 50% }
/************************************************************
************************************************************

File diff suppressed because one or more lines are too long

View File

@@ -55,7 +55,7 @@
*
*/
if (!defined('CAKE_CORE_INCLUDE_PATH')) {
define('CAKE_CORE_INCLUDE_PATH', 'D:\Website\localhost\CakePHP');
define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . APP_DIR . DS . 'CakePHP');
}
/**

View File

@@ -1 +1,169 @@
(function(a){a.jgrid={defaults:{recordtext:"View {0} - {1} of {2}",emptyrecords:"No records to view",loadtext:"Loading...",pgtext:"Page {0} of {1}"},search:{caption:"Search...",Find:"Find",Reset:"Reset",odata:["equal","not equal","less","less or equal","greater","greater or equal","begins with","does not begin with","is in","is not in","ends with","does not end with","contains","does not contain"],groupOps:[{op:"AND",text:"all"},{op:"OR",text:"any"}],matchText:" match",rulesText:" rules"},edit:{addCaption:"Add Record",editCaption:"Edit Record",bSubmit:"Submit",bCancel:"Cancel",bClose:"Close",saveData:"Data has been changed! Save changes?",bYes:"Yes",bNo:"No",bExit:"Cancel",msg:{required:"Field is required",number:"Please, enter valid number",minValue:"value must be greater than or equal to ",maxValue:"value must be less than or equal to",email:"is not a valid e-mail",integer:"Please, enter valid integer value",date:"Please, enter valid date value",url:"is not a valid URL. Prefix required ('http://' or 'https://')"}},view:{caption:"View Record",bClose:"Close"},del:{caption:"Delete",msg:"Delete selected record(s)?",bSubmit:"Delete",bCancel:"Cancel"},nav:{edittext:"",edittitle:"Edit selected row",addtext:"",addtitle:"Add new row",deltext:"",deltitle:"Delete selected row",searchtext:"",searchtitle:"Find records",refreshtext:"",refreshtitle:"Reload Grid",alertcap:"Warning",alerttext:"Please, select row",viewtext:"",viewtitle:"View selected row"},col:{caption:"Show/Hide Columns",bSubmit:"Submit",bCancel:"Cancel"},errors:{errcap:"Error",nourl:"No url is set",norecords:"No records to process",model:"Length of colNames <> colModel!"},formatter:{integer:{thousandsSeparator:" ",defaultValue:"0"},number:{decimalSeparator:".",thousandsSeparator:" ",decimalPlaces:2,defaultValue:"0.00"},currency:{decimalSeparator:".",thousandsSeparator:" ",decimalPlaces:2,prefix:"",suffix:"",defaultValue:"0.00"},date:{dayNames:["Sun","Mon","Tue","Wed","Thr","Fri","Sat","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","January","February","March","April","May","June","July","August","September","October","November","December"],AmPm:["am","pm","AM","PM"],S:function(b){return b<11||b>13?["st","nd","rd","th"][Math.min((b-1)%10,3)]:"th"},srcformat:"Y-m-d",newformat:"d/m/Y",masks:{ISO8601Long:"Y-m-d H:i:s",ISO8601Short:"Y-m-d",ShortDate:"n/j/Y",LongDate:"l, F d, Y",FullDateTime:"l, F d, Y g:i:s A",MonthDay:"F d",ShortTime:"g:i A",LongTime:"g:i:s A",SortableDateTime:"Y-m-d\\TH:i:s",UniversalSortableDateTime:"Y-m-d H:i:sO",YearMonth:"F, Y"},reformatAfterEdit:false},baseLinkUrl:"",showAction:"",target:"",checkbox:{disabled:true},idName:"id"}}})(jQuery);
;(function($){
/**
* jqGrid English Translation
* Tony Tomov tony@trirand.com
* http://trirand.com/blog/
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
**/
$.jgrid = $.jgrid || {};
$.extend($.jgrid,{
defaults : {
recordtext: "View {0} - {1} of {2}",
emptyrecords: "No records to view",
loadtext: "Loading...",
pgtext : "Page {0} of {1}"
},
search : {
caption: "Search...",
Find: "Find",
Reset: "Reset",
odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
matchText: " match",
rulesText: " rules"
},
edit : {
addCaption: "Add Record",
editCaption: "Edit Record",
bSubmit: "Submit",
bCancel: "Cancel",
bClose: "Close",
saveData: "Data has been changed! Save changes?",
bYes : "Yes",
bNo : "No",
bExit : "Cancel",
msg: {
required:"Field is required",
number:"Please, enter valid number",
minValue:"value must be greater than or equal to ",
maxValue:"value must be less than or equal to",
email: "is not a valid e-mail",
integer: "Please, enter valid integer value",
date: "Please, enter valid date value",
url: "is not a valid URL. Prefix required ('http://' or 'https://')",
nodefined : " is not defined!",
novalue : " return value is required!",
customarray : "Custom function should return array!",
customfcheck : "Custom function should be present in case of custom checking!"
}
},
view : {
caption: "View Record",
bClose: "Close"
},
del : {
caption: "Delete",
msg: "Delete selected record(s)?",
bSubmit: "Delete",
bCancel: "Cancel"
},
nav : {
edittext: "",
edittitle: "Edit selected row",
addtext:"",
addtitle: "Add new row",
deltext: "",
deltitle: "Delete selected row",
searchtext: "",
searchtitle: "Find records",
refreshtext: "",
refreshtitle: "Reload Grid",
alertcap: "Warning",
alerttext: "Please, select row",
viewtext: "",
viewtitle: "View selected row"
},
col : {
caption: "Select columns",
bSubmit: "Ok",
bCancel: "Cancel"
},
errors : {
errcap : "Error",
nourl : "No url is set",
norecords: "No records to process",
model : "Length of colNames <> colModel!"
},
formatter : {
integer : {thousandsSeparator: ",", defaultValue: '0'},
number : {decimalSeparator:".", thousandsSeparator: ",", decimalPlaces: 2, defaultValue: '0.00'},
currency : {decimalSeparator:".", thousandsSeparator: ",", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
date : {
dayNames: [
"Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
],
monthNames: [
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
],
AmPm : ["am","pm","AM","PM"],
S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th';},
srcformat: 'Y-m-d',
newformat: 'n/j/Y',
masks : {
// see http://php.net/manual/en/function.date.php for PHP format used in jqGrid
// and see http://docs.jquery.com/UI/Datepicker/formatDate
// and https://github.com/jquery/globalize#dates for alternative formats used frequently
// one can find on https://github.com/jquery/globalize/tree/master/lib/cultures many
// information about date, time, numbers and currency formats used in different countries
// one should just convert the information in PHP format
ISO8601Long:"Y-m-d H:i:s",
ISO8601Short:"Y-m-d",
// short date:
// n - Numeric representation of a month, without leading zeros
// j - Day of the month without leading zeros
// Y - A full numeric representation of a year, 4 digits
// example: 3/1/2012 which means 1 March 2012
ShortDate: "n/j/Y", // in jQuery UI Datepicker: "M/d/yyyy"
// long date:
// l - A full textual representation of the day of the week
// F - A full textual representation of a month
// d - Day of the month, 2 digits with leading zeros
// Y - A full numeric representation of a year, 4 digits
LongDate: "l, F d, Y", // in jQuery UI Datepicker: "dddd, MMMM dd, yyyy"
// long date with long time:
// l - A full textual representation of the day of the week
// F - A full textual representation of a month
// d - Day of the month, 2 digits with leading zeros
// Y - A full numeric representation of a year, 4 digits
// g - 12-hour format of an hour without leading zeros
// i - Minutes with leading zeros
// s - Seconds, with leading zeros
// A - Uppercase Ante meridiem and Post meridiem (AM or PM)
FullDateTime: "l, F d, Y g:i:s A", // in jQuery UI Datepicker: "dddd, MMMM dd, yyyy h:mm:ss tt"
// month day:
// F - A full textual representation of a month
// d - Day of the month, 2 digits with leading zeros
MonthDay: "F d", // in jQuery UI Datepicker: "MMMM dd"
// short time (without seconds)
// g - 12-hour format of an hour without leading zeros
// i - Minutes with leading zeros
// A - Uppercase Ante meridiem and Post meridiem (AM or PM)
ShortTime: "g:i A", // in jQuery UI Datepicker: "h:mm tt"
// long time (with seconds)
// g - 12-hour format of an hour without leading zeros
// i - Minutes with leading zeros
// s - Seconds, with leading zeros
// A - Uppercase Ante meridiem and Post meridiem (AM or PM)
LongTime: "g:i:s A", // in jQuery UI Datepicker: "h:mm:ss tt"
SortableDateTime: "Y-m-d\\TH:i:s",
UniversalSortableDateTime: "Y-m-d H:i:sO",
// month with year
// Y - A full numeric representation of a year, 4 digits
// F - A full textual representation of a month
YearMonth: "F, Y" // in jQuery UI Datepicker: "MMMM, yyyy"
},
reformatAfterEdit : false
},
baseLinkUrl: '',
showAction: '',
target: '',
checkbox : {disabled:true},
idName : 'id'
}
});
})(jQuery);

View File

@@ -0,0 +1,64 @@
;(function($){
/**
* jqGrid extension
* Paul Tiseo ptiseo@wasteconsultants.com
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl-2.0.html
**/
$.jgrid.extend({
getPostData : function(){
var $t = this[0];
if(!$t.grid) { return; }
return $t.p.postData;
},
setPostData : function( newdata ) {
var $t = this[0];
if(!$t.grid) { return; }
// check if newdata is correct type
if ( typeof(newdata) === 'object' ) {
$t.p.postData = newdata;
}
else {
alert("Error: cannot add a non-object postData value. postData unchanged.");
}
},
appendPostData : function( newdata ) {
var $t = this[0];
if(!$t.grid) { return; }
// check if newdata is correct type
if ( typeof(newdata) === 'object' ) {
$.extend($t.p.postData, newdata);
}
else {
alert("Error: cannot append a non-object postData value. postData unchanged.");
}
},
setPostDataItem : function( key, val ) {
var $t = this[0];
if(!$t.grid) { return; }
$t.p.postData[key] = val;
},
getPostDataItem : function( key ) {
var $t = this[0];
if(!$t.grid) { return; }
return $t.p.postData[key];
},
removePostDataItem : function( key ) {
var $t = this[0];
if(!$t.grid) { return; }
delete $t.p.postData[key];
},
getUserData : function(){
var $t = this[0];
if(!$t.grid) { return; }
return $t.p.userData;
},
getUserDataItem : function( key ) {
var $t = this[0];
if(!$t.grid) { return; }
return $t.p.userData[key];
}
});
})(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
site/webroot/js/jquery-1.7.2.min.js vendored Normal file

File diff suppressed because one or more lines are too long