Compare commits
462 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ae09d160bb | |||
| 4ee9c99e30 | |||
| cb716b06b7 | |||
| 35d7656bc5 | |||
| 8818ad7a80 | |||
| 15a4528e75 | |||
| 44e4477d38 | |||
| c4cc3ea812 | |||
| 1e10fbbf38 | |||
| 53a279a6db | |||
| 8e0270cc82 | |||
| 3a95a994cf | |||
| 00c99ea60a | |||
| e09fb7d258 | |||
| 37e7212abe | |||
| 655e0c3940 | |||
| e47a2cc7aa | |||
| 0cdcb6252e | |||
| bbec6ccbb6 | |||
| 91fdef9997 | |||
| 3e2d219c8d | |||
| 57d593fc38 | |||
| 65b7137f21 | |||
| 323519ab75 | |||
| a1a9c7800b | |||
| fe17f87f7d | |||
| 6b9279f5b0 | |||
| 2882b1917c | |||
| f707448b05 | |||
| 5247139fe8 | |||
| d2a4021d6f | |||
| b759f29d91 | |||
| c0d26a8e95 | |||
| a1f30804a7 | |||
| 55b3ec947e | |||
| 876d9b3d33 | |||
| d33bf24958 | |||
| 424cb0ea4f | |||
| 63de30d392 | |||
| 07232c77d5 | |||
| 1e7557de71 | |||
| d91957faed | |||
| 56e6aa1f34 | |||
| 6e759e8589 | |||
| 9733226dfd | |||
| be2865b4d7 | |||
| adddfecada | |||
| 55c5c9e9e6 | |||
| 42677ae2f4 | |||
| ec8f540107 | |||
| 393c0dbb3f | |||
| f8413b8784 | |||
| e1217cd185 | |||
| 37d0fe7f3f | |||
| 13f97e5770 | |||
| b789ed62b7 | |||
| 2ffe04e3e4 | |||
| cdba179d79 | |||
| 5ba6438b77 | |||
| a4459ef0de | |||
| e7b71e0abb | |||
| 0c06ef6d71 | |||
| 0f42ad9b07 | |||
| c20b287c53 | |||
| ef4d8d4d30 | |||
| e7a659a690 | |||
| f6ee56501d | |||
| 826eb63da1 | |||
| 6cf6dda3f8 | |||
| 5446f6a266 | |||
| b225775a91 | |||
| a5565546d1 | |||
| f0b65dcf74 | |||
| ad1758a5dc | |||
| b3389652fd | |||
| ba62eed027 | |||
| 3dc751c863 | |||
| 68fe787209 | |||
| d4292a85a0 | |||
| f9635419dd | |||
| d8f10bfd13 | |||
| 25b7da57f3 | |||
| 29fe265daa | |||
| 769c02a5f1 | |||
| 476a179e7b | |||
| df8ebe45ef | |||
| 0bf458f243 | |||
| 18c4f5ea48 | |||
| a0f33054cb | |||
| 0f00b42d1f | |||
| 1e0b96953e | |||
| b408d86a98 | |||
| e739282d17 | |||
| c73016ecf2 | |||
| 122dfb10a0 | |||
| 9a32800170 | |||
| 04bc284a76 | |||
| 708759765f | |||
| 9dccbfeda8 | |||
| f8c60ec265 | |||
| 234999b4d2 | |||
| 0ba5007438 | |||
| 8cf8f65474 | |||
| c596dfa5f0 | |||
| 8331be454c | |||
| 8b65bc5159 | |||
| 634f0f5423 | |||
| 7aa026f4e0 | |||
| 93ebc450fe | |||
| fd856323a5 | |||
| 59e6379977 | |||
| ae5d4763f9 | |||
| c002f3f3ba | |||
| f8d4dcef94 | |||
| a7671e76fe | |||
| fc30dfa2e8 | |||
| 6ac0204baf | |||
| e303898a95 | |||
| 3313a18407 | |||
| b2ab134996 | |||
| fbb751d054 | |||
| fff6eaeeca | |||
| 1408a3dcb3 | |||
| 9507bfddc8 | |||
| aa682c9bb2 | |||
| 0c8649d1c5 | |||
| 405e20f37f | |||
| 75ff8a2a40 | |||
| 20c1284788 | |||
| 116b014332 | |||
| 8fcecb7092 | |||
| 8a36b441de | |||
| b1914f7cca | |||
| 0649329dde | |||
| 50c4ee225f | |||
| d1075a2ea2 | |||
| 6210838b22 | |||
| f5b87fa6b0 | |||
| 1d8ef76efa | |||
| 60f43efdb7 | |||
| abc5f1feff | |||
| 8b7c27b5db | |||
| 865d9ee617 | |||
| 059dbd3190 | |||
| 8a3c6ae21b | |||
| 03af4e731f | |||
| 2cd73ed9e8 | |||
| b97d071bb4 | |||
| 6a0a77c116 | |||
| d6be905c08 | |||
| 6e1c684a06 | |||
| 0c13ef5cda | |||
| 9529431be2 | |||
| d2ac8019ee | |||
| 1994512d6e | |||
| a462e9be1c | |||
| ccf0138eee | |||
| 288e4c05de | |||
| b3ca719517 | |||
| b8fd17efcf | |||
| ece7ab25ae | |||
| 860006ed38 | |||
| e067af589c | |||
| 546766d9be | |||
| 4b43433d2d | |||
| 5a1fdedad0 | |||
| 6ce9eec1a4 | |||
| d44007a358 | |||
| 8d2a544042 | |||
| d9297d89ab | |||
| 46db9c8341 | |||
| ad17023570 | |||
| 9cac8c26a9 | |||
| 90d990e0a5 | |||
| 1cb56894ce | |||
| f2f389ee45 | |||
| 5877874e82 | |||
| de5f4208eb | |||
| 6507009acc | |||
| 6e1eba03a0 | |||
| 7a31f5cbd2 | |||
| 112aa7cf59 | |||
| 372578f171 | |||
| 645458c081 | |||
| 1afaede12a | |||
| 5a4cfb0581 | |||
| 17b6986758 | |||
| 00b473ee4f | |||
| 3463ae329b | |||
| b3bceef570 | |||
| 80ddeeed6f | |||
| 43787d6434 | |||
| 72c55459ca | |||
| 977b21ed96 | |||
| e4132237b9 | |||
| c2d2a1c400 | |||
| 208aaaa504 | |||
| 21aa2c1d26 | |||
| d3959e92e5 | |||
| 60c4d950fa | |||
| d7db5a32d6 | |||
| 1932a9c316 | |||
| d09af4f475 | |||
| 437ebabfd3 | |||
| 686c58afea | |||
| 754e2327c7 | |||
| aca9d13a7d | |||
| 311d8be646 | |||
| f77281835d | |||
| 1ed98b5e39 | |||
| a2cb53a83b | |||
| dff8394e91 | |||
| 014fa0feb9 | |||
| 3aacbb94aa | |||
| 5f9b9e15cb | |||
| 1f95e835f8 | |||
| f7f9da92f3 | |||
| 3f275b127b | |||
| f4319364f2 | |||
| 54ded6173a | |||
| b36d3117a3 | |||
| 06b8ff2ae9 | |||
| 40264d3c39 | |||
| 5007890d09 | |||
| aab8a994c8 | |||
| a8c91d8b22 | |||
| d5d2d07894 | |||
| 7b3f774304 | |||
| e17cf21351 | |||
| 807dc48375 | |||
| 8491d81496 | |||
| 1c164cebc1 | |||
| db5eed24f6 | |||
| c7d7c9e7e4 | |||
| eba1267f00 | |||
| 240a16367b | |||
| cb39f6f0eb | |||
| cd07f51ff9 | |||
| cba8e16be7 | |||
| fbeed43e61 | |||
| 1d82e263ad | |||
| aa12a1efa4 | |||
| 758a5f700c | |||
| 9aa598f81f | |||
| e953f2709d | |||
| 96dd06b58a | |||
| 5fd783dc50 | |||
| 689a6dc7aa | |||
| 3e60f8d45e | |||
| 09cb297dc7 | |||
| ab0e85824b | |||
| 6def9cbb02 | |||
| c7d772be53 | |||
| e584997805 | |||
| b7e0ea8313 | |||
| bb61de60ad | |||
| bc3bcd8312 | |||
| c59f48fb84 | |||
| 6844513253 | |||
| dc850f4e8e | |||
| dea1454dcd | |||
| 6a8d21dad7 | |||
| 27503ac4f9 | |||
| f6401c92be | |||
| d77dcfca75 | |||
| a796e9e82d | |||
| 504f1e7cc0 | |||
| 591e1db81d | |||
| 1ae1b6a4f3 | |||
| 021c0626a3 | |||
| 63b2e7360b | |||
| 3ad0cc1d20 | |||
| 8d87a0698c | |||
| 44df78e69f | |||
| 707c9a87ef | |||
| 0558c35ebc | |||
| 2b2991a13a | |||
| c1aedde374 | |||
| 0b69e065ae | |||
| 1c8cc70a28 | |||
| c6f68861b3 | |||
| ce4fa4131a | |||
| 80f8bd36d5 | |||
| 7aa1100cac | |||
| b9c1a81c3b | |||
| bd0bbd768d | |||
| 20b8908a00 | |||
| ab51fd32d2 | |||
| b780ebeb3e | |||
| 117e31af69 | |||
| 28b3f35318 | |||
| 2b8a525718 | |||
| dc6e399fea | |||
| 1508f963d3 | |||
| 3270ad9bf0 | |||
| febd216810 | |||
| c8b781804a | |||
| 3e5ac64108 | |||
| 9b6830468e | |||
| 063aec6c3c | |||
| a2ae522b2d | |||
| ba218fbeeb | |||
| 2e67695154 | |||
| a136fd5313 | |||
| 1e3774cad6 | |||
| 518f7836ac | |||
| 416e230da8 | |||
| cd416ea5fa | |||
| 001b156333 | |||
| df1e0daafd | |||
| 9331b0a412 | |||
| fae90c3fa9 | |||
| a83edef049 | |||
| 4ada3d5bac | |||
| ede1053de4 | |||
| ce9142ffe2 | |||
| 0270e5ea89 | |||
| 4d2b4779d4 | |||
| fe7d7c6b0f | |||
| 435b0614b2 | |||
| 708910870c | |||
| 8b067bf676 | |||
| 388dbc0540 | |||
| ce20a44836 | |||
| 1495bb3373 | |||
| eaea52a862 | |||
| 271207629b | |||
| edca01f98c | |||
| 23f4a29fc7 | |||
| 543e2daa43 | |||
| 3911b3303f | |||
| d859cb4dee | |||
| 39071b39fb | |||
| 3dcdcb03eb | |||
| 41636f5c75 | |||
| 1890a0490e | |||
| 2b9369b823 | |||
| 4ec3db7b58 | |||
| 9f876b78de | |||
| 31c603c757 | |||
| 4d49ad6516 | |||
| 015e6b082d | |||
| cdec4c3301 | |||
| 404323c6c1 | |||
| d5dbabd94a | |||
| c90830d41a | |||
| f6ca79d1a9 | |||
| 5fab94011b | |||
| af2d5c38f3 | |||
| 6b8d05f2a0 | |||
| 336ec3b643 | |||
| b4d640f7c2 | |||
| 90a16c721e | |||
| e7b4b21328 | |||
| 3be775f9b2 | |||
| 0278c77610 | |||
| 508a8b08aa | |||
| c5bd8b4b16 | |||
| a49b86898e | |||
| 55dd94681a | |||
| 2f91dd456a | |||
| e32a5e5d4c | |||
| cca48fe86a | |||
| 839d9c1697 | |||
| c80c66d958 | |||
| a2fa71038a | |||
| d3c7011fc8 | |||
| 2c224dbc62 | |||
| 13b2283d76 | |||
| 3d89da7a61 | |||
| 99263920a3 | |||
| 8ab8d087e6 | |||
| 18b928411b | |||
| 8d062ab92e | |||
| 147c1e7097 | |||
| 760420bdc5 | |||
| fb48baf575 | |||
| d60c9721ca | |||
| f8eb45a0b9 | |||
| 4277962e3b | |||
| a60d69ba52 | |||
| 55b896a9f0 | |||
| 9f8d4fa9b2 | |||
| 4988d2717f | |||
| 136d8e845a | |||
| 190a9259d4 | |||
| 374843aeee | |||
| 52032180f3 | |||
| d14b715a88 | |||
| 2a2d11ba0f | |||
| 2e07cb87a5 | |||
| bb5b563738 | |||
| f3ffa3c079 | |||
| 30b934823c | |||
| 948ae28616 | |||
| 30c6e0b0f4 | |||
| 46e3316ce1 | |||
| e1671a9fca | |||
| e586268dee | |||
| 24730fda1b | |||
| b6ec85205d | |||
| b6a0809350 | |||
| f42ce65768 | |||
| ef180e7dda | |||
| 4aa59a40a2 | |||
| 0c43a0f884 | |||
| e65db5c759 | |||
| 59b549955e | |||
| 603a08393e | |||
| 1db887cf38 | |||
| 4ebe1db2cc | |||
| f74073a2e1 | |||
| 3f6c526718 | |||
| 903209a47e | |||
| 23a81ae924 | |||
| 9db4dd737d | |||
| 52528f1c0e | |||
| 6bf06a3a3c | |||
| 387c1ae87b | |||
| 70812e0a0c | |||
| 7fae1bcaad | |||
| c041174b0c | |||
| 2a4b8079fb | |||
| 79bcf99fc5 | |||
| 9d09afca35 | |||
| f384e051bf | |||
| 2da7b6b2c0 | |||
| 2c85566ffc | |||
| db03c73b59 | |||
| 684f02ebc5 | |||
| 4e33c58246 | |||
| 9fc5562dd8 | |||
| 3cc8e95ff4 | |||
| 15930fae30 | |||
| dbe037fee8 | |||
| 5c6189cdef | |||
| 4a86d3dda0 | |||
| ec3d986c78 | |||
| e38e99c94e | |||
| aed2c6912c | |||
| 7433e6868c | |||
| 8393403443 | |||
| ed04f81dda | |||
| 4923712238 | |||
| ffe04ed6fd | |||
| 0021eb1768 | |||
| 0ef51ee30f | |||
| 28bf192853 | |||
| df846f9963 | |||
| f4007a0269 | |||
| 6b53d8a25a | |||
| 76a06d1655 | |||
| eeb8775820 | |||
| 2d9a85ad82 | |||
| 0da1080b86 | |||
| 2665d012c2 | |||
| c5d5e2c651 | |||
| c22be388cf | |||
| 220284d20f | |||
| 4502b73b2e | |||
| 3251ba340d | |||
| c9f9d0867b |
@@ -1,25 +0,0 @@
|
|||||||
<IfModule mod_rewrite.c>
|
|
||||||
RewriteEngine on
|
|
||||||
RewriteRule ^$ webroot/ [L]
|
|
||||||
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
|
|
||||||
|
|
||||||
# Provide a mechanism for user authentication
|
|
||||||
AuthType Digest
|
|
||||||
AuthName "Property Manager"
|
|
||||||
AuthUserFile "D:/Website/auth/pmgr.htpasswd"
|
|
||||||
Require valid-user
|
|
||||||
|
|
||||||
# Instead of satisfy all (too restrictive)
|
|
||||||
# This allows EITHER local domain OR authenticated user
|
|
||||||
satisfy any
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
%~dp0\scripts\sitelink2pmgr.pl %~dp0\db\schema.sql %~dp0db\vss.mdb %*
|
||||||
|
echo Done!
|
||||||
@@ -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!
|
|
||||||
@@ -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!
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
<?php
|
|
||||||
/* SVN FILE: $Id: bootstrap.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
|
||||||
/**
|
|
||||||
* Short description for file.
|
|
||||||
*
|
|
||||||
* Long description for file
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
|
||||||
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
|
||||||
*
|
|
||||||
* Licensed under The MIT License
|
|
||||||
* Redistributions of files must retain the above copyright notice.
|
|
||||||
*
|
|
||||||
* @filesource
|
|
||||||
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
|
||||||
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
|
||||||
* @package cake
|
|
||||||
* @subpackage cake.app.config
|
|
||||||
* @since CakePHP(tm) v 0.10.8.2117
|
|
||||||
* @version $Revision: 7945 $
|
|
||||||
* @modifiedby $LastChangedBy: gwoo $
|
|
||||||
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* This file is loaded automatically by the app/webroot/index.php file after the core bootstrap.php is loaded
|
|
||||||
* This is an application wide file to load any function that is not used within a class define.
|
|
||||||
* You can also use this to include or require any files in your application.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
function _box($type) {
|
|
||||||
static $box = array('type' => null, 'test' => array());
|
|
||||||
if (!isset($box['type']) && !isset($box['test'][$type])) {
|
|
||||||
$r = Router::requestRoute();
|
|
||||||
/* if (!preg_match("/gridData/", $_SERVER['REQUEST_URI'])) { */
|
|
||||||
/* print("<PRE>Route:\n");print_r($r);print("\n</PRE>\n"); */
|
|
||||||
/* } */
|
|
||||||
$box['test'][$type] = !empty($r[3]["${type}_route"]);
|
|
||||||
if ($box['test'][$type])
|
|
||||||
$box['type'] = $type;
|
|
||||||
}
|
|
||||||
return $box['type'] == $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
function sandbox() { return _box('sand'); }
|
|
||||||
function devbox() { return _box('dev'); }
|
|
||||||
|
|
||||||
function server_request_var($var) {
|
|
||||||
if (preg_match("/^HTTP_ACCEPT|REMOTE_PORT/", $var))
|
|
||||||
return false;
|
|
||||||
return (preg_match("/^HTTP|REQUEST|REMOTE/", $var));
|
|
||||||
}
|
|
||||||
|
|
||||||
function INTERNAL_ERROR($message, $exit = true, $drop = 0) {
|
|
||||||
$O = new Object();
|
|
||||||
for ($i=0; $i<3; ++$i) {
|
|
||||||
$O->log(str_repeat("\\", 80));
|
|
||||||
$O->log(str_repeat("/", 80));
|
|
||||||
}
|
|
||||||
$O->log("INTERNAL ERROR: $message");
|
|
||||||
echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">' . "\n";
|
|
||||||
echo '<H1 style="color:#000; margin-bottom:0.2em; font-size:2em;">INTERNAL ERROR:</H1>' . "\n";
|
|
||||||
echo '<H2 style="color:#000; margin-top:0; margin-left:1.5em; font-size:1.5em">' . $message . '</H2>' . "\n";
|
|
||||||
echo '<H4 style="color:#000;">This error was not caused by anything that you did wrong.' . "\n";
|
|
||||||
echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>' . "\n";
|
|
||||||
|
|
||||||
// Print out the entire stack trace
|
|
||||||
$O->log(str_repeat("-", 30));
|
|
||||||
$O->log("Stack:");
|
|
||||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nStack Trace:\n";
|
|
||||||
echo '<OL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
|
|
||||||
$trace = array_slice(debug_backtrace(false), $drop);
|
|
||||||
for ($i = 0; $i < count($trace); ++$i) {
|
|
||||||
$bline = $trace[$i]['line'];
|
|
||||||
$bfile = $trace[$i]['file'];
|
|
||||||
$bfile = str_replace(ROOT.DS, '', $bfile);
|
|
||||||
$bfile = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $bfile);
|
|
||||||
|
|
||||||
if ($i < count($trace)-1) {
|
|
||||||
$bfunc = $trace[$i+1]['function'];
|
|
||||||
$bclas = $trace[$i+1]['class'];
|
|
||||||
} else {
|
|
||||||
$bfunc = null;
|
|
||||||
$bclas = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$O->log(" $bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")");
|
|
||||||
echo("<LI>$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")</LI>\n");
|
|
||||||
}
|
|
||||||
echo "</OL>\n";
|
|
||||||
|
|
||||||
$O->log(str_repeat("-", 30));
|
|
||||||
$O->log("HTTP Request:");
|
|
||||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nHTTP Request:\n";
|
|
||||||
echo '<UL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
|
|
||||||
foreach($_REQUEST AS $k => $v) {
|
|
||||||
$O->log(sprintf(" %-20s => %s", $k, $v));
|
|
||||||
echo("<LI>$k => $v</LI>\n");
|
|
||||||
}
|
|
||||||
echo "</UL>\n";
|
|
||||||
|
|
||||||
$O->log(str_repeat("-", 30));
|
|
||||||
$O->log("Server:");
|
|
||||||
$SRV = array_intersect_key($_SERVER, array_flip(array_filter(array_keys($_SERVER), 'server_request_var')));
|
|
||||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nServer:\n";
|
|
||||||
echo '<UL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
|
|
||||||
foreach($SRV AS $k => $v) {
|
|
||||||
if ($k == 'REQUEST_TIME')
|
|
||||||
$v = date('c', $v);
|
|
||||||
$O->log(sprintf(" %-20s => %s", $k, $v));
|
|
||||||
echo("<LI>$k => $v</LI>\n");
|
|
||||||
}
|
|
||||||
echo "</UL>\n";
|
|
||||||
|
|
||||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\n";
|
|
||||||
echo date('c') . "<BR>\n";
|
|
||||||
|
|
||||||
echo '</DIV>';
|
|
||||||
if ($exit)
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The settings below can be used to set additional paths to models, views and controllers.
|
|
||||||
* This is related to Ticket #470 (https://trac.cakephp.org/ticket/470)
|
|
||||||
*
|
|
||||||
* $modelPaths = array('full path to models', 'second full path to models', 'etc...');
|
|
||||||
* $viewPaths = array('this path to views', 'second full path to views', 'etc...');
|
|
||||||
* $controllerPaths = array('this path to controllers', 'second full path to controllers', 'etc...');
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
//EOF
|
|
||||||
?>
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<?php
|
|
||||||
/* SVN FILE: $Id: routes.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
|
||||||
/**
|
|
||||||
* Short description for file.
|
|
||||||
*
|
|
||||||
* In this file, you set up routes to your controllers and their actions.
|
|
||||||
* Routes are very important mechanism that allows you to freely connect
|
|
||||||
* different urls to chosen controllers and their actions (functions).
|
|
||||||
*
|
|
||||||
* PHP versions 4 and 5
|
|
||||||
*
|
|
||||||
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
|
||||||
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
|
||||||
*
|
|
||||||
* Licensed under The MIT License
|
|
||||||
* Redistributions of files must retain the above copyright notice.
|
|
||||||
*
|
|
||||||
* @filesource
|
|
||||||
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
|
||||||
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
|
||||||
* @package cake
|
|
||||||
* @subpackage cake.app.config
|
|
||||||
* @since CakePHP(tm) v 0.2.9
|
|
||||||
* @version $Revision: 7945 $
|
|
||||||
* @modifiedby $LastChangedBy: gwoo $
|
|
||||||
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
|
||||||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
|
||||||
*/
|
|
||||||
|
|
||||||
$default_path = array('controller' => 'maps', 'action' => 'view', '1');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Here, we are connecting '/' (base path) to our site map.
|
|
||||||
* It's hardcoded to map #1, but at some point we'll implement
|
|
||||||
* a login mechanism and the default path will be to log on instead.
|
|
||||||
*/
|
|
||||||
Router::connect('/', $default_path);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Route for sandbox functionality
|
|
||||||
*/
|
|
||||||
Router::connect('/sand',
|
|
||||||
array('sand_route' => true) + $default_path);
|
|
||||||
Router::connect('/sand/:controller/:action/*',
|
|
||||||
array('sand_route' => true, 'action' => null));
|
|
||||||
/* Unfortunately, for some reason we need an extra route to solve
|
|
||||||
* a bug with form generation. When $this->data is set by the
|
|
||||||
* controller, and a URL is generated by the FormHelper, this
|
|
||||||
* route is required to ensure the form action is correct. An
|
|
||||||
* example of a broken page is for /customers/edit/XX. It appears
|
|
||||||
* the page location uses the route above, it's only URL generation
|
|
||||||
* that seems to be broken.
|
|
||||||
*/
|
|
||||||
Router::connect('/sand/:controller/:action/:id/*',
|
|
||||||
array('sand_route' => true,'action' => null, 'id'=>null));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Route for developement functionality
|
|
||||||
*/
|
|
||||||
Router::connect('/dev',
|
|
||||||
array('dev_route' => true) + $default_path);
|
|
||||||
Router::connect('/dev/:controller/:action/*',
|
|
||||||
array('dev_route' => true, 'action' => null));
|
|
||||||
/* Unfortunately, for some reason we need an extra route to solve
|
|
||||||
* a bug with form generation. When $this->data is set by the
|
|
||||||
* controller, and a URL is generated by the FormHelper, this
|
|
||||||
* route is required to ensure the form action is correct. An
|
|
||||||
* example of a broken page is for /customers/edit/XX. It appears
|
|
||||||
* the page location uses the route above, it's only URL generation
|
|
||||||
* that seems to be broken.
|
|
||||||
*/
|
|
||||||
Router::connect('/dev/:controller/:action/:id/*',
|
|
||||||
array('dev_route' => true,'action' => null, 'id'=>null));
|
|
||||||
|
|
||||||
?>
|
|
||||||
@@ -1,584 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class CustomersController extends AppController {
|
|
||||||
|
|
||||||
var $components = array('RequestHandler');
|
|
||||||
|
|
||||||
// DEBUG FUNCTION ONLY!
|
|
||||||
// Call without id to update ALL customers
|
|
||||||
function force_update($id = null) {
|
|
||||||
$this->Customer->update($id);
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* override: addGridViewSideMenuLinks
|
|
||||||
* - Adds grid view navigation side menu links
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addGridViewSideMenuLinks() {
|
|
||||||
parent::addGridViewSideMenuLinks();
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Current',
|
|
||||||
array('controller' => 'customers', 'action' => 'current'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Past',
|
|
||||||
array('controller' => 'customers', 'action' => 'past'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('All',
|
|
||||||
array('controller' => 'customers', 'action' => 'all'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
|
|
||||||
/* $this->addSideMenuLink('New Customer', */
|
|
||||||
/* array('controller' => 'customers', 'action' => 'add'), null, */
|
|
||||||
/* 'CONTROLLER', $this->new_area); */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: index / current / past / all
|
|
||||||
* - Creates a list of customers
|
|
||||||
*/
|
|
||||||
|
|
||||||
function index() { $this->current(); }
|
|
||||||
function current() { $this->gridView('Current Tenants', 'current'); }
|
|
||||||
function past() { $this->gridView('Past Tenants'); }
|
|
||||||
function all() { $this->gridView('All Customers'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* 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(// Models
|
|
||||||
'PrimaryContact',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
|
||||||
$link = $this->gridDataCountTables($params, $model);
|
|
||||||
// StatementEntry is needed to determine customer balance
|
|
||||||
$link['link']['StatementEntry'] = array('fields' => array());
|
|
||||||
return $link;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataFields(&$params, &$model) {
|
|
||||||
$fields = parent::gridDataFields($params, $model);
|
|
||||||
return array_merge($fields,
|
|
||||||
$this->Customer->StatementEntry->chargeDisbursementFields(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataConditions(&$params, &$model) {
|
|
||||||
$conditions = parent::gridDataConditions($params, $model);
|
|
||||||
|
|
||||||
if ($params['action'] === 'current') {
|
|
||||||
$conditions[] = array('Customer.current_lease_count >' => 0);
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'past') {
|
|
||||||
$conditions[] = array('Customer.current_lease_count' => 0);
|
|
||||||
$conditions[] = array('Customer.past_lease_count >' => 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataFilterTablesConfig(&$params, &$model, $table) {
|
|
||||||
$config = parent::gridDataFilterTablesConfig($params, $model, $table);
|
|
||||||
|
|
||||||
// Special case for Contact; We need the Contact/Customer relationship
|
|
||||||
if ($table == 'Contact')
|
|
||||||
$config = array('fields' => array('ContactsCustomer.type',
|
|
||||||
'ContactsCustomer.active'),
|
|
||||||
'conditions' => array('ContactsCustomer.active' => true),
|
|
||||||
);
|
|
||||||
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
|
||||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
|
||||||
|
|
||||||
// After sorting by whatever the user wants, add these
|
|
||||||
// defaults into the sort mechanism. If we're already
|
|
||||||
// sorting by one of them, it will only be redundant,
|
|
||||||
// and should cause no harm (possible a longer query?)
|
|
||||||
$order[] = 'PrimaryContact.last_name ' . $direction;
|
|
||||||
$order[] = 'PrimaryContact.first_name ' . $direction;
|
|
||||||
$order[] = 'Customer.id ' . $direction;
|
|
||||||
|
|
||||||
return $order;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
|
||||||
$links['Customer'] = array('name');
|
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: move_in
|
|
||||||
* - Sets up the move-in page for the given customer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function move_in($id = null, $unit_id = null) {
|
|
||||||
$customer = array();
|
|
||||||
$unit = array();
|
|
||||||
|
|
||||||
if (!empty($id)) {
|
|
||||||
$this->Customer->recursive = -1;
|
|
||||||
$customer = current($this->Customer->read(null, $id));
|
|
||||||
}
|
|
||||||
if (!empty($unit_id)) {
|
|
||||||
$this->Customer->Lease->Unit->recursive = -1;
|
|
||||||
$unit = current($this->Customer->Lease->Unit->read(null, $unit_id));
|
|
||||||
}
|
|
||||||
$this->set(compact('customer', 'unit'));
|
|
||||||
|
|
||||||
$title = 'Customer Move-In';
|
|
||||||
$this->set(compact('title'));
|
|
||||||
$this->render('/leases/move');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: move_out
|
|
||||||
* - prepare to move a customer out of one of their units
|
|
||||||
*/
|
|
||||||
|
|
||||||
function move_out($id) {
|
|
||||||
|
|
||||||
$customer = $this->Customer->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'Lease' =>
|
|
||||||
array('conditions' => array('Lease.moveout_date' => null),
|
|
||||||
// Models
|
|
||||||
'Unit' =>
|
|
||||||
array('order' => array('sort_order'),
|
|
||||||
'fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' => array('Customer.id' => $id),
|
|
||||||
));
|
|
||||||
$this->set('customer', $lease['Customer']);
|
|
||||||
$this->set('unit', array());
|
|
||||||
|
|
||||||
$redirect = array('controller' => 'customers',
|
|
||||||
'action' => 'view',
|
|
||||||
$id);
|
|
||||||
|
|
||||||
$title = $customer['Customer']['name'] . ': Prepare Move-Out';
|
|
||||||
$this->set(compact('title', 'customer', 'redirect'));
|
|
||||||
$this->render('/leases/move');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: view
|
|
||||||
* - Displays information about a specific customer
|
|
||||||
*/
|
|
||||||
|
|
||||||
function view($id = null) {
|
|
||||||
if (!$id) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get details on this customer, its contacts and leases
|
|
||||||
$customer = $this->Customer->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'Contact' =>
|
|
||||||
array('order' => array('Contact.display_name'),
|
|
||||||
// Models
|
|
||||||
'ContactPhone',
|
|
||||||
'ContactEmail',
|
|
||||||
'ContactAddress',
|
|
||||||
),
|
|
||||||
'Lease' =>
|
|
||||||
array('Unit' =>
|
|
||||||
array('order' => array('sort_order'),
|
|
||||||
'fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' => array('Customer.id' => $id),
|
|
||||||
));
|
|
||||||
//pr($customer);
|
|
||||||
|
|
||||||
// Determine how long this customer has been with us.
|
|
||||||
$leaseinfo = $this->Customer->find
|
|
||||||
('first', array
|
|
||||||
('link' => array('Lease' => array('fields' => array())),
|
|
||||||
'fields' => array('MIN(Lease.movein_date) AS since',
|
|
||||||
'IF(Customer.current_lease_count = 0, MAX(Lease.moveout_date), NULL) AS until'),
|
|
||||||
'conditions' => array('Customer.id' => $id),
|
|
||||||
'group' => 'Customer.id',
|
|
||||||
));
|
|
||||||
$this->set($leaseinfo[0]);
|
|
||||||
|
|
||||||
// Figure out the outstanding balances for this customer
|
|
||||||
//$this->set('stats', $this->Customer->stats($id));
|
|
||||||
$outstanding_balance = $this->Customer->balance($id);
|
|
||||||
$outstanding_deposit = $this->Customer->securityDepositBalance($id);
|
|
||||||
|
|
||||||
// Figure out if this customer has any non-closed leases
|
|
||||||
$show_moveout = false; $moveout_lease_id = null;
|
|
||||||
$show_payment = false; $payment_lease_id = null;
|
|
||||||
foreach ($customer['Lease'] AS $lease) {
|
|
||||||
if (!isset($lease['close_date'])) {
|
|
||||||
if ($show_payment)
|
|
||||||
$payment_lease_id = null;
|
|
||||||
else
|
|
||||||
$payment_lease_id = $lease['id'];
|
|
||||||
$show_payment = true;
|
|
||||||
}
|
|
||||||
if (!isset($lease['moveout_date'])) {
|
|
||||||
if ($show_moveout)
|
|
||||||
$moveout_lease_id = null;
|
|
||||||
else
|
|
||||||
$moveout_lease_id = $lease['id'];
|
|
||||||
$show_moveout = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up dynamic menu items
|
|
||||||
|
|
||||||
if ($show_payment || $outstanding_balance > 0)
|
|
||||||
$this->addSideMenuLink('New Receipt',
|
|
||||||
array('action' => 'receipt', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
if ($show_payment) {
|
|
||||||
/* $ids = $this->Customer->leaseIds($id, true); */
|
|
||||||
/* if (count($ids) == 1) */
|
|
||||||
/* $lease_id = $ids[0]; */
|
|
||||||
/* else */
|
|
||||||
/* $lease_id = null; */
|
|
||||||
|
|
||||||
$this->addSideMenuLink('New Invoice',
|
|
||||||
array('controller' => 'leases',
|
|
||||||
'action' => 'invoice',
|
|
||||||
$payment_lease_id), null,
|
|
||||||
'ACTION');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Move-In',
|
|
||||||
array('action' => 'move_in', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
if ($show_moveout) {
|
|
||||||
$this->addSideMenuLink('Move-Out',
|
|
||||||
array('controller' => 'leases',
|
|
||||||
'action' => 'move_out',
|
|
||||||
$moveout_lease_id), null,
|
|
||||||
'ACTION');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$show_moveout && $outstanding_balance > 0)
|
|
||||||
$this->addSideMenuLink('Write-Off',
|
|
||||||
array('action' => 'bad_debt', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
if ($outstanding_balance < 0)
|
|
||||||
$this->addSideMenuLink('Issue Refund',
|
|
||||||
array('action' => 'refund', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Edit',
|
|
||||||
array('action' => 'edit', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
if ($this->admin())
|
|
||||||
$this->addSideMenuLink('Merge',
|
|
||||||
array('action' => 'merge', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = 'Customer: ' . $customer['Customer']['name'];
|
|
||||||
$this->set(compact('customer', 'title',
|
|
||||||
'outstanding_balance',
|
|
||||||
'outstanding_deposit'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* 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['Customer']['id']))
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we have at least one contact
|
|
||||||
if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) {
|
|
||||||
$this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true);
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure there is a primary contact
|
|
||||||
if (!isset($this->data['Customer']['primary_contact_entry'])) {
|
|
||||||
$this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true);
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through each customer and strip the bogus ID if new
|
|
||||||
foreach ($this->data['Contact'] AS &$contact) {
|
|
||||||
if (isset($contact['source']) && $contact['source'] === 'new')
|
|
||||||
unset($contact['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the customer and all associated data
|
|
||||||
if (!$this->Customer->saveCustomer($this->data['Customer']['id'],
|
|
||||||
$this->data,
|
|
||||||
$this->data['Customer']['primary_contact_entry'])) {
|
|
||||||
$this->Session->setFlash("CUSTOMER SAVE FAILED", true);
|
|
||||||
pr("CUSTOMER SAVE FAILED");
|
|
||||||
}
|
|
||||||
|
|
||||||
// If existing customer, then view it.
|
|
||||||
if ($this->data['Customer']['id'])
|
|
||||||
$this->redirect(array('action'=>'view', $this->Customer->id));
|
|
||||||
|
|
||||||
// Since this is a new customer, go to the move in screen.
|
|
||||||
// First set the move-in unit id, if there is one, ...
|
|
||||||
if (empty($this->data['movein']['Unit']['id']))
|
|
||||||
$unit_id = null;
|
|
||||||
else
|
|
||||||
$unit_id = $this->data['movein']['Unit']['id'];
|
|
||||||
|
|
||||||
// ... then redirect
|
|
||||||
$this->redirect(array('action'=>'move_in',
|
|
||||||
$this->Customer->id,
|
|
||||||
$unit_id,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($id) {
|
|
||||||
// REVISIT <AP>: 20090816
|
|
||||||
// This should never need to be done by a controller.
|
|
||||||
// However, until things stabilize, this gives the
|
|
||||||
// user a way to update any cached items on the
|
|
||||||
// customer, by just clicking Edit then Cancel.
|
|
||||||
$this->Customer->update($id);
|
|
||||||
|
|
||||||
// Get details on this customer, its contacts and leases
|
|
||||||
$customer = $this->Customer->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'Contact' =>
|
|
||||||
array('order' => array('Contact.display_name'),
|
|
||||||
// Models
|
|
||||||
'ContactPhone',
|
|
||||||
'ContactEmail',
|
|
||||||
'ContactAddress',
|
|
||||||
),
|
|
||||||
'Lease' =>
|
|
||||||
array('Unit' =>
|
|
||||||
array('order' => array('sort_order'),
|
|
||||||
'fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' => array('Customer.id' => $id),
|
|
||||||
));
|
|
||||||
|
|
||||||
$this->data = $customer;
|
|
||||||
$title = 'Customer: ' . $this->data['Customer']['name'] . " : Edit";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$title = "Enter New Customer";
|
|
||||||
$this->data = array('Contact' => array(), 'PrimaryContact' => null);
|
|
||||||
}
|
|
||||||
|
|
||||||
$contact_types = array_flip($this->Customer->ContactsCustomer->getEnumValues('type'));
|
|
||||||
unset($contact_types[0]);
|
|
||||||
$contact_types = array_combine($contact_types, $contact_types);
|
|
||||||
$this->set(compact('contact_types'));
|
|
||||||
|
|
||||||
$contacts = $this->Customer->Contact->contactList();
|
|
||||||
$this->set(compact('contacts'));
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
//pr($this->data);
|
|
||||||
$this->set(compact('title'));
|
|
||||||
$this->render('edit');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: add
|
|
||||||
* - Add a new customer
|
|
||||||
*/
|
|
||||||
|
|
||||||
function add($unit_id = null) {
|
|
||||||
$this->set('movein', array('Unit' => array('id' => $unit_id)));
|
|
||||||
$this->edit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: merge
|
|
||||||
* - Merges two customers
|
|
||||||
*/
|
|
||||||
|
|
||||||
function merge($id = null) {
|
|
||||||
if ($id) {
|
|
||||||
$this->Customer->recursive = -1;
|
|
||||||
$customer = $this->Customer->read(null, $id);
|
|
||||||
$customer = $customer['Customer'];
|
|
||||||
if (empty($customer))
|
|
||||||
$this->INTERNAL_ERROR("Customer $id does not exist");
|
|
||||||
$this->set('dst_customer', $customer);
|
|
||||||
$this->set('dst_name', $customer['name']);
|
|
||||||
$this->set('dst_id', $id);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->INTERNAL_ERROR("Merge called with invalid customer");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergeFinal() {
|
|
||||||
if (!$this->RequestHandler->isPost()) {
|
|
||||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$post = $this->params['form'];
|
|
||||||
$this->Customer->merge($post['dst-id'], $post['src-id'],
|
|
||||||
unserialize($post['contact-ids']));
|
|
||||||
$this->redirect(array('action'=>'view', $post['dst-id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: receipt
|
|
||||||
* - Sets up the receipt entry page for the given customer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function receipt($id = null) {
|
|
||||||
if (isset($id)) {
|
|
||||||
$this->Customer->recursive = -1;
|
|
||||||
$customer = $this->Customer->read(null, $id);
|
|
||||||
$customer = $customer['Customer'];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$customer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$TT = new TenderType();
|
|
||||||
$payment_types = $TT->paymentTypes();
|
|
||||||
$default_type = $TT->defaultPaymentType();
|
|
||||||
$this->set(compact('payment_types', 'default_type'));
|
|
||||||
|
|
||||||
$title = ($customer['name'] . ': Receipt Entry');
|
|
||||||
$this->set(compact('customer', 'title'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: refund
|
|
||||||
* - Refunds customer charges
|
|
||||||
*/
|
|
||||||
|
|
||||||
function refund($id) {
|
|
||||||
$customer = $this->Customer->find
|
|
||||||
('first', array
|
|
||||||
('contain' => false,
|
|
||||||
'conditions' => array(array('Customer.id' => $id),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
if (empty($customer)) {
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the customer balance, bailing if the customer owes money
|
|
||||||
$balance = $this->Customer->balance($id);
|
|
||||||
if ($balance >= 0) {
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// The refund will be for a positive amount
|
|
||||||
$balance *= -1;
|
|
||||||
|
|
||||||
// Get the accounts capable of paying the refund
|
|
||||||
$refundAccounts = $this->Customer->StatementEntry->Account->refundAccounts();
|
|
||||||
$defaultAccount = current($refundAccounts);
|
|
||||||
$this->set(compact('refundAccounts', 'defaultAccount'));
|
|
||||||
|
|
||||||
// Prepare to render
|
|
||||||
$title = ($customer['Customer']['name'] . ': Refund');
|
|
||||||
$this->set(compact('title', 'customer', 'balance'));
|
|
||||||
$this->render('/transactions/refund');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: bad_debt
|
|
||||||
* - Sets up the write-off entry page, so that the
|
|
||||||
* user can write off remaining charges of a customer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function bad_debt($id) {
|
|
||||||
$this->Customer->id = $id;
|
|
||||||
$customer = $this->Customer->find
|
|
||||||
('first', array
|
|
||||||
('contain' => false,
|
|
||||||
));
|
|
||||||
|
|
||||||
// Make sure we have a valid customer to write off
|
|
||||||
if (empty($customer))
|
|
||||||
$this->redirect(array('action' => 'index'));
|
|
||||||
|
|
||||||
// Get the customer balance
|
|
||||||
$balance = $this->Customer->balance($id);
|
|
||||||
|
|
||||||
// Prepare to render
|
|
||||||
$title = ($customer['Customer']['name'] . ': Write Off Bad Debt');
|
|
||||||
$this->set(compact('title', 'customer', 'balance'));
|
|
||||||
$this->render('/transactions/bad_debt');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class DoubleEntriesController extends AppController {
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: view
|
|
||||||
* - Displays information about a specific entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
function view($id = null) {
|
|
||||||
if (!$id) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Entry and related fields
|
|
||||||
$entry = $this->DoubleEntry->find
|
|
||||||
('first',
|
|
||||||
array('contain' => array('DebitEntry', 'CreditEntry'),
|
|
||||||
'conditions' => array('DoubleEntry.id' => $id),
|
|
||||||
));
|
|
||||||
|
|
||||||
$entry += $this->DoubleEntry->DebitEntry->Transaction->find
|
|
||||||
('first',
|
|
||||||
array('contain' => false,
|
|
||||||
'conditions' => array('id' => $entry['DebitEntry']['transaction_id']),
|
|
||||||
));
|
|
||||||
|
|
||||||
$entry += $this->DoubleEntry->DebitEntry->find
|
|
||||||
('first',
|
|
||||||
array('contain' => array('Ledger' => array('Account')),
|
|
||||||
'conditions' => array('DebitEntry.id' => $entry['DebitEntry']['id']),
|
|
||||||
));
|
|
||||||
$entry['Ledger']['link'] =
|
|
||||||
$entry['Ledger']['Account']['level'] >=
|
|
||||||
$this->Permission->level('controller.accounts');
|
|
||||||
$entry['DebitLedger'] = $entry['Ledger'];
|
|
||||||
unset($entry['Ledger']);
|
|
||||||
|
|
||||||
$entry += $this->DoubleEntry->CreditEntry->find
|
|
||||||
('first',
|
|
||||||
array('contain' => array('Ledger' => array('Account')),
|
|
||||||
'conditions' => array('CreditEntry.id' => $entry['CreditEntry']['id']),
|
|
||||||
));
|
|
||||||
$entry['Ledger']['link'] =
|
|
||||||
$entry['Ledger']['Account']['level'] >=
|
|
||||||
$this->Permission->level('controller.accounts');
|
|
||||||
$entry['CreditLedger'] = $entry['Ledger'];
|
|
||||||
unset($entry['Ledger']);
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}";
|
|
||||||
$this->set(compact('entry', 'title'));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,590 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class LeasesController extends AppController {
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* override: addGridViewSideMenuLinks
|
|
||||||
* - Adds grid view navigation side menu links
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addGridViewSideMenuLinks() {
|
|
||||||
parent::addGridViewSideMenuLinks();
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Active',
|
|
||||||
array('controller' => 'leases', 'action' => 'active'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Closed',
|
|
||||||
array('controller' => 'leases', 'action' => 'closed'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Delinquent',
|
|
||||||
array('controller' => 'leases', 'action' => 'delinquent'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('All',
|
|
||||||
array('controller' => 'leases', 'action' => 'all'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: index / active / closed / all
|
|
||||||
* - Generate a listing of leases
|
|
||||||
*/
|
|
||||||
|
|
||||||
function index() { $this->active(); }
|
|
||||||
function active() { $this->gridView('Active Leases', 'active'); }
|
|
||||||
function delinquent() { $this->gridView('Delinquent Leases'); }
|
|
||||||
function closed() { $this->gridView('Closed Leases'); }
|
|
||||||
function all() { $this->gridView('All Leases'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* virtuals: gridData
|
|
||||||
* - With the application controller handling the gridData action,
|
|
||||||
* these virtual functions ensure that the correct data is passed
|
|
||||||
* to jqGrid.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function gridDataSetup(&$params) {
|
|
||||||
parent::gridDataSetup($params);
|
|
||||||
if (!isset($params['action']))
|
|
||||||
$params['action'] = 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataCountTables(&$params, &$model) {
|
|
||||||
return array
|
|
||||||
('link' => array('Unit' => array('fields' => array('id', 'name')),
|
|
||||||
'Customer' => array('fields' => array('id', 'name'))));
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
|
||||||
$link = $this->gridDataCountTables($params, $model);
|
|
||||||
$link['link']['StatementEntry'] = array('fields' => array());
|
|
||||||
return $link;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataFields(&$params, &$model) {
|
|
||||||
$fields = parent::gridDataFields($params, $model);
|
|
||||||
$fields[] = ("IF(" . $this->Lease->conditionDelinquent() . "," .
|
|
||||||
" 'DELINQUENT', 'CURRENT') AS 'status'");
|
|
||||||
return array_merge($fields,
|
|
||||||
$this->Lease->StatementEntry->chargeDisbursementFields(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataConditions(&$params, &$model) {
|
|
||||||
$conditions = parent::gridDataConditions($params, $model);
|
|
||||||
|
|
||||||
if ($params['action'] === 'active') {
|
|
||||||
$conditions[] = 'Lease.close_date IS NULL';
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'delinquent') {
|
|
||||||
$conditions[] = $this->Lease->conditionDelinquent();
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'closed') {
|
|
||||||
$conditions[] = 'Lease.close_date IS NOT NULL';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($customer_id))
|
|
||||||
$conditions[] = array('Lease.customer_id' => $customer_id);
|
|
||||||
|
|
||||||
return $conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
|
||||||
// Do not sort by number, which is type varchar and
|
|
||||||
// sorts on an ascii basis. Sort by ID instead.
|
|
||||||
if ($index === 'Lease.number')
|
|
||||||
$index = 'Lease.id';
|
|
||||||
|
|
||||||
// Instead of sorting by name, sort by defined order
|
|
||||||
if ($index === 'Unit.name')
|
|
||||||
$index = 'Unit.sort_order';
|
|
||||||
|
|
||||||
$order = array();
|
|
||||||
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
|
|
||||||
|
|
||||||
// If sorting by anything other than id/number
|
|
||||||
// add sorting by id as a secondary condition.
|
|
||||||
if ($index !== 'Lease.id' && $index !== 'Lease.number')
|
|
||||||
$order[] = parent::gridDataOrder($params, $model,
|
|
||||||
'Lease.id', $direction);
|
|
||||||
|
|
||||||
return $order;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* function gridDataPostProcess(&$params, &$model, &$records) { */
|
|
||||||
/* foreach ($records AS &$record) { */
|
|
||||||
/* $record['Lease']['through_date'] */
|
|
||||||
/* = $this->Lease->rentChargeThrough($record['Lease']['id']); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* parent::gridDataPostProcess($params, $model, $records); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
|
||||||
$links['Lease'] = array('number');
|
|
||||||
$links['Unit'] = array('name');
|
|
||||||
$links['Customer'] = array('name');
|
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: move_in
|
|
||||||
* - execute a move in on a new lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function move_in() {
|
|
||||||
if (!$this->data)
|
|
||||||
die("Should have some data");
|
|
||||||
|
|
||||||
// Handle the move in based on the data given
|
|
||||||
//pr(array('Move-in data', $this->data));
|
|
||||||
foreach (array('deposit', 'rent') AS $currency) {
|
|
||||||
$this->data['Lease'][$currency]
|
|
||||||
= str_replace('$', '', $this->data['Lease'][$currency]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$lid = $this->Lease->moveIn($this->data['Lease']['customer_id'],
|
|
||||||
$this->data['Lease']['unit_id'],
|
|
||||||
$this->data['Lease']['deposit'],
|
|
||||||
$this->data['Lease']['rent'],
|
|
||||||
$this->data['Lease']['movein_date'],
|
|
||||||
$this->data['Lease']['comment']
|
|
||||||
);
|
|
||||||
|
|
||||||
// Since this is a new lease, go to the invoice
|
|
||||||
// screen so we can start assessing charges.
|
|
||||||
$this->redirect(array('action'=>'invoice', $lid, 'move-in'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: move_out
|
|
||||||
* - prepare or execute a move out on a specific lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function move_out($id = null) {
|
|
||||||
if ($this->data) {
|
|
||||||
// Handle the move out based on the data given
|
|
||||||
$this->Lease->moveOut($this->data['Lease']['id'],
|
|
||||||
'VACANT',
|
|
||||||
$this->data['Lease']['moveout_date']
|
|
||||||
);
|
|
||||||
|
|
||||||
$lease = $this->Lease->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array('Customer.id'),
|
|
||||||
'conditions' => array(array('Lease.id' => $this->data['Lease']['id'])),
|
|
||||||
));
|
|
||||||
|
|
||||||
$this->redirect(array('controller' => 'customers',
|
|
||||||
'action' => 'view',
|
|
||||||
$lease['Customer']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($id)) {
|
|
||||||
$lease = $this->Lease->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'Unit' =>
|
|
||||||
array('order' => array('sort_order'),
|
|
||||||
'fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
|
|
||||||
'Customer' =>
|
|
||||||
array('fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' => array(array('Lease.id' => $id),
|
|
||||||
array('Lease.close_date' => null),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
$this->set('customer', $lease['Customer']);
|
|
||||||
$this->set('unit', $lease['Unit']);
|
|
||||||
$this->set('lease', $lease['Lease']);
|
|
||||||
|
|
||||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
|
||||||
$lease['Unit']['name'] . ': ' .
|
|
||||||
$lease['Customer']['name'] . ': Move-Out');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$title = 'Move-Out';
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->set(compact('title'));
|
|
||||||
$this->render('/leases/move');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* /\************************************************************************** */
|
|
||||||
/* ************************************************************************** */
|
|
||||||
/* ************************************************************************** */
|
|
||||||
/* * action: promote_credit */
|
|
||||||
/* * - Moves any lease credit up to the customer level, so that */
|
|
||||||
/* * it may be used for charges other than those on this lease. */
|
|
||||||
/* *\/ */
|
|
||||||
|
|
||||||
/* function promote_surplus($id) { */
|
|
||||||
/* $this->Lease->promoteSurplus($id); */
|
|
||||||
/* $this->redirect(array('controller' => 'leases', */
|
|
||||||
/* 'action' => 'view', */
|
|
||||||
/* $id)); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: refund
|
|
||||||
* - Provides lease customer with a refund
|
|
||||||
*/
|
|
||||||
|
|
||||||
function refund($id) {
|
|
||||||
$lease = $this->Lease->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'Unit' => array('fields' => array('id', 'name')),
|
|
||||||
'Customer' => array('fields' => array('id', 'name')),
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' => array(array('Lease.id' => $id),
|
|
||||||
// Make sure lease is not closed...
|
|
||||||
array('Lease.close_date' => null),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
if (empty($lease)) {
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the lease balance, bailing if the customer owes money
|
|
||||||
$balance = $this->Lease->balance($id);
|
|
||||||
if ($balance >= 0) {
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// The refund will be for a positive amount
|
|
||||||
$balance *= -1;
|
|
||||||
|
|
||||||
// Get the accounts capable of paying the refund
|
|
||||||
$refundAccounts = $this->Lease->StatementEntry->Account->refundAccounts();
|
|
||||||
$defaultAccount = current($refundAccounts);
|
|
||||||
$this->set(compact('refundAccounts', 'defaultAccount'));
|
|
||||||
|
|
||||||
// Prepare to render
|
|
||||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
|
||||||
$lease['Unit']['name'] . ': ' .
|
|
||||||
$lease['Customer']['name'] . ': Refund');
|
|
||||||
$this->set(compact('title', 'lease', 'balance'));
|
|
||||||
$this->render('/transactions/refund');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: bad_debt
|
|
||||||
* - Sets up the write-off entry page, so that the
|
|
||||||
* user can write off remaining charges on a lease.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function bad_debt($id) {
|
|
||||||
$this->Lease->id = $id;
|
|
||||||
$lease = $this->Lease->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'Unit' => array('fields' => array('id', 'name')),
|
|
||||||
'Customer' => array('fields' => array('id', 'name')),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Make sure we have a valid lease to write off
|
|
||||||
if (empty($lease))
|
|
||||||
$this->redirect(array('action' => 'view', $id));
|
|
||||||
|
|
||||||
// Get the lease balance
|
|
||||||
$balance = $this->Lease->balance($id);
|
|
||||||
|
|
||||||
// Prepare to render
|
|
||||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
|
||||||
$lease['Unit']['name'] . ': ' .
|
|
||||||
$lease['Customer']['name'] . ': Write Off Bad Debt');
|
|
||||||
$this->set(compact('title', 'lease', 'balance'));
|
|
||||||
$this->render('/transactions/bad_debt');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: close
|
|
||||||
* - Closes a lease to any further action
|
|
||||||
*/
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090809
|
|
||||||
// While cleaning up the sitelink data, then delete reldep()
|
|
||||||
function reldep($id) {
|
|
||||||
$this->Lease->id = $id;
|
|
||||||
$stamp = $this->Lease->field('moveout_date');
|
|
||||||
$this->Lease->releaseSecurityDeposits($id, $stamp);
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
function close($id) {
|
|
||||||
// REVISIT <AP>: 20090708
|
|
||||||
// We should probably seek confirmation first...
|
|
||||||
if (!$this->Lease->closeable($id)) {
|
|
||||||
$this->INTERNAL_ERROR("This lease is not ready to close");
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->Lease->close($id);
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: invoice
|
|
||||||
* - Sets up the invoice entry page for the given customer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function invoice($id = null, $type = null) {
|
|
||||||
|
|
||||||
$lease = $this->Lease->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'Unit' =>
|
|
||||||
array('order' => array('sort_order'),
|
|
||||||
'fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
|
|
||||||
'Customer' =>
|
|
||||||
array('fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' => array(array('Lease.id' => $id),
|
|
||||||
array('Lease.close_date' => null),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
$A = new Account();
|
|
||||||
$charge_accounts = $A->invoiceAccounts();
|
|
||||||
$default_account = $A->rentAccountID();
|
|
||||||
$rent_account = $A->rentAccountID();
|
|
||||||
$security_deposit_account = $A->securityDepositAccountID();
|
|
||||||
$this->set(compact('charge_accounts', 'default_account',
|
|
||||||
'rent_account', 'security_deposit_account'));
|
|
||||||
|
|
||||||
// REVISIT <AP> 20090705:
|
|
||||||
// Of course, the late charge should come from the late_schedule
|
|
||||||
$default_late = 10;
|
|
||||||
$this->set(compact('default_late'));
|
|
||||||
|
|
||||||
if ($type === 'move-in') {
|
|
||||||
// Make sure we have a valid lease that we're moving in
|
|
||||||
if (empty($lease))
|
|
||||||
$this->redirect(array('action' => 'index'));
|
|
||||||
|
|
||||||
$movein = array();
|
|
||||||
$movein['time'] = strtotime($lease['Lease']['movein_date']);
|
|
||||||
$movein['effective_time'] = strtotime($lease['Lease']['movein_date']);
|
|
||||||
$movein_date = getdate($movein['effective_time']);
|
|
||||||
$movein['through_time'] = mktime(0, 0, 0, $movein_date['mon'] + 1, 0, $movein_date['year']);
|
|
||||||
$days_in_month = idate('d', $movein['through_time']);
|
|
||||||
$movein['prorated_days'] = $days_in_month - $movein_date['mday'] + 1;
|
|
||||||
$movein['prorated_rent'] = $lease['Lease']['rent'] * $movein['prorated_days'] / $days_in_month;
|
|
||||||
$movein['prorated'] = $movein['prorated_days'] != $days_in_month;
|
|
||||||
$movein['deposit'] = $lease['Lease']['deposit'];
|
|
||||||
$this->set(compact('movein'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
|
||||||
$lease['Unit']['name'] . ': ' .
|
|
||||||
$lease['Customer']['name'] . ': Charge Entry');
|
|
||||||
$this->set(compact('title', 'lease', 'charge'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: assess_rent/late
|
|
||||||
* - Assesses the new monthly rent/late charge, if need be
|
|
||||||
*/
|
|
||||||
|
|
||||||
function assess_rent($date = null) {
|
|
||||||
$this->Lease->assessMonthlyRentAll($date);
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
function assess_late($date = null) {
|
|
||||||
$this->Lease->assessMonthlyLateAll($date);
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
function assess_all($date = null) {
|
|
||||||
$this->Lease->assessMonthlyRentAll($date);
|
|
||||||
$this->Lease->assessMonthlyLateAll($date);
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: overview
|
|
||||||
* - Displays lease up information
|
|
||||||
*/
|
|
||||||
function overview($months = 12) {
|
|
||||||
|
|
||||||
$overview = array('months' => array());
|
|
||||||
|
|
||||||
for ($month = 0; $month < $months; ++$month) {
|
|
||||||
//for ($month = 12; $month >= 0; --$month) {
|
|
||||||
$this_month = "(DATE(NOW() - INTERVAL $month MONTH - INTERVAL DAY(NOW())-1 DAY))";
|
|
||||||
$next_month = "($this_month + INTERVAL 1 MONTH)";
|
|
||||||
|
|
||||||
$row = $this->Lease->find
|
|
||||||
('first', array('link' => array(),
|
|
||||||
'fields' => array("MONTHNAME($this_month) AS month",
|
|
||||||
"YEAR($this_month) AS year"),
|
|
||||||
));
|
|
||||||
|
|
||||||
$mname = $row[0]['month'] .', '. $row[0]['year'];
|
|
||||||
$overview['months'][$mname] = array('name' => $mname);
|
|
||||||
|
|
||||||
foreach(array('start' => array('before' => $this_month, 'after' => $this_month),
|
|
||||||
'finish' => array('before' => $next_month, 'after' => $next_month),
|
|
||||||
'peak' => array('before' => $next_month, 'after' => $this_month))
|
|
||||||
AS $type => $parm) {
|
|
||||||
$count = $this->Lease->find
|
|
||||||
('count',
|
|
||||||
array('link' => array(),
|
|
||||||
'conditions' => array("movein_date < {$parm['before']}",
|
|
||||||
"(moveout_date IS NULL OR moveout_date >= {$parm['after']})",
|
|
||||||
),
|
|
||||||
));
|
|
||||||
$overview['months'][$mname][$type] = $count;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(array('movein', 'moveout') AS $mvinout) {
|
|
||||||
$count = $this->Lease->find
|
|
||||||
('count',
|
|
||||||
array('link' => array(),
|
|
||||||
'conditions' => array("{$mvinout}_date < $next_month",
|
|
||||||
"{$mvinout}_date >= $this_month")
|
|
||||||
));
|
|
||||||
$overview['months'][$mname][$mvinout] = $count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the Reports menu section
|
|
||||||
$this->sideMenuAreaActivate('REPORT');
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$this->set('title', 'Lease Up Report');
|
|
||||||
$this->set(compact('overview'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: view
|
|
||||||
* - Displays information about a specific lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function view($id = null) {
|
|
||||||
if (!$id) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get details about the lease and its ledgers (no ledger entries yet)
|
|
||||||
$lease = $this->Lease->find
|
|
||||||
('first',
|
|
||||||
array('contain' =>
|
|
||||||
array(// Models
|
|
||||||
'LeaseType(id,name)',
|
|
||||||
'Unit(id,name)',
|
|
||||||
'Customer(id,name)',
|
|
||||||
),
|
|
||||||
'fields' => array('Lease.*', $this->Lease->delinquentField()),
|
|
||||||
'conditions' => array(array('Lease.id' => $id)),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$lease['Lease'] += $lease[0];
|
|
||||||
unset($lease[0]);
|
|
||||||
|
|
||||||
// Figure out the outstanding balances for this lease
|
|
||||||
$outstanding_balance = $this->Lease->balance($id);
|
|
||||||
$outstanding_deposit = $this->Lease->securityDepositBalance($id);
|
|
||||||
|
|
||||||
// Set up dynamic menu items. Normally, these will only be present
|
|
||||||
// on an open lease, but it's possible for a lease to be closed, and
|
|
||||||
// yet still have an outstanding balance. This can happen if someone
|
|
||||||
// were to reverse charges, or if a payment should come back NSF.
|
|
||||||
if (!isset($lease['Lease']['close_date']) || $outstanding_balance > 0) {
|
|
||||||
if (!isset($lease['Lease']['moveout_date']))
|
|
||||||
$this->addSideMenuLink('Move-Out',
|
|
||||||
array('action' => 'move_out', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
if (!isset($lease['Lease']['close_date']))
|
|
||||||
$this->addSideMenuLink('New Invoice',
|
|
||||||
array('action' => 'invoice', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
$this->addSideMenuLink('New Receipt',
|
|
||||||
array('controller' => 'customers',
|
|
||||||
'action' => 'receipt',
|
|
||||||
$lease['Customer']['id']), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
// REVISIT <AP>:
|
|
||||||
// Not allowing refund to be issued from the lease, as
|
|
||||||
// in fact, we should never have a positive lease balance.
|
|
||||||
// I'll flag this at the moment, since we might get one
|
|
||||||
// when a charge is reimbursed; a bug that we'll either
|
|
||||||
// need to fix, or we'll have to revisit this assumption.
|
|
||||||
if ($outstanding_balance < 0)
|
|
||||||
$this->INTERNAL_ERROR("Should not have a customer lease credit.");
|
|
||||||
|
|
||||||
/* if ($outstanding_balance < 0) */
|
|
||||||
/* $this->addSideMenuLink('Issue Refund', */
|
|
||||||
/* array('action' => 'refund', $id), null, */
|
|
||||||
/* 'ACTION'); */
|
|
||||||
|
|
||||||
if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0)
|
|
||||||
$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');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare to render
|
|
||||||
$title = 'Lease: #' . $lease['Lease']['id'];
|
|
||||||
$this->set(compact('lease', 'title',
|
|
||||||
'outstanding_deposit',
|
|
||||||
'outstanding_balance'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,364 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class StatementEntriesController extends AppController {
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: index / current / past / all
|
|
||||||
* - Creates a list of statement entries
|
|
||||||
*/
|
|
||||||
|
|
||||||
function index() { $this->gridView('All Statement Entries'); }
|
|
||||||
function unpaid() { $this->gridView('Unpaid Charges', 'unreconciled'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* 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) {
|
|
||||||
$link =
|
|
||||||
array(// Models
|
|
||||||
'Transaction' =>
|
|
||||||
array('fields' => array('id', 'stamp'),
|
|
||||||
),
|
|
||||||
|
|
||||||
'Customer' =>
|
|
||||||
array('fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
|
|
||||||
'Lease' =>
|
|
||||||
array('fields' => array('id', 'number'),
|
|
||||||
'Unit' =>
|
|
||||||
array('fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
'Account' =>
|
|
||||||
array('fields' => array('id', 'name', 'type'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!empty($params['post']['custom']['statement_entry_id'])) {
|
|
||||||
$link['ChargeEntry'] = array();
|
|
||||||
// This query actually represents a union...
|
|
||||||
// Unpaid Charge/Surplus: ChargeID - NULL; DisbursementID - NULL
|
|
||||||
// Paid Charge/Refund: ChargeID - NULL; DisbursementID - !NULL
|
|
||||||
// Disbursement/Reversal: ChargeID - !NULL; DisbursementID - NULL
|
|
||||||
// <EMPTY SET>: ChargeID - !NULL; DisbursementID - !NULL
|
|
||||||
//
|
|
||||||
// The query is really slow unless we add the `id` condition to the join.
|
|
||||||
// A cleaner query would be nice, but we must work within the Cake framework.
|
|
||||||
$link['DisbursementEntry'] = array('conditions' =>
|
|
||||||
'`DisbursementEntry`.`id` = '
|
|
||||||
. $params['post']['custom']['statement_entry_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array('link' => $link);
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
|
||||||
$tables = $this->gridDataCountTables($params, $model);
|
|
||||||
|
|
||||||
if (in_array('applied', $params['post']['fields'])) {
|
|
||||||
$tables['link'] +=
|
|
||||||
array('ChargeEntry' => array(),
|
|
||||||
'DisbursementEntry' => array());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tables;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataFields(&$params, &$model) {
|
|
||||||
$fields = parent::gridDataFields($params, $model);
|
|
||||||
|
|
||||||
if (in_array('applied', $params['post']['fields'])) {
|
|
||||||
$fields[] = ("IF(StatementEntry.type = 'CHARGE'," .
|
|
||||||
" SUM(COALESCE(DisbursementEntry.amount,0))," .
|
|
||||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
|
||||||
" AS 'applied'");
|
|
||||||
}
|
|
||||||
if (in_array('unapplied', $params['post']['fields'])) {
|
|
||||||
$fields[] = ("StatementEntry.amount - (" .
|
|
||||||
"IF(StatementEntry.type = 'CHARGE'," .
|
|
||||||
" SUM(COALESCE(DisbursementEntry.amount,0))," .
|
|
||||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
|
||||||
") AS 'unapplied'");
|
|
||||||
}
|
|
||||||
|
|
||||||
$fields = array_merge($fields,
|
|
||||||
$this->StatementEntry->chargeDisbursementFields());
|
|
||||||
|
|
||||||
return $fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataConditions(&$params, &$model) {
|
|
||||||
$conditions = parent::gridDataConditions($params, $model);
|
|
||||||
extract($params['post']['custom']);
|
|
||||||
|
|
||||||
if (!empty($from_date))
|
|
||||||
$conditions[]
|
|
||||||
= array('Transaction.stamp >=' =>
|
|
||||||
$this->StatementEntry->Transaction->dateFormatBeforeSave($from_date));
|
|
||||||
|
|
||||||
if (!empty($through_date))
|
|
||||||
$conditions[]
|
|
||||||
= array('Transaction.stamp <=' =>
|
|
||||||
$this->StatementEntry->Transaction->dateFormatBeforeSave($through_date . ' 23:59:59'));
|
|
||||||
|
|
||||||
if (isset($account_id))
|
|
||||||
$conditions[] = array('StatementEntry.account_id' => $account_id);
|
|
||||||
|
|
||||||
if (isset($customer_id))
|
|
||||||
$conditions[] = array('StatementEntry.customer_id' => $customer_id);
|
|
||||||
|
|
||||||
if (isset($statement_entry_id))
|
|
||||||
$conditions[] = array('OR' =>
|
|
||||||
array(array('ChargeEntry.id' => $statement_entry_id),
|
|
||||||
array('DisbursementEntry.id' => $statement_entry_id)));
|
|
||||||
|
|
||||||
return $conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
|
||||||
$links['StatementEntry'] = array('id');
|
|
||||||
$links['Transaction'] = array('id');
|
|
||||||
// REVISIT <AP>: 20090827
|
|
||||||
// Need to take 'level' into account
|
|
||||||
if ($this->Permission->allow('controller.accounts'))
|
|
||||||
$links['Account'] = array('name');
|
|
||||||
$links['Customer'] = array('name');
|
|
||||||
$links['Lease'] = array('number');
|
|
||||||
$links['Unit'] = array('name');
|
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
|
||||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
|
||||||
|
|
||||||
// After sorting by whatever the user wants, add these
|
|
||||||
// defaults into the sort mechanism. If we're already
|
|
||||||
// sorting by one of them, it will only be redundant,
|
|
||||||
// and should cause no harm (possible a longer query?)
|
|
||||||
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'] === 'unreconciled') {
|
|
||||||
$lquery = array('conditions' => $query['conditions']);
|
|
||||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true);
|
|
||||||
|
|
||||||
$entries = array();
|
|
||||||
foreach ($set['entries'] AS $entry)
|
|
||||||
$entries[] = $entry['StatementEntry']['id'];
|
|
||||||
|
|
||||||
$query['conditions'] = array('StatementEntry.id' => $entries);
|
|
||||||
$params['userdata']['balance'] = $set['summary']['balance'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($params['action'] === 'collected') {
|
|
||||||
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
|
|
||||||
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
|
|
||||||
$total = $model->find('first', $tquery);
|
|
||||||
$params['userdata']['total'] = $total[0]['total'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::gridDataRecordsExecute($params, $model, $query);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: reverse the ledger entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
function reverse($id = null) {
|
|
||||||
if ($this->data) {
|
|
||||||
//pr($this->data); die();
|
|
||||||
|
|
||||||
$this->StatementEntry->reverse
|
|
||||||
($this->data['StatementEntry']['id'],
|
|
||||||
$this->data['Transaction']['stamp'],
|
|
||||||
$this->data['Transaction']['comment']);
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'view',
|
|
||||||
$this->data['StatementEntry']['id']));
|
|
||||||
$this->INTERNAL_ERROR('SHOULD HAVE REDIRECTED');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->StatementEntry->id = $id;
|
|
||||||
$entry = $this->StatementEntry->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array('Customer', 'Transaction', 'Account'),
|
|
||||||
));
|
|
||||||
|
|
||||||
if (empty($entry)) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('controller' => 'customers',
|
|
||||||
'action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->StatementEntry->reversable($id)) {
|
|
||||||
$this->Session->setFlash(__('Item not reversable.', true));
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = ("Charge #{$entry['StatementEntry']['id']}" .
|
|
||||||
" : {$entry['StatementEntry']['amount']}" .
|
|
||||||
" : Reverse");
|
|
||||||
$this->set(compact('entry', 'title'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: waive the ledger entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
function waive($id) {
|
|
||||||
$this->StatementEntry->waive($id);
|
|
||||||
$this->redirect(array('action'=>'view', $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: chargesbymonth
|
|
||||||
* - Displays charges by month
|
|
||||||
*/
|
|
||||||
|
|
||||||
function chargesbymonth($months = 12) {
|
|
||||||
$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' => 'INCOME',
|
|
||||||
'effective_date >= DATE(NOW() - INTERVAL '.($months-1).' MONTH - INTERVAL DAY(NOW())-1 DAY)',
|
|
||||||
'effective_date <= NOW()',
|
|
||||||
),
|
|
||||||
'group' => array('YEAR(effective_date)', 'MONTH(effective_date)', 'Account.id'),
|
|
||||||
'order' => array('YEAR(effective_date) DESC', 'MONTH(effective_date) DESC', 'Account.name'),
|
|
||||||
));
|
|
||||||
|
|
||||||
$overview = array('months' => array(), 'charges' => 0);
|
|
||||||
foreach ($result AS $row) {
|
|
||||||
$mname = $row[0]['month'] .', '. $row[0]['year'];
|
|
||||||
if (empty($overview['months'][$mname]))
|
|
||||||
$overview['months'][$mname] = array('name' => $mname,
|
|
||||||
'subs' => array(),
|
|
||||||
'charges' => 0);
|
|
||||||
$month = &$overview['months'][$mname];
|
|
||||||
$month['subs'][] = array('name' => $row['Account']['name'],
|
|
||||||
'charges' => $row[0]['balance']);
|
|
||||||
|
|
||||||
$month['charges'] += $row[0]['balance'];
|
|
||||||
$overview['charges'] += $row[0]['balance'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable the Reports menu section
|
|
||||||
$this->sideMenuAreaActivate('REPORT');
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$this->set('months', $months);
|
|
||||||
$this->set('title', 'Monthly Charges');
|
|
||||||
$this->set(compact('overview'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: view
|
|
||||||
* - Displays information about a specific entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
function view($id = null) {
|
|
||||||
$entry = $this->StatementEntry->find
|
|
||||||
('first',
|
|
||||||
array('contain' => array
|
|
||||||
('Transaction' => array('fields' => array('id', 'type', 'stamp')),
|
|
||||||
'Account' => array('id', 'name', 'type', 'level'),
|
|
||||||
'Customer' => array('fields' => array('id', 'name')),
|
|
||||||
'Lease' => array('fields' => array('id', 'number')),
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' => array(array('StatementEntry.id' => $id),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
if (empty($entry)) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$entry['Account']['link'] =
|
|
||||||
$entry['Account']['level'] >=
|
|
||||||
$this->Permission->level('controller.accounts');
|
|
||||||
|
|
||||||
$stats = $this->StatementEntry->stats($id);
|
|
||||||
|
|
||||||
if (in_array(strtoupper($entry['StatementEntry']['type']), $this->StatementEntry->debitTypes()))
|
|
||||||
$stats = $stats['Charge'];
|
|
||||||
else
|
|
||||||
$stats = $stats['Disbursement'];
|
|
||||||
|
|
||||||
|
|
||||||
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
|
|
||||||
|
|
||||||
// Set up dynamic menu items
|
|
||||||
if ($this->StatementEntry->reversable($id))
|
|
||||||
$this->addSideMenuLink('Reverse',
|
|
||||||
array('action' => 'reverse', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
if ($stats['balance'] > 0)
|
|
||||||
$this->addSideMenuLink('Waive Balance',
|
|
||||||
array('action' => 'waive', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = "Statement Entry #{$entry['StatementEntry']['id']}";
|
|
||||||
$this->set(compact('entry', 'title', 'stats'));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,255 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class UnitSizesController extends AppController {
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* override: addGridViewSideMenuLinks
|
|
||||||
* - Adds grid view navigation side menu links
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addGridViewSideMenuLinks() {
|
|
||||||
parent::addGridViewSideMenuLinks();
|
|
||||||
|
|
||||||
$this->addSideMenuLink('1 Bedroom',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'bd1'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('2 Bedroom',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'bd2'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('3 Bedroom',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'bd3'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('4+ Bedroom',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'bd4'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Auto',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'auto'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Boat',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'boat'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('RV',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'rv'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('All',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'all'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: index / unavailable / vacant / occupied / all
|
|
||||||
* - Generate a listing of units
|
|
||||||
*/
|
|
||||||
|
|
||||||
function index() { $this->all(); }
|
|
||||||
function bd1() { $this->gridView('Sizes for 1 Bedroom'); }
|
|
||||||
function bd2() { $this->gridView('Sizes for 2 Bedrooms'); }
|
|
||||||
function bd3() { $this->gridView('Sizes for 3 Bedroom'); }
|
|
||||||
function bd4() { $this->gridView('Sizes for 4+ Bedroom'); }
|
|
||||||
function auto() { $this->gridView('Sizes for an Automobile'); }
|
|
||||||
function boat() { $this->gridView('Sizes for a Boat'); }
|
|
||||||
function rv() { $this->gridView('Sizes for an RV'); }
|
|
||||||
function all() { $this->gridView('All Unit Sizes', 'all'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* virtuals: gridData
|
|
||||||
* - With the application controller handling the gridData action,
|
|
||||||
* these virtual functions ensure that the correct data is passed
|
|
||||||
* to jqGrid.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function gridDataCountTables(&$params, &$model) {
|
|
||||||
return array('link' => array('UnitType'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
|
||||||
$tables = $this->gridDataCountTables($params, $model);
|
|
||||||
$tables['link']['Unit'] = array();
|
|
||||||
return $tables;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataFields(&$params, &$model) {
|
|
||||||
$fields = parent::gridDataFields($params, $model);
|
|
||||||
$fields[] = 'ROUND(UnitSize.width/12, 1) AS width';
|
|
||||||
$fields[] = 'ROUND(UnitSize.depth/12, 1) AS depth';
|
|
||||||
$fields[] = 'ROUND(UnitSize.height/12, 1) AS height';
|
|
||||||
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft';
|
|
||||||
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12, 0) AS cuft';
|
|
||||||
$fields[] = 'ROUND(UnitSize.rent / (UnitSize.width/12 * UnitSize.depth/12), 2) AS sqcost';
|
|
||||||
$fields[] = 'ROUND(UnitSize.rent / (UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12), 2) AS cucost';
|
|
||||||
|
|
||||||
$fields[] = 'COUNT(Unit.id) AS units';
|
|
||||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionUnavailable() . ', 1, 0)) AS unavailable';
|
|
||||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionAvailable() . ', 1, 0)) AS available';
|
|
||||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 1, 0)) AS occupied';
|
|
||||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 0, 1)) / COUNT(unit.id) AS vacancy';
|
|
||||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 1, 0)) / COUNT(unit.id) AS occupancy';
|
|
||||||
|
|
||||||
return $fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataConditions(&$params, &$model) {
|
|
||||||
$conditions = parent::gridDataConditions($params, $model);
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090825
|
|
||||||
// Sizes should come from the database.
|
|
||||||
// For now, I took an assumed average need, then bracketed
|
|
||||||
// with +/- 50 sqft. This gives a 100sqft range for each.
|
|
||||||
if ($params['action'] === 'bd1') { // 75 sqft
|
|
||||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
|
||||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 125';
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'bd2') { // 125 sqft
|
|
||||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
|
||||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 75';
|
|
||||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 175';
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'bd3') { // 175 sqft
|
|
||||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
|
||||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 125';
|
|
||||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 225';
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'bd4') { // 225 sqft
|
|
||||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
|
||||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 175';
|
|
||||||
}
|
|
||||||
elseif (in_array($params['action'], array('auto', 'boat', 'rv'))) {
|
|
||||||
$conditions[] = array('UnitType.id' =>
|
|
||||||
array_merge(array_keys($this->UnitSize->UnitType->enclosedTypes()),
|
|
||||||
array_keys($this->UnitSize->UnitType->outdoorTypes())));
|
|
||||||
list($width, $depth, $height) = array(8, 15, null);
|
|
||||||
if ($params['action'] === 'auto')
|
|
||||||
$depth = 15;
|
|
||||||
elseif ($params['action'] === 'boat')
|
|
||||||
$depth = 15;
|
|
||||||
elseif ($params['action'] === 'rv')
|
|
||||||
list($width, $depth, $height) = array(10, 25, 12);
|
|
||||||
|
|
||||||
$conditions[] = "(UnitSize.width/12) >= $width";
|
|
||||||
$conditions[] = "(UnitSize.depth/12) >= $depth";
|
|
||||||
if (isset($height))
|
|
||||||
$conditions[] = array('OR' =>
|
|
||||||
array("(UnitSize.height/12) >= $height",
|
|
||||||
//"UnitSize.height IS NULL",
|
|
||||||
array('UnitType.id' =>
|
|
||||||
array_keys($this->UnitSize->UnitType->outdoorTypes())),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
|
||||||
if ($index == 'UnitType.name')
|
|
||||||
$index = 'UnitType.code';
|
|
||||||
|
|
||||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
|
||||||
|
|
||||||
// After sorting by whatever the user wants, add these
|
|
||||||
// defaults into the sort mechanism. If we're already
|
|
||||||
// sorting by one of them, it will only be redundant,
|
|
||||||
// and should cause no harm (possible a longer query?)
|
|
||||||
$order[] = 'UnitType.code ' . $direction;
|
|
||||||
$order[] = 'sqft ' . $direction;
|
|
||||||
$order[] = 'UnitSize.rent ' . $direction;
|
|
||||||
|
|
||||||
return $order;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
|
||||||
$links['UnitSize'] = array('name');
|
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: view
|
|
||||||
* - Displays information about a specific entry
|
|
||||||
*/
|
|
||||||
|
|
||||||
function view($id = null) {
|
|
||||||
if (!$id) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the UnitSize and related fields
|
|
||||||
$this->UnitSize->id = $id;
|
|
||||||
$size = $this->UnitSize->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array('UnitType'),
|
|
||||||
'fields' => array('UnitSize.*', 'UnitType.*',
|
|
||||||
'ROUND(UnitSize.width/12, 1) AS width',
|
|
||||||
'ROUND(UnitSize.depth/12, 1) AS depth',
|
|
||||||
'ROUND(UnitSize.height/12, 1) AS height',
|
|
||||||
'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft',
|
|
||||||
'ROUND(UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12, 0) AS cuft'),
|
|
||||||
));
|
|
||||||
$size['UnitSize'] = $size[0] + $size['UnitSize'];
|
|
||||||
unset($size[0]);
|
|
||||||
|
|
||||||
$this->set(compact('size'));
|
|
||||||
$this->set('stats', $this->UnitSize->stats($id));
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = "Unit Size : {$size['UnitSize']['name']}";
|
|
||||||
$this->set(compact('title'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: edit
|
|
||||||
* - Edit unit_size information
|
|
||||||
*/
|
|
||||||
|
|
||||||
function edit($id = null) {
|
|
||||||
$this->INTERNAL_ERROR('NOT READY');
|
|
||||||
if (isset($this->data)) {
|
|
||||||
// Check to see if the operation was cancelled.
|
|
||||||
if (isset($this->params['form']['cancel'])) {
|
|
||||||
if (empty($this->data['UnitSize']['id']))
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['UnitSize']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we have unit_size data
|
|
||||||
if (empty($this->data['UnitSize']) || empty($this->data['UnitSize']['id']))
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
|
|
||||||
// Save the unit_size and all associated data
|
|
||||||
$this->UnitSize->create();
|
|
||||||
$this->UnitSize->id = $this->data['UnitSize']['id'];
|
|
||||||
if (!$this->UnitSize->save($this->data, false)) {
|
|
||||||
$this->Session->setFlash("UNIT_SIZE SAVE FAILED", true);
|
|
||||||
pr("UNIT_SIZE SAVE FAILED");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'view', $this->UnitSize->id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($id) {
|
|
||||||
$this->data = $this->UnitSize->findById($id);
|
|
||||||
} else {
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = ('UnitSize ' . $this->data['UnitSize']['name'] .
|
|
||||||
" : Edit");
|
|
||||||
$this->set(compact('title'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,461 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class UnitsController extends AppController {
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* override: addGridViewSideMenuLinks
|
|
||||||
* - Adds grid view navigation side menu links
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addGridViewSideMenuLinks() {
|
|
||||||
parent::addGridViewSideMenuLinks();
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Unavailable',
|
|
||||||
array('controller' => 'units', 'action' => 'unavailable'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Vacant',
|
|
||||||
array('controller' => 'units', 'action' => 'vacant'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Occupied',
|
|
||||||
array('controller' => 'units', 'action' => 'occupied'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Overlocked',
|
|
||||||
array('controller' => 'units', 'action' => 'locked'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Liened',
|
|
||||||
array('controller' => 'units', 'action' => 'liened'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('All',
|
|
||||||
array('controller' => 'units', 'action' => 'all'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: index / unavailable / vacant / occupied / all
|
|
||||||
* - Generate a listing of units
|
|
||||||
*/
|
|
||||||
|
|
||||||
function index() { $this->all(); }
|
|
||||||
function unavailable() { $this->gridView('Unavailable Units'); }
|
|
||||||
function vacant() { $this->gridView('Vacant Units'); }
|
|
||||||
function occupied() { $this->gridView('Occupied Units'); }
|
|
||||||
function locked() { $this->gridView('Overlocked Units'); }
|
|
||||||
function liened() { $this->gridView('Liened Units'); }
|
|
||||||
function all() { $this->gridView('All Units', 'all'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* virtuals: gridData
|
|
||||||
* - With the application controller handling the gridData action,
|
|
||||||
* these virtual functions ensure that the correct data is passed
|
|
||||||
* to jqGrid.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function gridDataSetup(&$params) {
|
|
||||||
parent::gridDataSetup($params);
|
|
||||||
if (!isset($params['action']))
|
|
||||||
$params['action'] = 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataCountTables(&$params, &$model) {
|
|
||||||
return array
|
|
||||||
('link' => array('UnitSize' => array('fields' => array('id', 'name')),
|
|
||||||
'CurrentLease' => array('fields' => array('id'))));
|
|
||||||
|
|
||||||
/* if ($params['action'] === 'occupied') */
|
|
||||||
/* $link['Lease'] = array('fields' => array(), */
|
|
||||||
/* // Models */
|
|
||||||
/* 'Contact' => array('fields' => array('display_name'), */
|
|
||||||
/* //'type' => 'LEFT', */
|
|
||||||
/* ), */
|
|
||||||
/* ); */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
|
||||||
$link = $this->gridDataCountTables($params, $model);
|
|
||||||
$link['link']['CurrentLease']['StatementEntry'] = array('fields' => array());
|
|
||||||
return $link;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* function gridDataTables(&$params, &$model) { */
|
|
||||||
/* return array */
|
|
||||||
/* ('link' => array('Unit' => array('fields' => array('Unit.id', 'Unit.name')), */
|
|
||||||
/* 'Customer' => array('fields' => array('Customer.id', 'Customer.name')))); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
function gridDataFields(&$params, &$model) {
|
|
||||||
$fields = parent::gridDataFields($params, $model);
|
|
||||||
|
|
||||||
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft';
|
|
||||||
return array_merge($fields,
|
|
||||||
$this->Unit->Lease->StatementEntry->chargeDisbursementFields(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataConditions(&$params, &$model) {
|
|
||||||
$conditions = parent::gridDataConditions($params, $model);
|
|
||||||
|
|
||||||
if ($params['action'] === 'unavailable') {
|
|
||||||
$conditions[] = $this->Unit->conditionUnavailable();
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'vacant') {
|
|
||||||
$conditions[] = $this->Unit->conditionVacant();
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'occupied') {
|
|
||||||
$conditions[] = $this->Unit->conditionOccupied();
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'unoccupied') {
|
|
||||||
$conditions[] = array('NOT' => array($this->Unit->conditionOccupied()));
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'locked') {
|
|
||||||
$conditions[] = $this->Unit->conditionLocked();
|
|
||||||
}
|
|
||||||
elseif ($params['action'] === 'liened') {
|
|
||||||
$conditions[] = $this->Unit->conditionLiened();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
|
||||||
// Instead of sorting by name, sort by defined order
|
|
||||||
if ($index === 'Unit.name')
|
|
||||||
$index = 'Unit.sort_order';
|
|
||||||
|
|
||||||
$order = array();
|
|
||||||
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
|
|
||||||
|
|
||||||
// If sorting by anything other than name (defined order)
|
|
||||||
// add the sort-order as a secondary condition
|
|
||||||
if ($index !== 'Unit.name')
|
|
||||||
$order[] = parent::gridDataOrder($params, $model,
|
|
||||||
'Unit.sort_order', $direction);
|
|
||||||
|
|
||||||
return $order;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
|
||||||
$links['Unit'] = array('name');
|
|
||||||
$links['UnitSize'] = array('name');
|
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: move_in
|
|
||||||
* - Sets up the move-in page for the given unit.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function move_in($id = null) {
|
|
||||||
$customer = array();
|
|
||||||
$unit = array();
|
|
||||||
|
|
||||||
if (!empty($id)) {
|
|
||||||
$this->Unit->recursive = -1;
|
|
||||||
$unit = current($this->Unit->read(null, $id));
|
|
||||||
}
|
|
||||||
|
|
||||||
$title = 'Unit Move-In';
|
|
||||||
$this->set(compact('customer', 'unit', 'title'));
|
|
||||||
$this->render('/leases/move');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: move_out
|
|
||||||
* - prepare or execute a move out on a specific lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function move_out($id) {
|
|
||||||
|
|
||||||
$unit = $this->Unit->find
|
|
||||||
('first', array
|
|
||||||
('contain' => array
|
|
||||||
(// Models
|
|
||||||
'CurrentLease' =>
|
|
||||||
array(//'conditions' => array('Lease.moveout_date' => null),
|
|
||||||
// Models
|
|
||||||
'Customer' =>
|
|
||||||
array('fields' => array('id', 'name'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'conditions' => array('Unit.id' => $id),
|
|
||||||
));
|
|
||||||
$this->set('customer', $unit['CurrentLease']['Customer']);
|
|
||||||
$this->set('unit', $unit['Unit']);
|
|
||||||
$this->set('lease', $unit['CurrentLease']);
|
|
||||||
|
|
||||||
$redirect = array('controller' => 'units',
|
|
||||||
'action' => 'view',
|
|
||||||
$id);
|
|
||||||
|
|
||||||
$title = ('Lease #' . $unit['CurrentLease']['number'] . ': ' .
|
|
||||||
$unit['Unit']['name'] . ': ' .
|
|
||||||
$unit['CurrentLease']['Customer']['name'] . ': Prepare Move-Out');
|
|
||||||
$this->set(compact('title', 'redirect'));
|
|
||||||
$this->render('/leases/move');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: lock/unlock
|
|
||||||
* - Transitions the unit into / out of the LOCKED state
|
|
||||||
*/
|
|
||||||
|
|
||||||
function status($id, $status) {
|
|
||||||
$this->Unit->updateStatus($id, $status, true);
|
|
||||||
$this->redirect(array('action' => 'view', $id));
|
|
||||||
}
|
|
||||||
function lock($id) { $this->status($id, 'LOCKED'); }
|
|
||||||
function unlock($id) { $this->status($id, 'OCCUPIED'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* 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'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: view
|
|
||||||
* - Displays information about a specific unit
|
|
||||||
*/
|
|
||||||
|
|
||||||
function view($id = null) {
|
|
||||||
if (!$id) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('action'=>''));
|
|
||||||
}
|
|
||||||
|
|
||||||
$unit = $this->Unit->find
|
|
||||||
('first',
|
|
||||||
array('contain' =>
|
|
||||||
array(// Models
|
|
||||||
'UnitSize',
|
|
||||||
'Lease' => array('Customer'),
|
|
||||||
'CurrentLease' => array('Customer')
|
|
||||||
),
|
|
||||||
'conditions' => array('Unit.id' => $id),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Get the balance on each lease.
|
|
||||||
foreach ($unit['Lease'] AS &$lease) {
|
|
||||||
$stats = $this->Unit->Lease->stats($lease['id']);
|
|
||||||
$lease['balance'] = $stats['balance'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$outstanding_balance = 0;
|
|
||||||
$outstanding_deposit = 0;
|
|
||||||
if (isset($unit['CurrentLease']['id'])) {
|
|
||||||
// Figure out the outstanding balance of the current lease.
|
|
||||||
$stats = $this->Unit->stats($id);
|
|
||||||
$outstanding_balance =
|
|
||||||
$stats['CurrentLease']['balance'];
|
|
||||||
|
|
||||||
// Figure out the total security deposit for the current lease.
|
|
||||||
$deposits = $this->Unit->Lease->securityDeposits($unit['CurrentLease']['id']);
|
|
||||||
$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');
|
|
||||||
|
|
||||||
// If the unit is locked, provide an option to unlock it,
|
|
||||||
// unless it's locked due to lien, which is not so simple.
|
|
||||||
if ($this->Unit->locked($unit['Unit']['status']) &&
|
|
||||||
!$this->Unit->liened($unit['Unit']['status']))
|
|
||||||
$this->addSideMenuLink('Unlock',
|
|
||||||
array('action' => 'unlock', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
// If there is a current lease on this unit, then provide
|
|
||||||
// a link to move the tenant out. Current lease for a unit
|
|
||||||
// has a bit different definition than a current lease for
|
|
||||||
// a customer, since a lease stays with a customer until it
|
|
||||||
// is finally closed. A lease, however, only stays with a
|
|
||||||
// unit while occupied (since a unit is not responsible for
|
|
||||||
// any lingering financial obligations, like a customer is).
|
|
||||||
// Of course, if there is no current lease, provide a link
|
|
||||||
// to move a new tenant in (if the unit is available).
|
|
||||||
if (isset($unit['CurrentLease']['id'])) {
|
|
||||||
$this->addSideMenuLink('Move-Out',
|
|
||||||
array('action' => 'move_out', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
} elseif ($this->Unit->available($unit['Unit']['status'])) {
|
|
||||||
$this->addSideMenuLink('Move-In',
|
|
||||||
array('action' => 'move_in', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
} else {
|
|
||||||
// Unit is unavailable (dirty, damaged, reserved, business-use, etc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is a current lease, allow new charges to
|
|
||||||
// be added, and payments to be made.
|
|
||||||
if (isset($unit['CurrentLease']['id'])) {
|
|
||||||
$this->addSideMenuLink('New Invoice',
|
|
||||||
array('controller' => 'leases',
|
|
||||||
'action' => 'invoice',
|
|
||||||
$unit['CurrentLease']['id']), null,
|
|
||||||
'ACTION');
|
|
||||||
$this->addSideMenuLink('New Receipt',
|
|
||||||
array('controller' => 'customers',
|
|
||||||
'action' => 'receipt',
|
|
||||||
$unit['CurrentLease']['customer_id']), null,
|
|
||||||
'ACTION');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always allow the unit to be edited.
|
|
||||||
$this->addSideMenuLink('Edit',
|
|
||||||
array('action' => 'edit', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = 'Unit ' . $unit['Unit']['name'];
|
|
||||||
$this->set(compact('unit', 'title',
|
|
||||||
'outstanding_balance',
|
|
||||||
'outstanding_deposit'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: edit
|
|
||||||
* - Edit unit information
|
|
||||||
*/
|
|
||||||
|
|
||||||
function edit($id = null) {
|
|
||||||
if (isset($this->data)) {
|
|
||||||
// Check to see if the operation was cancelled.
|
|
||||||
if (isset($this->params['form']['cancel'])) {
|
|
||||||
if (empty($this->data['Unit']['id']))
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['Unit']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we have unit data
|
|
||||||
if (empty($this->data['Unit']))
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
|
|
||||||
// Make sure we have a rental rate
|
|
||||||
if (empty($this->data['Unit']['rent']))
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['Unit']['id']));
|
|
||||||
|
|
||||||
// Save the unit and all associated data
|
|
||||||
$this->Unit->create();
|
|
||||||
$this->Unit->id = $this->data['Unit']['id'];
|
|
||||||
if (!$this->Unit->save($this->data, false)) {
|
|
||||||
$this->Session->setFlash("UNIT SAVE FAILED", true);
|
|
||||||
pr("UNIT SAVE FAILED");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'view', $this->Unit->id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($id) {
|
|
||||||
$this->data = $this->Unit->findById($id);
|
|
||||||
$title = 'Unit ' . $this->data['Unit']['name'] . " : Edit";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$title = "Enter New Unit";
|
|
||||||
$this->data = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$statusEnums = $this->Unit->allowedStatusSet($id);
|
|
||||||
$statusEnums = array_combine(array_keys($statusEnums),
|
|
||||||
array_keys($statusEnums));
|
|
||||||
$this->set(compact('statusEnums'));
|
|
||||||
|
|
||||||
$unit_sizes = $this->Unit->UnitSize->find
|
|
||||||
('list', array('order' => array('unit_type_id', 'width', 'depth', 'id')));
|
|
||||||
$this->set(compact('unit_sizes'));
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$this->set(compact('title'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: rebuild_box
|
|
||||||
*/
|
|
||||||
|
|
||||||
function rebuild_box($type) {
|
|
||||||
$this->layout = null;
|
|
||||||
$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');
|
|
||||||
while (($read = fread($handle, 2096))) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
pclose($handle);
|
|
||||||
|
|
||||||
$url = $_SERVER['HTTP_REFERER'];
|
|
||||||
if (empty($url))
|
|
||||||
$url = "/";
|
|
||||||
|
|
||||||
$this->redirect($url);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rebuild_sandbox() { $this->rebuild_box('sand'); }
|
|
||||||
function rebuild_devbox() { $this->rebuild_box('dev'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: logmsg
|
|
||||||
* - action to allow posting log message data
|
|
||||||
*/
|
|
||||||
|
|
||||||
function logmsg() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+1360
File diff suppressed because it is too large
Load Diff
@@ -1,506 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Customer extends AppModel {
|
|
||||||
|
|
||||||
var $name = 'Customer';
|
|
||||||
var $validate = array(
|
|
||||||
'id' => array('numeric'),
|
|
||||||
'name' => array('notempty'),
|
|
||||||
);
|
|
||||||
|
|
||||||
var $belongsTo = array(
|
|
||||||
'PrimaryContact' => array(
|
|
||||||
'className' => 'Contact',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasMany = array(
|
|
||||||
'CurrentLease' => array(
|
|
||||||
'className' => 'Lease',
|
|
||||||
'conditions' => 'CurrentLease.close_date IS NULL',
|
|
||||||
),
|
|
||||||
'Lease',
|
|
||||||
'StatementEntry',
|
|
||||||
'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' => array(
|
|
||||||
'unique' => true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
//var $default_log_level = 20;
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: accountId
|
|
||||||
* - Returns the account ID for the given customer
|
|
||||||
*/
|
|
||||||
function accountId($id) {
|
|
||||||
$this->cacheQueries = true;
|
|
||||||
$customer = $this->find('first',
|
|
||||||
array('contain' => false,
|
|
||||||
'fields' => array('account_id'),
|
|
||||||
'conditions' => array(array('Customer.id' => $id))));
|
|
||||||
$this->cacheQueries = false;
|
|
||||||
|
|
||||||
return $customer['Customer']['account_id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: leaseIds
|
|
||||||
* - Returns the lease IDs for the given customer
|
|
||||||
*/
|
|
||||||
function leaseIds($id, $current = false) {
|
|
||||||
$Lease = $current ? 'CurrentLease' : 'Lease';
|
|
||||||
|
|
||||||
$this->cacheQueries = true;
|
|
||||||
$customer = $this->find('first',
|
|
||||||
array('contain' =>
|
|
||||||
array($Lease => array('fields' => array('id'))),
|
|
||||||
'fields' => array(),
|
|
||||||
'conditions' => array(array('Customer.id' => $id))));
|
|
||||||
$this->cacheQueries = false;
|
|
||||||
|
|
||||||
$ids = array();
|
|
||||||
foreach ($customer[$Lease] AS $lease)
|
|
||||||
$ids[] = $lease['id'];
|
|
||||||
|
|
||||||
return $ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: securityDeposits
|
|
||||||
* - Returns an array of security deposit entries
|
|
||||||
*/
|
|
||||||
function securityDeposits($id, $query = null) {
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
||||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
|
||||||
$this->StatementEntry->Account->securityDepositAccountID());
|
|
||||||
|
|
||||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
|
||||||
return $this->prReturn($set);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: securityDepositBalance
|
|
||||||
* - Returns the balance of the customer security deposit(s)
|
|
||||||
*/
|
|
||||||
|
|
||||||
function securityDepositBalance($id, $query = null) {
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$sd_account_id =
|
|
||||||
$this->StatementEntry->Account->securityDepositAccountID();
|
|
||||||
|
|
||||||
$squery = $query;
|
|
||||||
$squery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
||||||
$squery['conditions'][] = array('StatementEntry.account_id' => $sd_account_id);
|
|
||||||
$stats = $this->StatementEntry->stats(null, $squery);
|
|
||||||
$this->pr(26, compact('squery', 'stats'));
|
|
||||||
|
|
||||||
// OK, we know now how much we charged for a security
|
|
||||||
// deposit, as well as how much we received to pay for it.
|
|
||||||
// Now we need to know if any has been released.
|
|
||||||
// Yes... this sucks.
|
|
||||||
$lquery = $query;
|
|
||||||
$lquery['link'] = array('Transaction' =>
|
|
||||||
array('fields' => array(),
|
|
||||||
'Customer' =>
|
|
||||||
(empty($query['link'])
|
|
||||||
? array('fields' => array())
|
|
||||||
: $query['link'])));
|
|
||||||
$lquery['conditions'][] = array('Transaction.customer_id' => $id);
|
|
||||||
$lquery['conditions'][] = array('LedgerEntry.account_id' => $sd_account_id);
|
|
||||||
$lquery['conditions'][] = array('LedgerEntry.crdr' => 'DEBIT');
|
|
||||||
$lquery['fields'][] = 'SUM(LedgerEntry.amount) AS total';
|
|
||||||
$released = $this->StatementEntry->Transaction->LedgerEntry->find
|
|
||||||
('first', $lquery);
|
|
||||||
$this->pr(26, compact('lquery', 'released'));
|
|
||||||
|
|
||||||
return $this->prReturn($stats['Charge']['disbursement'] - $released[0]['total']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: unreconciledCharges
|
|
||||||
* - Returns charges have not yet been fully paid
|
|
||||||
*/
|
|
||||||
|
|
||||||
function unreconciledCharges($id, $query = null) {
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
||||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
|
|
||||||
return $this->prReturn($set);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: saveCustomer
|
|
||||||
* - Saves the customer and related data
|
|
||||||
*/
|
|
||||||
|
|
||||||
function saveCustomer($id, $data, $primary_contact_entry) {
|
|
||||||
|
|
||||||
// Go through each contact, and create new ones as needed
|
|
||||||
foreach ($data['Contact'] AS &$contact) {
|
|
||||||
if (isset($contact['id']))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$I = new Contact();
|
|
||||||
if (!$I->saveContact(null, array('Contact' => $contact)))
|
|
||||||
return false;
|
|
||||||
$contact['id'] = $I->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the primary contact ID based on caller selection
|
|
||||||
$data['Customer']['primary_contact_id']
|
|
||||||
= $data['Contact'][$primary_contact_entry]['id'];
|
|
||||||
|
|
||||||
// Provide a default customer name if not specified
|
|
||||||
if (!$data['Customer']['name']) {
|
|
||||||
$this->Contact->recursive = -1;
|
|
||||||
$pcontact = $this->Contact->read(null, $data['Customer']['primary_contact_id']);
|
|
||||||
$data['Customer']['name'] = $pcontact['Contact']['display_name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the customer data
|
|
||||||
$this->create();
|
|
||||||
if ($id)
|
|
||||||
$this->id = $id;
|
|
||||||
if (!$this->save($data, false)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$id = $this->id;
|
|
||||||
|
|
||||||
// Appears that $this->save() "helpfully" choses to add in
|
|
||||||
// any missing data fields, populated with default values.
|
|
||||||
// So, after saving is complete, the fields 'lease_count',
|
|
||||||
// 'past_lease_count', and 'current_lease_count' have all
|
|
||||||
// been reset to zero. Gee, thanks Cake...
|
|
||||||
$this->update($id);
|
|
||||||
|
|
||||||
// Remove all associated Customer Contacts, as it ensures
|
|
||||||
// any entries deleted by the user actually get deleted
|
|
||||||
// in the system. We'll recreate the needed ones anyway.
|
|
||||||
// REVISIT <AP>: 20090706
|
|
||||||
// Appears that $this->save() is already doing the
|
|
||||||
// delete. I would have thought this would only happen
|
|
||||||
// on a saveAll??
|
|
||||||
/* $this->ContactsCustomer->deleteAll */
|
|
||||||
/* (array('customer_id' => $id), false); */
|
|
||||||
|
|
||||||
// At this point, since we've saved data to customer,
|
|
||||||
// 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 entry of this customer method
|
|
||||||
foreach ($data['Contact'] AS &$contact) {
|
|
||||||
// Update the ContactsCustomer to reflect the appropriate IDs
|
|
||||||
$contact['ContactsCustomer']['customer_id'] = $id;
|
|
||||||
$contact['ContactsCustomer']['contact_id'] = $contact['id'];
|
|
||||||
|
|
||||||
// Save the relationship between customer and contact
|
|
||||||
$CM = new ContactsCustomer();
|
|
||||||
if (!$CM->save($contact['ContactsCustomer'], false)) {
|
|
||||||
$ret = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the result
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: update
|
|
||||||
* - Update any cached or calculated fields
|
|
||||||
*/
|
|
||||||
function update($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
|
|
||||||
if (empty($id)) {
|
|
||||||
$customers = $this->find('all', array('contain' => false, 'fields' => array('id')));
|
|
||||||
foreach ($customers AS $customer) {
|
|
||||||
// This SHOULDN'T happen, but check to be sure
|
|
||||||
// or we'll get infinite recursion.
|
|
||||||
if (empty($customer['Customer']['id']))
|
|
||||||
continue;
|
|
||||||
$this->update($customer['Customer']['id']);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateLeaseCount is typically handled directly when needed.
|
|
||||||
// However, this function is used to _ensure_ customer info is
|
|
||||||
// current, so we're obligated to call it anyway.
|
|
||||||
$this->updateLeaseCount($id);
|
|
||||||
|
|
||||||
$current_leases =
|
|
||||||
$this->find('all',
|
|
||||||
// REVISIT <AP>: 20090816
|
|
||||||
// Do we need to update leases other than the current ones?
|
|
||||||
// It may be necessary. For example, a non-current lease
|
|
||||||
// can still be hit with an NSF item. In that case, it
|
|
||||||
// could have stale data if we look only to current leases.
|
|
||||||
//array('link' => array('CurrentLease' => array('type' => 'INNER')),
|
|
||||||
array('link' => array('Lease' => array('type' => 'INNER')),
|
|
||||||
'conditions' => array('Customer.id' => $id)));
|
|
||||||
|
|
||||||
foreach ($current_leases AS $lease) {
|
|
||||||
if (!empty($lease['CurrentLease']['id']))
|
|
||||||
$this->Lease->update($lease['CurrentLease']['id']);
|
|
||||||
if (!empty($lease['Lease']['id']))
|
|
||||||
$this->Lease->update($lease['Lease']['id']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: merge
|
|
||||||
* - Merges two customers into one
|
|
||||||
*/
|
|
||||||
|
|
||||||
function merge($dst_id, $src_id, $contacts) {
|
|
||||||
$this->prEnter(compact('dst_id', 'src_id', 'contacts'));
|
|
||||||
|
|
||||||
// Get the entire list of destination customer contacts
|
|
||||||
$dst_contacts = array();
|
|
||||||
$result = $this->find('all',
|
|
||||||
array('link' => array('ContactsCustomer'),
|
|
||||||
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
|
|
||||||
'conditions' => array(array('id' => $dst_id,
|
|
||||||
'ContactsCustomer.active' => true))));
|
|
||||||
foreach ($result AS $contact) {
|
|
||||||
$dst_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
|
|
||||||
}
|
|
||||||
$this->pr(17, compact('dst_contacts'));
|
|
||||||
|
|
||||||
// Get the entire list of source customer contacts
|
|
||||||
$src_contacts = array();
|
|
||||||
$result = $this->find('all',
|
|
||||||
array('link' => array('ContactsCustomer'),
|
|
||||||
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
|
|
||||||
'conditions' => array(array('id' => $src_id,
|
|
||||||
'ContactsCustomer.active' => true))));
|
|
||||||
foreach ($result AS $contact) {
|
|
||||||
$src_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
|
|
||||||
}
|
|
||||||
$this->pr(17, compact('src_contacts'));
|
|
||||||
|
|
||||||
// Verify the contacts list are all valid source customer contacts
|
|
||||||
foreach ($contacts AS $contact_id) {
|
|
||||||
if (!array_key_exists($contact_id, $src_contacts))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove any contacts which are already destination customer contacts
|
|
||||||
$new_contacts = array_diff($contacts, array_keys($dst_contacts));
|
|
||||||
$all_contacts = array_merge($new_contacts, array_keys($dst_contacts));
|
|
||||||
$this->pr(17, compact('new_contacts', 'all_contacts'));
|
|
||||||
|
|
||||||
// For now, we'll assume the operation will succeed.
|
|
||||||
$ret = true;
|
|
||||||
|
|
||||||
// Add each desired source customer contact to the destination customer
|
|
||||||
foreach ($new_contacts AS $contact_id) {
|
|
||||||
$CM = new ContactsCustomer();
|
|
||||||
if (!$CM->save(array('customer_id' => $dst_id)
|
|
||||||
+ $src_contacts[$contact_id], false)) {
|
|
||||||
$ret = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->Lease->updateAll
|
|
||||||
(array('Lease.customer_id' => $dst_id),
|
|
||||||
array('Lease.customer_id' => $src_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->Tender->updateAll
|
|
||||||
(array('Tender.customer_id' => $dst_id),
|
|
||||||
array('Tender.customer_id' => $src_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->StatementEntry->updateAll
|
|
||||||
(array('StatementEntry.customer_id' => $dst_id),
|
|
||||||
array('StatementEntry.customer_id' => $src_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->Transaction->updateAll
|
|
||||||
(array('Transaction.customer_id' => $dst_id),
|
|
||||||
array('Transaction.customer_id' => $src_id)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Make sure our lease counts, etc are correct
|
|
||||||
$this->update($dst_id);
|
|
||||||
|
|
||||||
// Delete the old customer
|
|
||||||
$this->pr(12, compact('src_id'), "Delete Customer");
|
|
||||||
$this->delete($src_id);
|
|
||||||
|
|
||||||
// Delete all the orphaned customers
|
|
||||||
foreach (array_diff(array_keys($src_contacts), $all_contacts) AS $contact_id) {
|
|
||||||
// Delete un-used or duplicate contacts
|
|
||||||
// REVISIT <AP> 20100702:
|
|
||||||
// Not sure if we really want to do this.
|
|
||||||
// On the one hand, they're probably really redundant,
|
|
||||||
// and only clutter up the list of all contacts. On the
|
|
||||||
// other hand, it destroys data, not only losing the
|
|
||||||
// history, but making it difficult to recover if the
|
|
||||||
// merge is a mistake. Additionally, we need to do
|
|
||||||
// extra checking to ensure that the contact is not
|
|
||||||
// in use by some other customer.
|
|
||||||
// We need some sort of Contact.deleted field...
|
|
||||||
$this->pr(12, compact('contact_id'), "Delete Contact");
|
|
||||||
$this->Contact->delete($contact_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, delete all customer contact relationships
|
|
||||||
$this->ContactsCustomer->deleteAll
|
|
||||||
(array('customer_id' => $src_id), false);
|
|
||||||
|
|
||||||
// Return the result
|
|
||||||
return $this->prReturn($ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: updateLeaseCount
|
|
||||||
* - Updates the internal lease count
|
|
||||||
*/
|
|
||||||
|
|
||||||
function updateLeaseCount($id) {
|
|
||||||
$this->id = $id;
|
|
||||||
|
|
||||||
$lease_count =
|
|
||||||
$this->find('count',
|
|
||||||
array('link' => array('Lease' => array('type' => 'INNER')),
|
|
||||||
'conditions' => array('Customer.id' => $id)));
|
|
||||||
$current_count =
|
|
||||||
$this->find('count',
|
|
||||||
array('link' => array('CurrentLease' => array('type' => 'INNER')),
|
|
||||||
'conditions' => array('Customer.id' => $id)));
|
|
||||||
|
|
||||||
$this->saveField('lease_count', $lease_count);
|
|
||||||
$this->saveField('current_lease_count', $current_count);
|
|
||||||
$this->saveField('past_lease_count', $lease_count - $current_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: balance
|
|
||||||
* - Returns the balance of money owed on the lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function balance($id) {
|
|
||||||
$stats = $this->stats($id);
|
|
||||||
return $stats['balance'];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: stats
|
|
||||||
* - Returns summary data from the requested customer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function stats($id = null, $query = null) {
|
|
||||||
//$this->prFunctionLevel(20);
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
if (!$id)
|
|
||||||
return $this->prExit(null);
|
|
||||||
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090725
|
|
||||||
// We'll need to go directly to the statement entries if
|
|
||||||
// transactions are not always associated with the customer.
|
|
||||||
// This could happen if either we remove the customer_id
|
|
||||||
// field from Transaction, or we allow multiple customers
|
|
||||||
// to be part of the same transaction (essentially making
|
|
||||||
// the Transaction.customer_id meaningless).
|
|
||||||
|
|
||||||
/* $stats = $this->StatementEntry->find */
|
|
||||||
/* ('first', array */
|
|
||||||
/* ('contain' => false, */
|
|
||||||
/* 'fields' => $this->StatementEntry->chargeDisbursementFields(true), */
|
|
||||||
/* 'conditions' => array('StatementEntry.customer_id' => $id), */
|
|
||||||
/* )); */
|
|
||||||
|
|
||||||
$find_stats = $this->StatementEntry->find
|
|
||||||
('first', array
|
|
||||||
('contain' => false,
|
|
||||||
'fields' => $this->StatementEntry->chargeDisbursementFields(true),
|
|
||||||
'conditions' => array('StatementEntry.customer_id' => $id),
|
|
||||||
));
|
|
||||||
$find_stats = $find_stats[0];
|
|
||||||
$this->pr(17, compact('find_stats'));
|
|
||||||
|
|
||||||
$tquery = $query;
|
|
||||||
$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
||||||
$statement_stats = $this->StatementEntry->stats(null, $tquery);
|
|
||||||
$statement_stats['balance'] = $statement_stats['Charge']['balance'];
|
|
||||||
$this->pr(17, compact('statement_stats'));
|
|
||||||
|
|
||||||
$tquery = $query;
|
|
||||||
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
||||||
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
|
||||||
$transaction_stats = $this->Transaction->stats(null, $tquery);
|
|
||||||
$transaction_stats += $transaction_stats['StatementEntry'];
|
|
||||||
$this->pr(17, compact('transaction_stats'));
|
|
||||||
|
|
||||||
$tquery = $query;
|
|
||||||
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
|
||||||
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
|
||||||
$ar_transaction_stats = $this->Transaction->stats(null, $tquery,
|
|
||||||
$this->Transaction->Account->accountReceivableAccountID());
|
|
||||||
$ar_transaction_stats += $ar_transaction_stats['LedgerEntry'];
|
|
||||||
$this->pr(17, compact('ar_transaction_stats'));
|
|
||||||
|
|
||||||
//$stats = $ar_transaction_stats;
|
|
||||||
$stats = $find_stats;
|
|
||||||
return $this->prReturn($stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
class DefaultOption extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('OptionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($name = null) {
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['DefaultOption'] = array();
|
|
||||||
$query['link']['DefaultOption']['type'] = 'INNER';
|
|
||||||
$query['link']['DefaultOption']['fields'] = array();
|
|
||||||
return $this->prReturn($this->OptionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
class DefaultPermission extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('PermissionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($name = null) {
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['DefaultPermission'] = array();
|
|
||||||
$query['link']['DefaultPermission']['type'] = 'INNER';
|
|
||||||
$query['link']['DefaultPermission']['fields'] = array();
|
|
||||||
return $this->prReturn($this->PermissionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Group extends AppModel {
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array('GroupOption',
|
|
||||||
'Membership',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $knows =
|
|
||||||
array('User',
|
|
||||||
'Site',
|
|
||||||
);
|
|
||||||
|
|
||||||
static $current_group_ids;
|
|
||||||
function currentGroupIds() {
|
|
||||||
if (empty(self::$current_group_ids))
|
|
||||||
self::$current_group_ids = $this->groupIds();
|
|
||||||
|
|
||||||
if (empty(self::$current_group_ids))
|
|
||||||
// We must force a stop here, since this is typically
|
|
||||||
// called very early on, and so will cause a recursive
|
|
||||||
// crash as we try to render the internal error and
|
|
||||||
// again stumble on this problem.
|
|
||||||
$this->INTERNAL_ERROR('INVALID MEMBERSHIP', 0, true);
|
|
||||||
|
|
||||||
return self::$current_group_ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
function groupIds($user_id = null, $site_id = null) {
|
|
||||||
if (empty($user_id))
|
|
||||||
$user_id = $this->User->currentUserId();
|
|
||||||
if (empty($site_id))
|
|
||||||
$site_id = $this->Site->currentSiteId();
|
|
||||||
|
|
||||||
return $this->Membership->memberGroups($user_id, $site_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
class GroupOption extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('Group',
|
|
||||||
'OptionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($ids, $name = null) {
|
|
||||||
$this->prEnter(compact('id', 'name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['GroupOption'] = array();
|
|
||||||
$query['link']['GroupOption']['fields'] = array();
|
|
||||||
$query['link']['GroupOption']['Group'] = array();
|
|
||||||
$query['link']['GroupOption']['Group']['fields'] = array();
|
|
||||||
$query['conditions'][] = array('Group.id' => $ids);
|
|
||||||
$query['order'][] = 'Group.rank';
|
|
||||||
return $this->prReturn($this->OptionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
class GroupPermission extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('Group',
|
|
||||||
'PermissionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($ids, $name = null) {
|
|
||||||
$this->prEnter(compact('id', 'name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['GroupPermission'] = array();
|
|
||||||
$query['link']['GroupPermission']['fields'] = array();
|
|
||||||
$query['link']['GroupPermission']['Group'] = array();
|
|
||||||
$query['link']['GroupPermission']['Group']['fields'] = array();
|
|
||||||
$query['conditions'][] = array('Group.id' => $ids);
|
|
||||||
$query['order'][] = 'Group.rank';
|
|
||||||
return $this->prReturn($this->PermissionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,851 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Lease extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo = array(
|
|
||||||
'LeaseType',
|
|
||||||
'Unit',
|
|
||||||
'Customer',
|
|
||||||
'LateSchedule',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasMany = array(
|
|
||||||
'StatementEntry',
|
|
||||||
);
|
|
||||||
|
|
||||||
//var $default_log_level = array('log' => 30, 'show' => 30);
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: securityDeposits
|
|
||||||
* - Returns an array of security deposit entries
|
|
||||||
*/
|
|
||||||
function securityDeposits($id, $query = null) {
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
|
||||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
|
||||||
$this->StatementEntry->Account->securityDepositAccountID());
|
|
||||||
|
|
||||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
|
||||||
return $this->prReturn($set);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: securityDepositBalance
|
|
||||||
* - Returns the balance of the lease security deposit(s)
|
|
||||||
*/
|
|
||||||
|
|
||||||
function securityDepositBalance($id, $query = null) {
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090807
|
|
||||||
// Let's try simplifying the security deposit issue.
|
|
||||||
// Presume that security deposits are NOT used at all,
|
|
||||||
// until the customer moves out of the unit. At that
|
|
||||||
// time, the ENTIRE deposit is converted to customer
|
|
||||||
// credit. Piece of cake.
|
|
||||||
// For more information, see file revision history,
|
|
||||||
// including the revision just before this, r503.
|
|
||||||
|
|
||||||
$this->id = $id;
|
|
||||||
$moveout_date = $this->field('moveout_date');
|
|
||||||
if (!empty($moveout_date))
|
|
||||||
return $this->prReturn(0);
|
|
||||||
|
|
||||||
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
|
||||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
|
||||||
$this->StatementEntry->Account->securityDepositAccountID());
|
|
||||||
|
|
||||||
$stats = $this->StatementEntry->stats(null, $query);
|
|
||||||
return $this->prReturn($stats['Charge']['disbursement']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: releaseSecurityDeposits
|
|
||||||
* - Releases all security deposits associated with this lease.
|
|
||||||
* That simply makes a disbursement out of them, which can be used
|
|
||||||
* to pay outstanding customer charges, or simply to become
|
|
||||||
* a customer surplus (customer credit).
|
|
||||||
*/
|
|
||||||
function releaseSecurityDeposits($id, $stamp = null, $query = null) {
|
|
||||||
//$this->prFunctionLevel(30);
|
|
||||||
$this->prEnter(compact('id', 'stamp', 'query'));
|
|
||||||
|
|
||||||
$secdeps = $this->securityDeposits($id, $query);
|
|
||||||
$secdeps = $secdeps['entries'];
|
|
||||||
$this->pr(20, compact('secdeps'));
|
|
||||||
|
|
||||||
// If there are no paid security deposits, then
|
|
||||||
// we can consider all security deposits released.
|
|
||||||
if (count($secdeps) == 0)
|
|
||||||
return $this->prReturn(true);
|
|
||||||
|
|
||||||
// Build a transaction
|
|
||||||
$release = array('Transaction' => array(), 'Entry' => array());
|
|
||||||
$release['Transaction']['stamp'] = $stamp;
|
|
||||||
$release['Transaction']['comment'] = "Security Deposit Release";
|
|
||||||
foreach ($secdeps AS $charge) {
|
|
||||||
if ($charge['StatementEntry']['type'] !== 'CHARGE')
|
|
||||||
die("INTERNAL ERROR: SECURITY DEPOSIT IS NOT CHARGE");
|
|
||||||
|
|
||||||
// Since security deposits are being released, this also means
|
|
||||||
// any unpaid (or only partially paid) security deposit should
|
|
||||||
// have the remaining balance reversed.
|
|
||||||
if ($charge['StatementEntry']['balance'] > 0)
|
|
||||||
$this->StatementEntry->reverse($charge['StatementEntry']['id'], true, $stamp);
|
|
||||||
|
|
||||||
$release['Entry'][] =
|
|
||||||
array('amount' => $charge['StatementEntry']['reconciled'],
|
|
||||||
'account_id' => $this->StatementEntry->Account->securityDepositAccountID(),
|
|
||||||
'comment' => "Released Security Deposit",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$customer_id = $secdeps[0]['StatementEntry']['customer_id'];
|
|
||||||
$lease_id = $secdeps[0]['StatementEntry']['lease_id'];
|
|
||||||
|
|
||||||
// Add receipt of the security deposit funds. Do NOT
|
|
||||||
// flag them as part of the lease, as all received funds
|
|
||||||
// are only associated with the customer, for future
|
|
||||||
// (or present) disbursement on any lease.
|
|
||||||
$result = $this->StatementEntry->Transaction->addReceipt
|
|
||||||
($release, $customer_id, null);
|
|
||||||
|
|
||||||
return $this->prReturn($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: rentLastCharges
|
|
||||||
* - Returns a list of rent charges from this lease that
|
|
||||||
* do not have sequential followup charges. Under normal
|
|
||||||
* circumstances, there would only be one entry, which is
|
|
||||||
* the most recent rent charge. However, it's possible
|
|
||||||
* that there are several, indicating a problem with lease.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function rentLastCharges($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
|
|
||||||
$entries = $this->find
|
|
||||||
('all',
|
|
||||||
array('link' =>
|
|
||||||
array(// Models
|
|
||||||
'StatementEntry',
|
|
||||||
|
|
||||||
'SEx' =>
|
|
||||||
array('class' => 'StatementEntry',
|
|
||||||
'fields' => array(),
|
|
||||||
'conditions' => array
|
|
||||||
('SEx.lease_id = StatementEntry.lease_id',
|
|
||||||
'SEx.type' => 'CHARGE',
|
|
||||||
'SEx.account_id' => $rent_account_id,
|
|
||||||
'SEx.reverse_transaction_id IS NULL',
|
|
||||||
'SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
|
||||||
'fields' => array(),
|
|
||||||
'conditions' => array(array('Lease.id' => $id),
|
|
||||||
array('StatementEntry.type' => 'CHARGE'),
|
|
||||||
array('StatementEntry.account_id' => $rent_account_id),
|
|
||||||
array('StatementEntry.reverse_transaction_id IS NULL'),
|
|
||||||
array('SEx.id' => null),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->prReturn($entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: lateCharges
|
|
||||||
* - Returns a list of late charges from this lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function lateCharges($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$late_account_id = $this->StatementEntry->Account->lateChargeAccountID();
|
|
||||||
$entries = $this->StatementEntry->find
|
|
||||||
('all',
|
|
||||||
array('link' =>
|
|
||||||
array(// Models
|
|
||||||
'Lease',
|
|
||||||
),
|
|
||||||
|
|
||||||
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
|
||||||
'conditions' => array(array('Lease.id' => $id),
|
|
||||||
array('StatementEntry.type' => 'CHARGE'),
|
|
||||||
array('StatementEntry.account_id' => $late_account_id),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return $this->prReturn($entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: rentChargeGaps
|
|
||||||
* - Checks for gaps in rent charges
|
|
||||||
*/
|
|
||||||
|
|
||||||
function rentChargeGaps($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$entries = $this->rentLastCharges($id);
|
|
||||||
if ($entries && count($entries) > 1)
|
|
||||||
return $this->prReturn(true);
|
|
||||||
return $this->prReturn(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: rentChargeThrough
|
|
||||||
* - Determines the date that rent has been charged through
|
|
||||||
* Returns one of:
|
|
||||||
* null: There are gaps in the charges
|
|
||||||
* false: There are not yet any charges
|
|
||||||
* date: The date rent has been charged through
|
|
||||||
*/
|
|
||||||
|
|
||||||
function rentChargeThrough($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$entries = $this->rentLastCharges($id);
|
|
||||||
if (!$entries)
|
|
||||||
return $this->prReturn(false);
|
|
||||||
if (count($entries) != 1)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
return $this->prReturn($entries[0]['StatementEntry']['through_date']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: rentPaidThrough
|
|
||||||
* - Determines the date of the first unpaid rent
|
|
||||||
*/
|
|
||||||
|
|
||||||
function rentPaidThrough($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
|
|
||||||
|
|
||||||
// First, see if we can find any unpaid entries. Of course,
|
|
||||||
// the first unpaid entry gives us a very direct indication
|
|
||||||
// of when the customer is paid up through, which is 1 day
|
|
||||||
// prior to the effective date of that first unpaid charge.
|
|
||||||
$rent = $this->StatementEntry->reconciledSet
|
|
||||||
('CHARGE',
|
|
||||||
array('fields' =>
|
|
||||||
array('StatementEntry.*',
|
|
||||||
'DATE_SUB(StatementEntry.effective_date, INTERVAL 1 DAY) AS paid_through',
|
|
||||||
),
|
|
||||||
|
|
||||||
'conditions' =>
|
|
||||||
array(array('StatementEntry.lease_id' => $id),
|
|
||||||
array('StatementEntry.account_id' => $rent_account_id),
|
|
||||||
array('StatementEntry.reverse_transaction_id IS NULL'),
|
|
||||||
),
|
|
||||||
|
|
||||||
'order' => array('StatementEntry.effective_date'),
|
|
||||||
),
|
|
||||||
true);
|
|
||||||
$this->pr(20, $rent, "Unpaid rent");
|
|
||||||
|
|
||||||
if ($rent['entries'])
|
|
||||||
return $this->prReturn($rent['entries'][0]['StatementEntry']['paid_through']);
|
|
||||||
|
|
||||||
|
|
||||||
// If we don't have any unpaid charges (great!), then the
|
|
||||||
// customer is paid up through the last day of the last
|
|
||||||
// charge. So, search for paid charges, which already
|
|
||||||
// have the paid through date saved as part of the entry.
|
|
||||||
$rent = $this->StatementEntry->reconciledSet
|
|
||||||
('CHARGE',
|
|
||||||
array('conditions' =>
|
|
||||||
array(array('StatementEntry.lease_id' => $id),
|
|
||||||
array('StatementEntry.account_id' => $rent_account_id),
|
|
||||||
array('StatementEntry.reverse_transaction_id IS NULL'),
|
|
||||||
),
|
|
||||||
|
|
||||||
'order' => array('StatementEntry.through_date DESC'),
|
|
||||||
),
|
|
||||||
false);
|
|
||||||
$this->pr(20, $rent, "Paid rent");
|
|
||||||
|
|
||||||
if ($rent['entries'])
|
|
||||||
return $this->prReturn($rent['entries'][0]['StatementEntry']['through_date']);
|
|
||||||
|
|
||||||
|
|
||||||
// After all that, having found that there are no unpaid
|
|
||||||
// charges, and in fact, no paid charges either, we cannot
|
|
||||||
// possibly say when the customer is paid through.
|
|
||||||
return $this->prReturn(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: assessMonthlyRent
|
|
||||||
* - Charges rent for the month, if not already charged.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function assessMonthlyRent($id, $date = null) {
|
|
||||||
$this->prEnter(compact('id', 'date'));
|
|
||||||
$this->id = $id;
|
|
||||||
|
|
||||||
if (empty($date))
|
|
||||||
$date = time();
|
|
||||||
|
|
||||||
if (is_string($date))
|
|
||||||
$date = strtotime($date);
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090808
|
|
||||||
// Anniversary Billing not supported
|
|
||||||
$anniversary = 0 && $this->field('anniversary_billing');
|
|
||||||
if (empty($anniversary)) {
|
|
||||||
$date_parts = getdate($date);
|
|
||||||
$date = mktime(0, 0, 0, $date_parts['mon'], 1, $date_parts['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we're not trying to assess rent on a closed lease
|
|
||||||
$close_date = $this->field('close_date');
|
|
||||||
$this->pr(17, compact('close_date'));
|
|
||||||
if (!empty($close_date))
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// Don't assess rent after customer has moved out
|
|
||||||
$moveout_date = $this->field('moveout_date');
|
|
||||||
$this->pr(17, compact('moveout_date'));
|
|
||||||
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// Determine when the customer has already been charged through
|
|
||||||
// and, of course, don't charge them if they've already been.
|
|
||||||
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
|
||||||
$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 >= $date)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// OK, it seems we're going to go ahead and charge the customer
|
|
||||||
// on this lease. Calculate the new charge through date, which
|
|
||||||
// is 1 day shy of 1 month from $date. For example, if we're
|
|
||||||
// charging for 8/1/09, charge through will be 8/31/09, and
|
|
||||||
// charging for 8/15/09, charge through will be 9/14/09.
|
|
||||||
$date_parts = getdate($date);
|
|
||||||
$charge_through_date = mktime(0, 0, 0,
|
|
||||||
$date_parts['mon']+1,
|
|
||||||
$date_parts['mday']-1,
|
|
||||||
$date_parts['year']);
|
|
||||||
|
|
||||||
// Build the invoice transaction
|
|
||||||
$invoice = array('Transaction' => array(), 'Entry' => array());
|
|
||||||
// REVISIT <AP>: 20090808
|
|
||||||
// Keeping Transaction.stamp until the existing facility
|
|
||||||
// is up to date. Then we want the stamp to be now()
|
|
||||||
// (and so can just delete the next line).
|
|
||||||
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
|
||||||
$invoice['Entry'][] =
|
|
||||||
array('effective_date' => date('Y-m-d', $date),
|
|
||||||
'through_date' => date('Y-m-d', $charge_through_date),
|
|
||||||
'amount' => $this->field('rent'),
|
|
||||||
'account_id' => $this->StatementEntry->Account->rentAccountId(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Record the invoice and return the result
|
|
||||||
$this->pr(21, compact('invoice'));
|
|
||||||
$result = $this->StatementEntry->Transaction->addInvoice
|
|
||||||
($invoice, null, $id);
|
|
||||||
return $this->prReturn($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: assessMonthlyRentAll
|
|
||||||
* - Ensures rent has been charged on all open leases
|
|
||||||
*/
|
|
||||||
|
|
||||||
function assessMonthlyRentAll($date = null) {
|
|
||||||
$this->prEnter(compact('date'));
|
|
||||||
$leases = $this->find
|
|
||||||
('all', array('contain' => false,
|
|
||||||
'conditions' => array('Lease.close_date' => null),
|
|
||||||
));
|
|
||||||
|
|
||||||
$ret = array('Lease' => array());
|
|
||||||
foreach ($leases AS $lease) {
|
|
||||||
$result = $this->assessMonthlyRent($lease['Lease']['id'], $date);
|
|
||||||
$ret['Lease'][$lease['Lease']['id']] = $result;
|
|
||||||
if ($result['error'])
|
|
||||||
$ret['error'] = true;
|
|
||||||
}
|
|
||||||
return $this->prReturn($ret + array('error' => false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: assessMonthlyLate
|
|
||||||
* - Assess late charges for the month, if not already charged.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function assessMonthlyLate($id, $date = null) {
|
|
||||||
$this->prEnter(compact('id', 'date'));
|
|
||||||
$this->id = $id;
|
|
||||||
|
|
||||||
if (empty($date))
|
|
||||||
$date = time();
|
|
||||||
|
|
||||||
if (is_string($date))
|
|
||||||
$date = strtotime($date);
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090808
|
|
||||||
// Anniversary Billing not supported
|
|
||||||
$anniversary = 0 && $this->field('anniversary_billing');
|
|
||||||
if (empty($anniversary)) {
|
|
||||||
$date_parts = getdate($date);
|
|
||||||
$date = mktime(0, 0, 0, $date_parts['mon'], 11, $date_parts['year']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't assess a late charge if the late charge date hasn't
|
|
||||||
// even come yet. This is questionable whether we really
|
|
||||||
// should restrict, since the user could know what they're
|
|
||||||
// doing, and/or the server clock could be off (although that
|
|
||||||
// would certainly have much larger ramifications). But, the
|
|
||||||
// fact is that this check likely handles the vast majority
|
|
||||||
// of the expected behavior, and presents an issue for very
|
|
||||||
// few users, if any at all.
|
|
||||||
if ($date > time())
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// Make sure we're not trying to assess late charges on a closed lease
|
|
||||||
$close_date = $this->field('close_date');
|
|
||||||
$this->pr(17, compact('close_date'));
|
|
||||||
if (!empty($close_date))
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// Don't assess late charges after customer has moved out
|
|
||||||
$moveout_date = $this->field('moveout_date');
|
|
||||||
$this->pr(17, compact('moveout_date'));
|
|
||||||
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// Determine when the customer has been charged through for rent
|
|
||||||
// and don't mark them as late if they haven't even been charged rent
|
|
||||||
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
|
||||||
$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 <= $date)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// Determine if the customer is actually late. This is based on
|
|
||||||
// when they've paid through, plus 10 days before they're late.
|
|
||||||
// REVISIT <AP>: 20090813
|
|
||||||
// Of course, 10 days is a terrible hardcode. This should be
|
|
||||||
// driven from the late schedule, saved as part of the lease
|
|
||||||
// (when finally implemented).
|
|
||||||
$paid_through_date = strtotime($this->rentPaidThrough($id));
|
|
||||||
$this->pr(17, compact('date', 'paid_through_date')
|
|
||||||
+ array('date_str' => date('Y-m-d', $date),
|
|
||||||
'paid_through_date_str' => date('Y-m-d', $paid_through_date)));
|
|
||||||
$date_parts = getdate($paid_through_date);
|
|
||||||
$paid_through_date = mktime(0, 0, 0, $date_parts['mon'], $date_parts['mday']+10, $date_parts['year']);
|
|
||||||
if ($paid_through_date >= $date)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
// Determine if the customer has already been charged a late fee
|
|
||||||
// and, of course, don't charge them if they've already been.
|
|
||||||
$late_charges = $this->lateCharges($id);
|
|
||||||
foreach ($late_charges AS $late) {
|
|
||||||
if (strtotime($late['StatementEntry']['effective_date']) == $date)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the invoice transaction
|
|
||||||
$invoice = array('Transaction' => array(), 'Entry' => array());
|
|
||||||
// REVISIT <AP>: 20090808
|
|
||||||
// Keeping Transaction.stamp until the existing facility
|
|
||||||
// is up to date. Then we want the stamp to be now()
|
|
||||||
// (and so can just delete the next line).
|
|
||||||
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
|
||||||
$invoice['Entry'][] =
|
|
||||||
array('effective_date' => date('Y-m-d', $date),
|
|
||||||
'amount' => 10,
|
|
||||||
'account_id' => $this->StatementEntry->Account->lateChargeAccountId(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Record the invoice and return the result
|
|
||||||
$this->pr(21, compact('invoice'));
|
|
||||||
$result = $this->StatementEntry->Transaction->addInvoice
|
|
||||||
($invoice, null, $id);
|
|
||||||
return $this->prReturn($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: assessMonthlyLateAll
|
|
||||||
* - Ensures rent has been charged on all open leases
|
|
||||||
*/
|
|
||||||
|
|
||||||
function assessMonthlyLateAll($date = null) {
|
|
||||||
$this->prEnter(compact('date'));
|
|
||||||
$leases = $this->find
|
|
||||||
('all', array('contain' => false,
|
|
||||||
'conditions' => array('Lease.close_date' => null),
|
|
||||||
));
|
|
||||||
|
|
||||||
$ret = array('Lease' => array());
|
|
||||||
foreach ($leases AS $lease) {
|
|
||||||
$result = $this->assessMonthlyLate($lease['Lease']['id'], $date);
|
|
||||||
$ret['Lease'][$lease['Lease']['id']] = $result;
|
|
||||||
if ($result['error'])
|
|
||||||
$ret['error'] = true;
|
|
||||||
}
|
|
||||||
return $this->prReturn($ret + array('error' => false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* functions: delinquency
|
|
||||||
* - SQL fragments to determine whether a lease is delinquent
|
|
||||||
*/
|
|
||||||
|
|
||||||
function conditionDelinquent($table_name = 'Lease') {
|
|
||||||
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
|
||||||
return ("({$t}close_date IS NULL AND" .
|
|
||||||
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 1 DAY))");
|
|
||||||
}
|
|
||||||
|
|
||||||
function delinquentDaysSQL($table_name = 'Lease') {
|
|
||||||
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
|
||||||
return ("IF(" . $this->conditionDelinquent($table_name) . "," .
|
|
||||||
" DATEDIFF(NOW(), {$t}paid_through_date)-1," .
|
|
||||||
" NULL)");
|
|
||||||
}
|
|
||||||
|
|
||||||
function delinquentField($table_name = 'Lease') {
|
|
||||||
return ($this->delinquentDaysSQL($table_name) . " AS 'delinquent'");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: moveIn
|
|
||||||
* - Moves the specified customer into the specified lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function moveIn($customer_id, $unit_id,
|
|
||||||
$deposit = null, $rent = null,
|
|
||||||
$stamp = null, $comment = null)
|
|
||||||
{
|
|
||||||
$this->prEnter(compact('customer_id', 'unit_id',
|
|
||||||
'deposit', 'rent', 'stamp', 'comment'));
|
|
||||||
|
|
||||||
$lt = $this->LeaseType->find('first',
|
|
||||||
array('conditions' =>
|
|
||||||
array('code' => 'SL')));
|
|
||||||
|
|
||||||
// Use NOW if not given a movein date
|
|
||||||
if (!isset($stamp))
|
|
||||||
$stamp = date('Y-m-d G:i:s');
|
|
||||||
|
|
||||||
if (!$comment)
|
|
||||||
$comment = null;
|
|
||||||
|
|
||||||
if (!isset($deposit) || !isset($rent)) {
|
|
||||||
$rates = $this->Unit->find
|
|
||||||
('first',
|
|
||||||
array('contain' =>
|
|
||||||
array('UnitSize' =>
|
|
||||||
array('deposit', 'rent'),
|
|
||||||
),
|
|
||||||
'fields' => array('deposit', 'rent'),
|
|
||||||
'conditions' => array('Unit.id' => $unit_id),
|
|
||||||
));
|
|
||||||
|
|
||||||
$deposit =
|
|
||||||
(isset($deposit)
|
|
||||||
? $deposit
|
|
||||||
: (isset($rates['Unit']['deposit'])
|
|
||||||
? $rates['Unit']['deposit']
|
|
||||||
: (isset($rates['UnitSize']['deposit'])
|
|
||||||
? $rates['UnitSize']['deposit']
|
|
||||||
: 0)));
|
|
||||||
|
|
||||||
$rent =
|
|
||||||
(isset($rent)
|
|
||||||
? $rent
|
|
||||||
: (isset($rates['Unit']['rent'])
|
|
||||||
? $rates['Unit']['rent']
|
|
||||||
: (isset($rates['UnitSize']['rent'])
|
|
||||||
? $rates['UnitSize']['rent']
|
|
||||||
: 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Save this new lease.
|
|
||||||
$this->create();
|
|
||||||
if (!$this->save(array('lease_type_id' => $lt['LeaseType']['id'],
|
|
||||||
'unit_id' => $unit_id,
|
|
||||||
'customer_id' => $customer_id,
|
|
||||||
'lease_date' => $stamp,
|
|
||||||
'movein_date' => $stamp,
|
|
||||||
'deposit' => $deposit,
|
|
||||||
'rent' => $rent,
|
|
||||||
'comment' => $comment), false)) {
|
|
||||||
return $this->prReturn(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the lease number to be the same as the lease ID
|
|
||||||
$this->id;
|
|
||||||
$this->saveField('number', $this->id);
|
|
||||||
|
|
||||||
// Update the current lease count for the customer
|
|
||||||
$this->Customer->updateLeaseCount($customer_id);
|
|
||||||
|
|
||||||
// Update the unit status
|
|
||||||
$this->Unit->updateStatus($unit_id, 'OCCUPIED');
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090702
|
|
||||||
// We need to assess the security deposit charge,
|
|
||||||
// and probably rent as well. Rent, however, will
|
|
||||||
// require user parameters to indicate whether it
|
|
||||||
// was waived, pro-rated, etc.
|
|
||||||
|
|
||||||
// Return the new lease ID
|
|
||||||
return $this->prReturn($this->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: moveOut
|
|
||||||
* - Moves the customer out of the specified lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function moveOut($id, $status = 'VACANT',
|
|
||||||
$stamp = null, $close = true)
|
|
||||||
{
|
|
||||||
$this->prEnter(compact('id', 'status', 'stamp', 'close'));
|
|
||||||
|
|
||||||
// Use NOW if not given a moveout date
|
|
||||||
if (!isset($stamp))
|
|
||||||
$stamp = date('Y-m-d G:i:s');
|
|
||||||
|
|
||||||
// Reset the data
|
|
||||||
$this->create();
|
|
||||||
$this->id = $id;
|
|
||||||
|
|
||||||
// Set the customer move-out date
|
|
||||||
$this->data['Lease']['moveout_date'] = $stamp;
|
|
||||||
|
|
||||||
// Save it!
|
|
||||||
$this->save($this->data, false);
|
|
||||||
|
|
||||||
// Release the security deposit(s)
|
|
||||||
$this->releaseSecurityDeposits($id, $stamp);
|
|
||||||
|
|
||||||
// Close the lease, if so requested
|
|
||||||
if ($close)
|
|
||||||
$this->close($id, $stamp);
|
|
||||||
|
|
||||||
// Update the current lease count for the customer
|
|
||||||
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
|
||||||
|
|
||||||
// Finally, update the unit status
|
|
||||||
$this->recursive = -1;
|
|
||||||
$this->read();
|
|
||||||
$this->Unit->updateStatus($this->data['Lease']['unit_id'], $status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: close
|
|
||||||
* - Closes the lease to further action
|
|
||||||
*/
|
|
||||||
|
|
||||||
function close($id, $stamp = null) {
|
|
||||||
$this->prEnter(compact('id', 'stamp'));
|
|
||||||
|
|
||||||
if (!$this->closeable($id))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
// Reset the data
|
|
||||||
$this->create();
|
|
||||||
$this->id = $id;
|
|
||||||
|
|
||||||
// Use NOW if not given a moveout date
|
|
||||||
if (!isset($stamp))
|
|
||||||
$stamp = date('Y-m-d G:i:s');
|
|
||||||
|
|
||||||
// Set the close date
|
|
||||||
$this->data['Lease']['close_date'] = $stamp;
|
|
||||||
|
|
||||||
// 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: closeable
|
|
||||||
* - Indicates whether or not the lease can be closed
|
|
||||||
*/
|
|
||||||
|
|
||||||
function closeable($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
|
|
||||||
$this->recursive = -1;
|
|
||||||
$this->read(null, $id);
|
|
||||||
|
|
||||||
// We can't close a lease that's still in use
|
|
||||||
if (!isset($this->data['Lease']['moveout_date']))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
// We can't close a lease that's already closed
|
|
||||||
if (isset($this->data['Lease']['close_date']))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
// A lease can only be closed if there are no outstanding
|
|
||||||
// security deposits ...
|
|
||||||
if ($this->securityDepositBalance($id) != 0)
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
// ... and if the account balance is zero.
|
|
||||||
if ($this->balance($id) != 0)
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
// Apparently this lease meets all the criteria!
|
|
||||||
return $this->prReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: refund
|
|
||||||
* - Marks any lease balance as payable to the customer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function refund($id, $stamp = null) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$balance = $this->balance($id);
|
|
||||||
|
|
||||||
if ($balance >= 0)
|
|
||||||
return $this->prReturn(array('error' => true));
|
|
||||||
|
|
||||||
$balance *= -1;
|
|
||||||
|
|
||||||
// Build a transaction
|
|
||||||
$refund = array('Transaction' => array(), 'Entry' => array());
|
|
||||||
$refund['Transaction']['stamp'] = $stamp;
|
|
||||||
$refund['Transaction']['comment'] = "Lease Refund";
|
|
||||||
|
|
||||||
$refund['Entry'][] =
|
|
||||||
array('amount' => $balance);
|
|
||||||
|
|
||||||
$result = $this->StatementEntry->Transaction->addRefund
|
|
||||||
($refund, null, $id);
|
|
||||||
|
|
||||||
return $this->prReturn($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: update
|
|
||||||
* - Update any cached or calculated fields
|
|
||||||
*/
|
|
||||||
function update($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
|
|
||||||
$this->id = $id;
|
|
||||||
$this->saveField('charge_through_date', $this->rentChargeThrough($id));
|
|
||||||
$this->saveField('paid_through_date', $this->rentPaidThrough($id));
|
|
||||||
|
|
||||||
$moveout = $this->field('moveout_date');
|
|
||||||
if (empty($moveout))
|
|
||||||
$this->Unit->update($this->field('unit_id'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: balance
|
|
||||||
* - Returns the balance of money owed on the lease
|
|
||||||
*/
|
|
||||||
|
|
||||||
function balance($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$stats = $this->stats($id);
|
|
||||||
return $this->prReturn($stats['balance']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: stats
|
|
||||||
* - Returns summary data from the requested lease.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function stats($id = null, $query = null) {
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
if (!$id)
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
$find_stats = $this->StatementEntry->find
|
|
||||||
('first', array
|
|
||||||
('contain' => false,
|
|
||||||
'fields' => $this->StatementEntry->chargeDisbursementFields(true),
|
|
||||||
'conditions' => array('StatementEntry.lease_id' => $id),
|
|
||||||
));
|
|
||||||
$find_stats = $find_stats[0];
|
|
||||||
return $this->prReturn($find_stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Membership extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('User',
|
|
||||||
'Site',
|
|
||||||
'Group'
|
|
||||||
);
|
|
||||||
|
|
||||||
function memberGroups($user_id, $site_id) {
|
|
||||||
$this->prEnter(compact('user_id', 'site_id'));
|
|
||||||
|
|
||||||
$this->cacheQueries = true;
|
|
||||||
$groups = $this->find('all', array
|
|
||||||
('recursive' => -1,
|
|
||||||
'fields' => array('group_id'),
|
|
||||||
'conditions' => array(array('user_id' => $user_id),
|
|
||||||
array('site_id' => $site_id)),
|
|
||||||
));
|
|
||||||
$this->cacheQueries = false;
|
|
||||||
|
|
||||||
if (empty($groups))
|
|
||||||
return $this->prReturn(null);
|
|
||||||
|
|
||||||
$group_ids = array();
|
|
||||||
foreach ($groups AS $group)
|
|
||||||
$group_ids[] = $group['Membership']['group_id'];
|
|
||||||
|
|
||||||
return $this->prReturn($group_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
function memberOf($user_id, $site_id) {
|
|
||||||
$groups = $this->memberGroups($user_id, $site_id);
|
|
||||||
return (!empty($groups));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Option extends AppModel {
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array('OptionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $knows =
|
|
||||||
array('User', 'Site', 'Group');
|
|
||||||
|
|
||||||
|
|
||||||
static $option_set = array();
|
|
||||||
|
|
||||||
function getAll($name, $force = false) {
|
|
||||||
/* $this->prClassLevel(30); */
|
|
||||||
/* //$this->OptionValue->prClassLevel(30); */
|
|
||||||
/* $this->Group->Membership->prClassLevel(30); */
|
|
||||||
/* $this->OptionValue->SiteOption->prClassLevel(30); */
|
|
||||||
/* $this->OptionValue->UserOption->prClassLevel(30); */
|
|
||||||
/* $this->OptionValue->GroupOption->prClassLevel(30); */
|
|
||||||
/* $this->OptionValue->DefaultOption->prClassLevel(30); */
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
|
|
||||||
if (!empty(self::$option_set[$name]) && !$force)
|
|
||||||
return $this->prReturn(self::$option_set[$name]);
|
|
||||||
|
|
||||||
self::$option_set[$name] = array();
|
|
||||||
|
|
||||||
$site_id = $this->Site->currentSiteId();
|
|
||||||
$user_id = $this->User->currentUserId();
|
|
||||||
$group_ids = $this->Group->currentGroupIds();
|
|
||||||
|
|
||||||
/* $site_id = 2; */
|
|
||||||
/* $user_id = 4; */
|
|
||||||
/* $group_ids = $this->Group->groupIds($user_id, $site_id); */
|
|
||||||
|
|
||||||
if (!empty($site_id))
|
|
||||||
self::$option_set[$name] =
|
|
||||||
array_merge(self::$option_set[$name],
|
|
||||||
$this->OptionValue->SiteOption->values($site_id, $name));
|
|
||||||
|
|
||||||
if (!empty($user_id))
|
|
||||||
self::$option_set[$name] =
|
|
||||||
array_merge(self::$option_set[$name],
|
|
||||||
$this->OptionValue->UserOption->values($user_id, $name));
|
|
||||||
|
|
||||||
if (!empty($group_ids))
|
|
||||||
self::$option_set[$name] =
|
|
||||||
array_merge(self::$option_set[$name],
|
|
||||||
$this->OptionValue->GroupOption->values($group_ids, $name));
|
|
||||||
|
|
||||||
self::$option_set[$name] =
|
|
||||||
array_merge(self::$option_set[$name],
|
|
||||||
$this->OptionValue->DefaultOption->values($name));
|
|
||||||
|
|
||||||
return $this->prReturn(self::$option_set[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($name) {
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
$values = $this->getAll($name);
|
|
||||||
if (empty($values))
|
|
||||||
return null;
|
|
||||||
return $this->prReturn($values[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function enabled($name) {
|
|
||||||
$val = $this->get($name);
|
|
||||||
return (!empty($val));
|
|
||||||
}
|
|
||||||
|
|
||||||
function disabled($name) {
|
|
||||||
return (!$this->enabled($name));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
class OptionValue extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('Option',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array('UserOption',
|
|
||||||
'SiteOption',
|
|
||||||
'GroupOption',
|
|
||||||
'DefaultOption',
|
|
||||||
);
|
|
||||||
|
|
||||||
function values($name = null, $query = null) {
|
|
||||||
$this->prEnter(compact('name', 'query'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['Option'] = array();
|
|
||||||
|
|
||||||
if (!empty($name)) {
|
|
||||||
$query['conditions'][] = array('Option.name' => $name);
|
|
||||||
$query['link']['Option']['fields'] = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->cacheQueries = true;
|
|
||||||
$values = array();
|
|
||||||
foreach ($this->find('all', $query) AS $result)
|
|
||||||
$values[] = $result['OptionValue']['value'];
|
|
||||||
$this->cacheQueries = false;
|
|
||||||
|
|
||||||
return $this->prReturn($values);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Permission extends AppModel {
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array('PermissionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $knows =
|
|
||||||
array('User', 'Site', 'Group');
|
|
||||||
|
|
||||||
static $permission_set = array();
|
|
||||||
|
|
||||||
function getAll($name, $force = false) {
|
|
||||||
/* $this->prClassLevel(30); */
|
|
||||||
/* $this->PermissionValue->prClassLevel(30); */
|
|
||||||
/* $this->Group->Membership->prClassLevel(30); */
|
|
||||||
/* $this->PermissionValue->SitePermission->prClassLevel(30); */
|
|
||||||
/* $this->PermissionValue->UserPermission->prClassLevel(30); */
|
|
||||||
/* $this->PermissionValue->GroupPermission->prClassLevel(30); */
|
|
||||||
/* $this->PermissionValue->DefaultPermission->prClassLevel(30); */
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
|
|
||||||
if (!empty(self::$permission_set[$name]) && !$force)
|
|
||||||
return $this->prReturn(self::$permission_set[$name]);
|
|
||||||
|
|
||||||
self::$permission_set[$name] = array();
|
|
||||||
|
|
||||||
$site_id = $this->Site->currentSiteId();
|
|
||||||
$user_id = $this->User->currentUserId();
|
|
||||||
$group_ids = $this->Group->currentGroupIds();
|
|
||||||
|
|
||||||
/* $site_id = 1; */
|
|
||||||
/* $user_id = 2; */
|
|
||||||
/* $group_ids = $this->Group->groupIds($user_id, $site_id); */
|
|
||||||
|
|
||||||
if (empty($group_ids)) {
|
|
||||||
self::$permission_set[$name][$name][] = array('access' => 'DENY', 'level' => null);
|
|
||||||
$site_id = null;
|
|
||||||
$user_id = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($site_id))
|
|
||||||
self::$permission_set[$name] =
|
|
||||||
array_merge(self::$permission_set[$name],
|
|
||||||
$this->PermissionValue->SitePermission->values($site_id, $name));
|
|
||||||
|
|
||||||
if (!empty($user_id))
|
|
||||||
self::$permission_set[$name] =
|
|
||||||
array_merge(self::$permission_set[$name],
|
|
||||||
$this->PermissionValue->UserPermission->values($user_id, $name));
|
|
||||||
|
|
||||||
if (!empty($group_ids)) {
|
|
||||||
self::$permission_set[$name] =
|
|
||||||
array_merge(self::$permission_set[$name],
|
|
||||||
$this->PermissionValue->GroupPermission->values($group_ids, $name));
|
|
||||||
|
|
||||||
self::$permission_set[$name] =
|
|
||||||
array_merge(self::$permission_set[$name],
|
|
||||||
$this->PermissionValue->DefaultPermission->values($name));
|
|
||||||
|
|
||||||
self::$permission_set[$name][] = array('access' => 'ALLOW', 'level' => null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn(self::$permission_set[$name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function get($name) {
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090827
|
|
||||||
// This is a pretty crappy algorithm. How do we decide whether DENY really
|
|
||||||
// means DENY, or whether an ALLOW has priority.
|
|
||||||
// Oh well, it works for now...
|
|
||||||
|
|
||||||
$values = $this->getAll($name);
|
|
||||||
$result = array_shift($values);
|
|
||||||
|
|
||||||
foreach ($values AS $value)
|
|
||||||
if (empty($result['level']) || (!empty($value['level']) && $value['level'] < $result['level']))
|
|
||||||
$result['level'] = $value['level'];
|
|
||||||
|
|
||||||
if ($result['access'] !== 'ALLOW')
|
|
||||||
$result['level'] = 9999999;
|
|
||||||
|
|
||||||
return $this->prReturn($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
function allow($name) {
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
$result = $this->get($name);
|
|
||||||
return $this->prReturn($result['access'] === 'ALLOW');
|
|
||||||
}
|
|
||||||
|
|
||||||
function deny($name) {
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
return $this->prReturn(!$this->allow($name));
|
|
||||||
}
|
|
||||||
|
|
||||||
function level($name) {
|
|
||||||
$this->prEnter(compact('name'));
|
|
||||||
$result = $this->get($name);
|
|
||||||
return $this->prReturn($result['level']);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
class PermissionValue extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('Permission',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array('UserPermission',
|
|
||||||
'SitePermission',
|
|
||||||
'GroupPermission',
|
|
||||||
'DefaultPermission',
|
|
||||||
);
|
|
||||||
|
|
||||||
function values($name = null, $query = null) {
|
|
||||||
$this->prEnter(compact('name', 'query'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['Permission'] = array();
|
|
||||||
|
|
||||||
if (!empty($name)) {
|
|
||||||
$query['conditions'][] = array('Permission.name' => $name);
|
|
||||||
$query['link']['Permission']['fields'] = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->cacheQueries = true;
|
|
||||||
$values = array();
|
|
||||||
foreach ($this->find('all', $query) AS $result)
|
|
||||||
$values[] = array('access' => $result['PermissionValue']['access'],
|
|
||||||
'level' => $result['PermissionValue']['level']);
|
|
||||||
$this->cacheQueries = false;
|
|
||||||
|
|
||||||
return $this->prReturn($values);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Site extends AppModel {
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array('SiteArea',
|
|
||||||
'SiteOption',
|
|
||||||
'Membership',
|
|
||||||
);
|
|
||||||
|
|
||||||
static $current_site_id;
|
|
||||||
|
|
||||||
function currentSiteId() {
|
|
||||||
if (!empty(self::$current_site_id))
|
|
||||||
return self::$current_site_id;
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090827
|
|
||||||
// Must get the actual site
|
|
||||||
$code = 'VSS';
|
|
||||||
|
|
||||||
$site = $this->find
|
|
||||||
('first',
|
|
||||||
array('recursive' => -1,
|
|
||||||
'conditions' => compact('code')));
|
|
||||||
|
|
||||||
if (!empty($site['Site']['id']))
|
|
||||||
self::$current_site_id = $site['Site']['id'];
|
|
||||||
else
|
|
||||||
// We must force a stop here, since this is typically
|
|
||||||
// called very early on, and so will cause a recursive
|
|
||||||
// crash as we try to render the internal error and
|
|
||||||
// again stumble on this problem.
|
|
||||||
$this->INTERNAL_ERROR('UNKNOWN SITE', 0, true);
|
|
||||||
|
|
||||||
return self::$current_site_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
class SiteOption extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('Site',
|
|
||||||
'OptionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($id, $name = null) {
|
|
||||||
$this->prEnter(compact('id', 'name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['SiteOption'] = array();
|
|
||||||
$query['link']['SiteOption']['fields'] = array();
|
|
||||||
$query['link']['SiteOption']['Site'] = array();
|
|
||||||
$query['link']['SiteOption']['Site']['fields'] = array();
|
|
||||||
$query['conditions'][] = array('Site.id' => $id);
|
|
||||||
return $this->prReturn($this->OptionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
class SitePermission extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('Site',
|
|
||||||
'PermissionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($id, $name = null) {
|
|
||||||
$this->prEnter(compact('id', 'name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['SitePermission'] = array();
|
|
||||||
$query['link']['SitePermission']['fields'] = array();
|
|
||||||
$query['link']['SitePermission']['Site'] = array();
|
|
||||||
$query['link']['SitePermission']['Site']['fields'] = array();
|
|
||||||
$query['conditions'][] = array('Site.id' => $id);
|
|
||||||
return $this->prReturn($this->PermissionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,784 +0,0 @@
|
|||||||
<?php
|
|
||||||
class StatementEntry extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo = array(
|
|
||||||
'Transaction',
|
|
||||||
'Customer',
|
|
||||||
'Lease',
|
|
||||||
'Account',
|
|
||||||
|
|
||||||
// The charge to which this disbursement applies (if it is one)
|
|
||||||
'ChargeEntry' => array(
|
|
||||||
'className' => 'StatementEntry',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasMany = array(
|
|
||||||
// The disbursements that apply to this charge (if it is one)
|
|
||||||
'DisbursementEntry' => array(
|
|
||||||
'className' => 'StatementEntry',
|
|
||||||
'foreignKey' => 'charge_entry_id',
|
|
||||||
'dependent' => true,
|
|
||||||
),
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
//var $default_log_level = array('log' => 30, 'show' => 15);
|
|
||||||
var $max_log_level = 19;
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: debit/creditTypes
|
|
||||||
*/
|
|
||||||
|
|
||||||
function debitTypes() {
|
|
||||||
return array('CHARGE', 'PAYMENT', 'REFUND');
|
|
||||||
}
|
|
||||||
|
|
||||||
function creditTypes() {
|
|
||||||
return array('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS');
|
|
||||||
}
|
|
||||||
|
|
||||||
function voidTypes() {
|
|
||||||
return array('VOID');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: chargeDisbursementFields
|
|
||||||
*/
|
|
||||||
|
|
||||||
function chargeDisbursementFields($sum = false, $entry_name = 'StatementEntry') {
|
|
||||||
$debits = $this->debitTypes();
|
|
||||||
$credits = $this->creditTypes();
|
|
||||||
$voids = $this->voidTypes();
|
|
||||||
|
|
||||||
foreach ($debits AS &$enum)
|
|
||||||
$enum = "'" . $enum . "'";
|
|
||||||
foreach ($credits AS &$enum)
|
|
||||||
$enum = "'" . $enum . "'";
|
|
||||||
foreach ($voids AS &$enum)
|
|
||||||
$enum = "'" . $enum . "'";
|
|
||||||
|
|
||||||
$debit_set = implode(", ", $debits);
|
|
||||||
$credit_set = implode(", ", $credits);
|
|
||||||
$void_set = implode(", ", $voids);
|
|
||||||
|
|
||||||
$fields = array
|
|
||||||
(
|
|
||||||
($sum ? 'SUM(' : '') .
|
|
||||||
"IF({$entry_name}.type IN ({$debit_set})," .
|
|
||||||
" {$entry_name}.amount, NULL)" .
|
|
||||||
($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''),
|
|
||||||
|
|
||||||
($sum ? 'SUM(' : '') .
|
|
||||||
"IF({$entry_name}.type IN({$credit_set})," .
|
|
||||||
" {$entry_name}.amount, NULL)" .
|
|
||||||
($sum ? ')' : '') . ' AS disbursement' . ($sum ? 's' : ''),
|
|
||||||
|
|
||||||
($sum ? 'SUM(' : '') .
|
|
||||||
"IF({$entry_name}.type IN ({$debit_set}), 1," .
|
|
||||||
" IF({$entry_name}.type IN ({$credit_set}), -1, 0))" .
|
|
||||||
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
|
|
||||||
($sum ? ')' : '') . ' AS balance',
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($sum)
|
|
||||||
$fields[] = "COUNT({$entry_name}.id) AS entries";
|
|
||||||
|
|
||||||
return $fields;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: verifyStatementEntry
|
|
||||||
* - Verifies consistenty of new statement entry data
|
|
||||||
* (not in a pre-existing statement entry)
|
|
||||||
*/
|
|
||||||
function verifyStatementEntry($entry) {
|
|
||||||
$this->prFunctionLevel(10);
|
|
||||||
$this->prEnter(compact('entry'));
|
|
||||||
|
|
||||||
if (empty($entry['type']) ||
|
|
||||||
//empty($entry['effective_date']) ||
|
|
||||||
empty($entry['account_id']) ||
|
|
||||||
empty($entry['amount'])
|
|
||||||
) {
|
|
||||||
return $this->prReturn(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: addStatementEntry
|
|
||||||
* - Inserts new Statement Entry into the database
|
|
||||||
*/
|
|
||||||
function addStatementEntry($entry) {
|
|
||||||
$this->prEnter(compact('entry'));
|
|
||||||
|
|
||||||
$ret = array('data' => $entry);
|
|
||||||
if (!$this->verifyStatementEntry($entry))
|
|
||||||
return $this->prReturn(array('error' => true, 'verify_data' => $entry) + $ret);
|
|
||||||
|
|
||||||
$this->create();
|
|
||||||
if (!$this->save($entry))
|
|
||||||
return $this->prReturn(array('error' => true, 'save_data' => $entry) + $ret);
|
|
||||||
|
|
||||||
$ret['statement_entry_id'] = $this->id;
|
|
||||||
return $this->prReturn($ret + array('error' => false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: waive
|
|
||||||
* - Waives the charge balance
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function waive($id, $stamp = null) {
|
|
||||||
$this->prEnter(compact('id', 'stamp'));
|
|
||||||
|
|
||||||
// Get the basic information about the entry to be waived.
|
|
||||||
$this->recursive = -1;
|
|
||||||
$charge = $this->read(null, $id);
|
|
||||||
$charge = $charge['StatementEntry'];
|
|
||||||
|
|
||||||
if ($charge['type'] !== 'CHARGE')
|
|
||||||
$this->INTERNAL_ERROR("Waiver item is not CHARGE.");
|
|
||||||
|
|
||||||
// Query the stats to get the remaining balance
|
|
||||||
$stats = $this->stats($id);
|
|
||||||
|
|
||||||
// Build a transaction
|
|
||||||
$waiver = array('Transaction' => array(), 'Entry' => array());
|
|
||||||
$waiver['Transaction']['stamp'] = $stamp;
|
|
||||||
$waiver['Transaction']['comment'] = "Charge Waiver";
|
|
||||||
|
|
||||||
// Add the charge waiver
|
|
||||||
$waiver['Entry'][] =
|
|
||||||
array('amount' => $stats['Charge']['balance'],
|
|
||||||
'comment' => null,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Record the waiver transaction
|
|
||||||
return $this->prReturn($this->Transaction->addWaiver
|
|
||||||
($waiver, $id, $charge['customer_id'], $charge['lease_id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: reversable
|
|
||||||
* - Returns true if the charge can be reversed; false otherwise
|
|
||||||
*/
|
|
||||||
function reversable($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
|
|
||||||
if (empty($id))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
// Verify the item is an actual charge
|
|
||||||
$this->id = $id;
|
|
||||||
$charge_type = $this->field('type');
|
|
||||||
if ($charge_type !== 'CHARGE')
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
// Determine anything reconciled against the charge
|
|
||||||
$reverse_transaction_id = $this->field('reverse_transaction_id');
|
|
||||||
if (!empty($reverse_transaction_id))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
return $this->prReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: reverse
|
|
||||||
* - Reverses the charges
|
|
||||||
*/
|
|
||||||
function reverse($id, $stamp = null, $comment) {
|
|
||||||
$this->prEnter(compact('id', 'stamp'));
|
|
||||||
|
|
||||||
// Verify the item can be reversed
|
|
||||||
if (!$this->reversable($id))
|
|
||||||
$this->INTERNAL_ERROR("Item is not reversable.");
|
|
||||||
|
|
||||||
// Get the basic information about this charge
|
|
||||||
$charge = $this->find('first', array('contain' => true));
|
|
||||||
//$charge = $charge['StatementEntry'];
|
|
||||||
|
|
||||||
// Query the stats to get the remaining balance
|
|
||||||
$stats = $this->stats($id);
|
|
||||||
$charge['paid'] = $stats['Charge']['disbursement'];
|
|
||||||
|
|
||||||
// Record the reversal transaction
|
|
||||||
$result = $this->Transaction->addReversal
|
|
||||||
($charge, $stamp, $comment ? $comment : 'Charge Reversal');
|
|
||||||
|
|
||||||
if (empty($result['error'])) {
|
|
||||||
// Mark the charge as reversed
|
|
||||||
$this->id = $id;
|
|
||||||
$this->saveField('reverse_transaction_id', $result['transaction_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: reconciledSet
|
|
||||||
* - Returns the set of entries satisfying the given conditions,
|
|
||||||
* along with any entries that they reconcile
|
|
||||||
*/
|
|
||||||
function reconciledSetQuery($set, $query) {
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
if (in_array($set, $this->debitTypes()))
|
|
||||||
$query['link']['DisbursementEntry'] = array('fields' => array("SUM(DisbursementEntry.amount) AS reconciled"));
|
|
||||||
elseif (in_array($set, $this->creditTypes()))
|
|
||||||
$query['link']['ChargeEntry'] = array('fields' => array("SUM(ChargeEntry.amount) AS reconciled"));
|
|
||||||
else
|
|
||||||
die("INVALID RECONCILE SET");
|
|
||||||
|
|
||||||
$query['conditions'][] = array('StatementEntry.type' => $set);
|
|
||||||
$query['group'] = 'StatementEntry.id';
|
|
||||||
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reconciledSet($set, $query = null, $unrec = false, $if_rec_include_partial = false) {
|
|
||||||
//$this->prFunctionLevel(array('log' => 16, 'show' => 10));
|
|
||||||
$this->prEnter(compact('set', 'query', 'unrec', 'if_rec_include_partial'));
|
|
||||||
$lquery = $this->reconciledSetQuery($set, $query);
|
|
||||||
$result = $this->find('all', $lquery);
|
|
||||||
|
|
||||||
$this->pr(20, compact('lquery', 'result'));
|
|
||||||
|
|
||||||
$resultset = array();
|
|
||||||
foreach ($result AS $i => $entry) {
|
|
||||||
$this->pr(25, compact('entry'));
|
|
||||||
if (!empty($entry[0]))
|
|
||||||
$entry['StatementEntry'] = $entry[0] + $entry['StatementEntry'];
|
|
||||||
unset($entry[0]);
|
|
||||||
|
|
||||||
$entry['StatementEntry']['balance'] =
|
|
||||||
$entry['StatementEntry']['amount'] - $entry['StatementEntry']['reconciled'];
|
|
||||||
|
|
||||||
// Since HAVING isn't a builtin feature of CakePHP,
|
|
||||||
// we'll have to post-process to get the desired entries
|
|
||||||
|
|
||||||
if ($entry['StatementEntry']['balance'] == 0)
|
|
||||||
$reconciled = true;
|
|
||||||
elseif ($entry['StatementEntry']['reconciled'] == 0)
|
|
||||||
$reconciled = false;
|
|
||||||
else // Partial disbursement; depends on unrec
|
|
||||||
$reconciled = (!$unrec && $if_rec_include_partial);
|
|
||||||
|
|
||||||
// Add to the set, if it's been requested
|
|
||||||
if ($reconciled == !$unrec)
|
|
||||||
$resultset[] = $entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn(array('entries' => $resultset,
|
|
||||||
'summary' => $this->stats(null, $query)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: reconciledEntries
|
|
||||||
* - Returns a list of entries that reconcile against the given entry.
|
|
||||||
* (such as disbursements towards a charge).
|
|
||||||
*/
|
|
||||||
function reconciledEntriesQuery($id, $query = null) {
|
|
||||||
$this->queryInit($query, false);
|
|
||||||
|
|
||||||
$this->id = $id;
|
|
||||||
$this->recursive = -1;
|
|
||||||
$this->read();
|
|
||||||
|
|
||||||
$query['conditions'][] = array('StatementEntry.id' => $id);
|
|
||||||
|
|
||||||
if (in_array($this->data['StatementEntry']['type'], $this->debitTypes())) {
|
|
||||||
$query['link']['DisbursementEntry'] = array();
|
|
||||||
$query['conditions'][] = array('DisbursementEntry.id !=' => null);
|
|
||||||
}
|
|
||||||
if (in_array($this->data['StatementEntry']['type'], $this->creditTypes())) {
|
|
||||||
$query['link']['ChargeEntry'] = array();
|
|
||||||
$query['conditions'][] = array('ChargeEntry.id !=' => null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
function reconciledEntries($id, $query = null) {
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
$lquery = $this->reconciledEntriesQuery($id, $query);
|
|
||||||
|
|
||||||
$result = $this->find('all', $lquery);
|
|
||||||
foreach (array_keys($result) AS $i)
|
|
||||||
unset($result[$i]['StatementEntry']);
|
|
||||||
|
|
||||||
return $this->prReturn(array('entries' => $result));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* 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'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: assignCredits
|
|
||||||
* - Assigns all credits to existing charges
|
|
||||||
*
|
|
||||||
* REVISIT <AP>: 20090726
|
|
||||||
* This algorithm shouldn't be hardcoded. We need to allow
|
|
||||||
* the user to specify how disbursements should be applied.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function assignCredits($query = null, $receipt_id = null,
|
|
||||||
$charge_ids = null, $disbursement_type = null,
|
|
||||||
$customer_id = null, $lease_id = null)
|
|
||||||
{
|
|
||||||
//$this->prFunctionLevel(25);
|
|
||||||
$this->prEnter(compact('query', 'receipt_id',
|
|
||||||
'charge_ids', 'disbursement_type',
|
|
||||||
'customer_id', 'lease_id'));
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
if (empty($disbursement_type))
|
|
||||||
$disbursement_type = 'DISBURSEMENT';
|
|
||||||
|
|
||||||
$ret = array();
|
|
||||||
|
|
||||||
// First, find all known credits, unless this call is to make
|
|
||||||
// credit adjustments to a specific charge
|
|
||||||
if (empty($receipt_id)) {
|
|
||||||
|
|
||||||
if (!empty($charge_ids))
|
|
||||||
$this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt");
|
|
||||||
|
|
||||||
$lquery = $query;
|
|
||||||
if (!empty($customer_id))
|
|
||||||
$lquery['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
|
|
||||||
|
|
||||||
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
|
|
||||||
// REVISIT <AP>: 20090804
|
|
||||||
// We need to ensure that we're using surplus credits ONLY from either
|
|
||||||
// the given lease, or those that do not apply to any specific lease.
|
|
||||||
// However, by doing this, it forces any lease surplus amounts to
|
|
||||||
// remain frozen with that lease until either there is a lease charge,
|
|
||||||
// we refund the money, or we "promote" that surplus to the customer
|
|
||||||
// level and out of the leases direct control.
|
|
||||||
// That seems like a pain. Perhaps we should allow any customer
|
|
||||||
// surplus to be used on any customer charge.
|
|
||||||
$lquery['conditions'][] =
|
|
||||||
array('OR' =>
|
|
||||||
array(array('StatementEntry.lease_id' => null),
|
|
||||||
(!empty($lease_id)
|
|
||||||
? array('StatementEntry.lease_id' => $lease_id)
|
|
||||||
: array()),
|
|
||||||
));
|
|
||||||
$lquery['order'][] = 'StatementEntry.effective_date ASC';
|
|
||||||
$credits = $this->find('all', $lquery);
|
|
||||||
$this->pr(18, compact('credits'),
|
|
||||||
"Credits Established");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Establish credit from the (newly added) receipt
|
|
||||||
$lquery =
|
|
||||||
array('link' =>
|
|
||||||
array('StatementEntry',
|
|
||||||
'LedgerEntry' =>
|
|
||||||
array('conditions' =>
|
|
||||||
array('LedgerEntry.account_id <> Transaction.account_id')
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'conditions' => array('Transaction.id' => $receipt_id),
|
|
||||||
'fields' => array('Transaction.id', 'Transaction.stamp', 'Transaction.amount'),
|
|
||||||
);
|
|
||||||
$receipt_credit = $this->Transaction->find('first', $lquery);
|
|
||||||
if (!$receipt_credit)
|
|
||||||
$this->INTERNAL_ERROR("Unable to locate receipt.");
|
|
||||||
|
|
||||||
$stats = $this->Transaction->stats($receipt_id);
|
|
||||||
$receipt_credit['balance'] = $stats['undisbursed'];
|
|
||||||
|
|
||||||
$receipt_credit['receipt'] = true;
|
|
||||||
$credits = array($receipt_credit);
|
|
||||||
$this->pr(18, compact('credits'),
|
|
||||||
"Receipt Credit Added");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
$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
|
|
||||||
foreach ($charges AS $charge) {
|
|
||||||
$this->pr(20, compact('charge'),
|
|
||||||
'Process Charge');
|
|
||||||
|
|
||||||
$charge['balance'] = $charge['StatementEntry']['balance'];
|
|
||||||
|
|
||||||
// Use explicit credits before using the new receipt credit
|
|
||||||
foreach ($credits AS &$credit) {
|
|
||||||
if (empty($charge['balance']))
|
|
||||||
break;
|
|
||||||
if ($charge['balance'] < 0)
|
|
||||||
$this->INTERNAL_ERROR("Negative Charge Balance");
|
|
||||||
|
|
||||||
if (!isset($credit['balance']))
|
|
||||||
$credit['balance'] = $credit['StatementEntry']['amount'];
|
|
||||||
|
|
||||||
if (empty($credit['balance']))
|
|
||||||
continue;
|
|
||||||
if ($credit['balance'] < 0)
|
|
||||||
$this->INTERNAL_ERROR("Negative Credit Balance");
|
|
||||||
|
|
||||||
$this->pr(20, compact('charge'),
|
|
||||||
'Attempt Charge Reconciliation');
|
|
||||||
|
|
||||||
if (empty($credit['receipt']))
|
|
||||||
$disbursement_account_id = $credit['StatementEntry']['account_id'];
|
|
||||||
else
|
|
||||||
$disbursement_account_id = $credit['LedgerEntry']['account_id'];
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090811
|
|
||||||
// Need to come up with a better strategy for handling
|
|
||||||
// concessions. For now, just restricting concessions
|
|
||||||
// to apply only towards rent will resolve the most
|
|
||||||
// predominant (or only) needed usage case.
|
|
||||||
if ($disbursement_account_id == $this->Account->concessionAccountID() &&
|
|
||||||
$charge['StatementEntry']['account_id'] != $this->Account->rentAccountID())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Set the disbursement amount to the maximum amount
|
|
||||||
// possible without exceeding the charge or credit balance
|
|
||||||
$disbursement_amount = round(min($charge['balance'], $credit['balance']), 2);
|
|
||||||
if (!isset($credit['applied']))
|
|
||||||
$credit['applied'] = 0;
|
|
||||||
|
|
||||||
$credit['applied'] = round($credit['applied'] + $disbursement_amount, 2);
|
|
||||||
$credit['balance'] = round($credit['balance'] - $disbursement_amount, 2);
|
|
||||||
|
|
||||||
$this->pr(20, compact('credit', 'disbursement_amount'),
|
|
||||||
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
|
|
||||||
(empty($credit['receipt']) ? ' Credit' : ' Receipt'));
|
|
||||||
|
|
||||||
if (strtotime($charge['StatementEntry']['effective_date']) >
|
|
||||||
strtotime($credit['StatementEntry']['effective_date']))
|
|
||||||
$disbursement_edate = $charge['StatementEntry']['effective_date'];
|
|
||||||
else
|
|
||||||
$disbursement_edate = $credit['StatementEntry']['effective_date'];
|
|
||||||
|
|
||||||
if (empty($credit['receipt'])) {
|
|
||||||
// Explicit Credit
|
|
||||||
$result = $this->Transaction->addTransactionEntries
|
|
||||||
(array('include_ledger_entry' => true,
|
|
||||||
'include_statement_entry' => true),
|
|
||||||
array('type' => 'INVOICE',
|
|
||||||
'id' => $credit['StatementEntry']['transaction_id'],
|
|
||||||
'account_id' => $this->Account->accountReceivableAccountID(),
|
|
||||||
'crdr' => 'CREDIT',
|
|
||||||
'customer_id' => $charge['StatementEntry']['customer_id'],
|
|
||||||
'lease_id' => $charge['StatementEntry']['lease_id'],
|
|
||||||
),
|
|
||||||
array
|
|
||||||
(array('type' => $disbursement_type,
|
|
||||||
'effective_date' => $disbursement_edate,
|
|
||||||
'account_id' => $credit['StatementEntry']['account_id'],
|
|
||||||
'amount' => $disbursement_amount,
|
|
||||||
'charge_entry_id' => $charge['StatementEntry']['id'],
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
$ret['Disbursement'][] = $result;
|
|
||||||
if ($result['error'])
|
|
||||||
$ret['error'] = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Receipt Credit
|
|
||||||
|
|
||||||
if (strtotime($charge['StatementEntry']['effective_date']) >
|
|
||||||
strtotime($credit['Transaction']['stamp']))
|
|
||||||
$disbursement_edate = $charge['StatementEntry']['effective_date'];
|
|
||||||
else
|
|
||||||
$disbursement_edate = $credit['Transaction']['stamp'];
|
|
||||||
|
|
||||||
// Add a disbursement that uses the available credit to pay the charge
|
|
||||||
$disbursement =
|
|
||||||
array('type' => $disbursement_type,
|
|
||||||
'effective_date' => $disbursement_edate,
|
|
||||||
'amount' => $disbursement_amount,
|
|
||||||
'account_id' => $credit['LedgerEntry']['account_id'],
|
|
||||||
'transaction_id' => $credit['Transaction']['id'],
|
|
||||||
'customer_id' => $charge['StatementEntry']['customer_id'],
|
|
||||||
'lease_id' => $charge['StatementEntry']['lease_id'],
|
|
||||||
'charge_entry_id' => $charge['StatementEntry']['id'],
|
|
||||||
'comment' => null,
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->pr(20, compact('disbursement'), 'New Disbursement Entry');
|
|
||||||
$result = $this->addStatementEntry($disbursement);
|
|
||||||
$ret['Disbursement'][] = $result;
|
|
||||||
if ($result['error'])
|
|
||||||
$ret['error'] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust the charge balance to reflect the new disbursement
|
|
||||||
$charge['balance'] = 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?");
|
|
||||||
}
|
|
||||||
// Break the $credit reference to avoid future problems
|
|
||||||
unset($credit);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->pr(18, compact('credits'),
|
|
||||||
'Disbursements complete');
|
|
||||||
|
|
||||||
// Clean up any explicit credits that have been used
|
|
||||||
foreach ($credits AS $credit) {
|
|
||||||
if (!empty($credit['receipt']))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (empty($credit['applied']))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ($credit['balance'] > 0) {
|
|
||||||
$this->pr(20, compact('credit'),
|
|
||||||
'Update Credit Entry');
|
|
||||||
|
|
||||||
$this->id = $credit['StatementEntry']['id'];
|
|
||||||
$this->saveField('amount', $credit['balance']);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->pr(20, compact('credit'),
|
|
||||||
'Delete Exhausted Credit Entry');
|
|
||||||
|
|
||||||
$this->delete($credit['StatementEntry']['id'], false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for any implicit receipt credits, converting
|
|
||||||
// into explicit credits if there is a remaining balance.
|
|
||||||
foreach ($credits AS $credit) {
|
|
||||||
if (empty($credit['receipt']))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (empty($credit['balance']))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// See if there is an existing explicit credit
|
|
||||||
// for this transaction.
|
|
||||||
$explicit_credit = $this->find
|
|
||||||
('first', array('contain' => false,
|
|
||||||
'conditions' =>
|
|
||||||
array(array('transaction_id' => $credit['Transaction']['id']),
|
|
||||||
array('type' => 'SURPLUS')),
|
|
||||||
));
|
|
||||||
|
|
||||||
if (!empty($explicit_credit)) {
|
|
||||||
// REVISIT <AP>: 20090815
|
|
||||||
// Testing whether or not this case occurs
|
|
||||||
$this->INTERNAL_ERROR('Existing explicit credit unexpected');
|
|
||||||
|
|
||||||
// Since there IS an existing explicit credit, we must update
|
|
||||||
// its balance instead of creating a new one, since it has
|
|
||||||
// already been incorporated in the overall credit balance.
|
|
||||||
// If we were to create a new one, we would erroneously create
|
|
||||||
// an excess of credit available.
|
|
||||||
$this->pr(18, compact('explicit_credit', 'credit'),
|
|
||||||
'Update existing explicit credit');
|
|
||||||
$EC = new StatementEntry();
|
|
||||||
$EC->id = $explicit_credit['StatementEntry']['id'];
|
|
||||||
$EC->saveField('amount', $credit['balance']);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($ret['receipt_balance']))
|
|
||||||
$this->INTERNAL_ERROR('Only one receipt expected in assignCredits');
|
|
||||||
|
|
||||||
// Give caller the information necessary to create an explicit
|
|
||||||
// credit from the passed receipt, which we've not exhausted.
|
|
||||||
$this->pr(18, compact('credit'), 'Convert to explicit credit');
|
|
||||||
$ret['receipt_balance'] = $credit['balance'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn($ret + array('error' => false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: stats
|
|
||||||
* - Returns summary data from the requested statement entry
|
|
||||||
*/
|
|
||||||
function stats($id = null, $query = null) {
|
|
||||||
//$this->prFunctionLevel(array('log' => 16, 'show' => 10));
|
|
||||||
$this->prEnter(compact('id', 'query'));
|
|
||||||
|
|
||||||
$this->queryInit($query);
|
|
||||||
unset($query['group']);
|
|
||||||
|
|
||||||
$stats = array();
|
|
||||||
if (isset($id))
|
|
||||||
$query['conditions'][] = array('StatementEntry.id' => $id);
|
|
||||||
|
|
||||||
$types = array('Charge', 'Disbursement');
|
|
||||||
foreach ($types AS $type_index => $this_name) {
|
|
||||||
$that_name = $types[($type_index + 1) % 2];
|
|
||||||
if ($this_name === 'Charge') {
|
|
||||||
$this_types = $this->debitTypes();
|
|
||||||
$that_types = $this->creditTypes();
|
|
||||||
} else {
|
|
||||||
$this_types = $this->creditTypes();
|
|
||||||
$that_types = $this->debitTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this_query = $query;
|
|
||||||
$this_query['fields'] = array();
|
|
||||||
$this_query['fields'][] = "SUM(StatementEntry.amount) AS total";
|
|
||||||
$this_query['conditions'][] = array('StatementEntry.type' => $this_types);
|
|
||||||
$result = $this->find('first', $this_query);
|
|
||||||
$stats[$this_name] = $result[0];
|
|
||||||
|
|
||||||
$this->pr(17, compact('this_query', 'result'), $this_name.'s');
|
|
||||||
|
|
||||||
// Tally the different types that result in credits towards the charges
|
|
||||||
$stats[$this_name]['reconciled'] = 0;
|
|
||||||
foreach ($that_types AS $that_type) {
|
|
||||||
$lc_that_type = strtolower($that_type);
|
|
||||||
$that_query = $this_query;
|
|
||||||
$that_query['link']["{$that_name}Entry"] = array('fields' => array());
|
|
||||||
$that_query['fields'] = array();
|
|
||||||
if ($this_name == 'Charge')
|
|
||||||
$that_query['fields'][] = "COALESCE(SUM(${that_name}Entry.amount),0) AS $lc_that_type";
|
|
||||||
else
|
|
||||||
$that_query['fields'][] = "COALESCE(SUM(StatementEntry.amount), 0) AS $lc_that_type";
|
|
||||||
$that_query['conditions'][] = array("{$that_name}Entry.type" => $that_type);
|
|
||||||
$result = $this->find('first', $that_query);
|
|
||||||
$stats[$this_name] += $result[0];
|
|
||||||
|
|
||||||
$this->pr(17, compact('that_query', 'result'), "{$this_name}s: $that_type");
|
|
||||||
$stats[$this_name]['reconciled'] += $stats[$this_name][$lc_that_type];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute balance information for charges
|
|
||||||
$stats[$this_name]['balance'] =
|
|
||||||
$stats[$this_name]['total'] - $stats[$this_name]['reconciled'];
|
|
||||||
if (!isset($stats[$this_name]['balance']))
|
|
||||||
$stats[$this_name]['balance'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 'balance' is simply the difference between
|
|
||||||
// the balances of charges and disbursements
|
|
||||||
$stats['balance'] = $stats['Charge']['balance'] - $stats['Disbursement']['balance'];
|
|
||||||
if (!isset($stats['balance']))
|
|
||||||
$stats['balance'] = 0;
|
|
||||||
|
|
||||||
// 'account_balance' is really only relevant to
|
|
||||||
// callers that have requested charge and disbursement
|
|
||||||
// stats with respect to a particular account.
|
|
||||||
// It represents the difference between inflow
|
|
||||||
// and outflow from that account.
|
|
||||||
$stats['account_balance'] = $stats['Charge']['reconciled'] - $stats['Disbursement']['total'];
|
|
||||||
if (!isset($stats['account_balance']))
|
|
||||||
$stats['account_balance'] = 0;
|
|
||||||
|
|
||||||
return $this->prReturn($stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Tender extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo = array(
|
|
||||||
'TenderType',
|
|
||||||
'Customer',
|
|
||||||
'LedgerEntry',
|
|
||||||
'DepositTransaction' => array(
|
|
||||||
'className' => 'Transaction',
|
|
||||||
),
|
|
||||||
'DepositLedgerEntry' => array(
|
|
||||||
'className' => 'LedgerEntry',
|
|
||||||
),
|
|
||||||
'NsfTransaction' => array(
|
|
||||||
'className' => 'Transaction',
|
|
||||||
'dependent' => true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: afterSave
|
|
||||||
* - Performs any work needed after the save occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
function afterSave($created) {
|
|
||||||
// Come up with a (not necessarily unique) name for the tender.
|
|
||||||
// For checks & money orders, this will be based on the check
|
|
||||||
// number. For other types of tender, we'll just use the
|
|
||||||
// generic name of the tender type, and the tender ID
|
|
||||||
|
|
||||||
// Determine our tender type, and set the ID of that model
|
|
||||||
$this->TenderType->id = $this->field('tender_type_id');
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090810
|
|
||||||
// The only tender expected to have no tender type
|
|
||||||
// is our special "Closing" tender.
|
|
||||||
if (empty($this->TenderType->id))
|
|
||||||
$newname = 'Closing';
|
|
||||||
else {
|
|
||||||
$newname = $this->TenderType->field('name');
|
|
||||||
$naming_field = $this->TenderType->field('naming_field');
|
|
||||||
if (!empty($naming_field))
|
|
||||||
$newname .= ' #' . $this->field($naming_field);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($newname !== $this->field('name'))
|
|
||||||
$this->saveField('name', $newname);
|
|
||||||
|
|
||||||
return parent::afterSave($created);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: beforeDelete
|
|
||||||
* - Performs any work needed before the delete occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
function beforeDelete($cascade = true) {
|
|
||||||
// REVISIT <AP>: 20090814
|
|
||||||
// Experimental, and incomplete mechanism to protect
|
|
||||||
// against trying to delete data that shouldn't be deleted.
|
|
||||||
|
|
||||||
$deposit_id = $this->field('deposit_transaction_id');
|
|
||||||
pr(compact('deposit_id'));
|
|
||||||
// If this tender has already been deposited, it would
|
|
||||||
// be a rats nest to figure out how to delete this tender.
|
|
||||||
if (!empty($deposit_id))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return parent::beforeDelete($cascade);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: verifyTender
|
|
||||||
* - Verifies consistenty of new tender data
|
|
||||||
* (not in a pre-existing tender)
|
|
||||||
*/
|
|
||||||
function verifyTender($tender) {
|
|
||||||
$this->prFunctionLevel(10);
|
|
||||||
$this->prEnter(compact('tender'));
|
|
||||||
|
|
||||||
if (empty($tender['tender_type_id'])) {
|
|
||||||
return $this->prReturn(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: addTender
|
|
||||||
* - Inserts new Tender into the database
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addTender($tender) {
|
|
||||||
$this->prEnter(compact('tender'));
|
|
||||||
|
|
||||||
$ret = array('data' => $tender);
|
|
||||||
if (!$this->verifyTender($tender))
|
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
|
||||||
|
|
||||||
$this->create();
|
|
||||||
if (!$this->save($tender))
|
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
|
||||||
|
|
||||||
$ret['tender_id'] = $this->id;
|
|
||||||
return $this->prReturn($ret + array('error' => false));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: nsf
|
|
||||||
* - Flags the ledger entry as having insufficient funds
|
|
||||||
*/
|
|
||||||
|
|
||||||
function nsf($id, $stamp = null, $comment = null) {
|
|
||||||
$this->prEnter(compact('id', 'stamp', 'comment'));
|
|
||||||
|
|
||||||
// Get information about this NSF item.
|
|
||||||
$this->id = $id;
|
|
||||||
$tender = $this->find
|
|
||||||
('first', array
|
|
||||||
('contain' =>
|
|
||||||
array('LedgerEntry',
|
|
||||||
'DepositTransaction',
|
|
||||||
'DepositLedgerEntry',
|
|
||||||
'NsfTransaction'),
|
|
||||||
));
|
|
||||||
$this->pr(20, compact('tender'));
|
|
||||||
|
|
||||||
if (!empty($tender['NsfTransaction']['id']))
|
|
||||||
die("Item has already been set as NSF");
|
|
||||||
|
|
||||||
if (empty($tender['DepositTransaction']['id']))
|
|
||||||
die("Item has not been deposited yet");
|
|
||||||
|
|
||||||
$tender['Transaction'] = $tender['DepositTransaction'];
|
|
||||||
unset($tender['DepositTransaction']);
|
|
||||||
unset($tender['NsfTransaction']);
|
|
||||||
|
|
||||||
$T = new Transaction();
|
|
||||||
$result = $T->addNsf($tender, $stamp, $comment);
|
|
||||||
if (empty($result['error'])) {
|
|
||||||
// Flag the tender as NSF, using the items created from addNsf
|
|
||||||
$this->id = $id;
|
|
||||||
$this->saveField('nsf_transaction_id', $result['nsf_transaction_id']);
|
|
||||||
$this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
File diff suppressed because it is too large
Load Diff
-248
@@ -1,248 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Unit extends AppModel {
|
|
||||||
|
|
||||||
var $name = 'Unit';
|
|
||||||
var $validate = array(
|
|
||||||
'id' => array('numeric'),
|
|
||||||
'unit_size_id' => array('numeric'),
|
|
||||||
'name' => array('notempty'),
|
|
||||||
'sort_order' => array('numeric'),
|
|
||||||
'walk_order' => array('numeric'),
|
|
||||||
'deposit' => array('money'),
|
|
||||||
'amount' => array('money')
|
|
||||||
);
|
|
||||||
|
|
||||||
var $belongsTo = array(
|
|
||||||
'UnitSize',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasOne = array(
|
|
||||||
'CurrentLease' => array(
|
|
||||||
'className' => 'Lease',
|
|
||||||
'conditions' => 'CurrentLease.moveout_date IS NULL',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasMany = array(
|
|
||||||
'Lease',
|
|
||||||
);
|
|
||||||
|
|
||||||
//var $default_log_level = array('log' => 30, 'show' => 15);
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* helpers: status enumerations
|
|
||||||
*/
|
|
||||||
|
|
||||||
function statusEnums() {
|
|
||||||
static $status_enums;
|
|
||||||
if (!isset($status_enums))
|
|
||||||
$status_enums = $this->getEnumValues('status');
|
|
||||||
return $status_enums;
|
|
||||||
}
|
|
||||||
|
|
||||||
function activeStatusEnums() {
|
|
||||||
return array_diff_key($this->statusEnums(), array(''=>1, 'DELETED'=>1));
|
|
||||||
}
|
|
||||||
|
|
||||||
function statusValue($enum) {
|
|
||||||
$enums = $this->statusEnums();
|
|
||||||
return $enums[$enum];
|
|
||||||
}
|
|
||||||
|
|
||||||
function occupiedEnumValue() {
|
|
||||||
return $this->statusValue('OCCUPIED');
|
|
||||||
}
|
|
||||||
|
|
||||||
function statusCheck($id_or_enum,
|
|
||||||
$min = null, $min_strict = false,
|
|
||||||
$max = null, $max_strict = false)
|
|
||||||
{
|
|
||||||
$this->prEnter(compact('id_or_enum', 'min', 'min_strict', 'max', 'max_strict'));
|
|
||||||
|
|
||||||
if (is_int($id_or_enum)) {
|
|
||||||
$this->id = $id_or_enum;
|
|
||||||
$id_or_enum = $this->field('status');
|
|
||||||
}
|
|
||||||
|
|
||||||
$enum_val = $this->statusValue($id_or_enum);
|
|
||||||
if (isset($min) && is_string($min))
|
|
||||||
$min = $this->statusValue($min);
|
|
||||||
if (isset($max) && is_string($max))
|
|
||||||
$max = $this->statusValue($max);
|
|
||||||
|
|
||||||
$this->pr(17, compact('enum_val', 'min', 'min_strict', 'max', 'max_strict'));
|
|
||||||
|
|
||||||
if (isset($min) &&
|
|
||||||
($enum_val < $min ||
|
|
||||||
($min_strict && $enum_val == $min)))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
if (isset($max) &&
|
|
||||||
($enum_val > $max ||
|
|
||||||
($max_strict && $enum_val == $max)))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
|
|
||||||
return $this->prReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function locked($enum) {
|
|
||||||
return $this->statusCheck($enum, 'LOCKED', false, null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function conditionLocked() {
|
|
||||||
//return array('Unit.status' => 'LOCKED');
|
|
||||||
return ('Unit.status >= ' . $this->statusValue('LOCKED'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function liened($enum) {
|
|
||||||
return $this->statusCheck($enum, 'LIENED', false, null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function conditionLiened() {
|
|
||||||
return ('Unit.status >= ' . $this->statusValue('LIENED'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function occupied($enum) {
|
|
||||||
return $this->statusCheck($enum, 'OCCUPIED', false, null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function conditionOccupied() {
|
|
||||||
return ('Unit.status >= ' . $this->statusValue('OCCUPIED'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function vacant($enum) {
|
|
||||||
return $this->statusCheck($enum, 'UNAVAILABLE', true, 'OCCUPIED', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
function conditionVacant() {
|
|
||||||
return ('Unit.status BETWEEN ' .
|
|
||||||
($this->statusValue('UNAVAILABLE')+1) .
|
|
||||||
' AND ' .
|
|
||||||
($this->statusValue('OCCUPIED')-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
function unavailable($enum) {
|
|
||||||
return $this->statusCheck($enum, null, false, 'UNAVAILABLE', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function conditionUnavailable() {
|
|
||||||
return ('Unit.status <= ' . $this->statusValue('UNAVAILABLE'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function available($enum) { return $this->vacant($enum); }
|
|
||||||
function conditionAvailable() { return $this->conditionVacant($enum); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: allowedStatusSet
|
|
||||||
* - Returns the status set allowed for the given unit
|
|
||||||
*/
|
|
||||||
function allowedStatusSet($id) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
$this->id = $id;
|
|
||||||
$old_status = $this->field('status');
|
|
||||||
$old_val = $this->statusValue($old_status);
|
|
||||||
$this->pr(17, compact('old_status', 'old_val'));
|
|
||||||
|
|
||||||
$enums = $this->activeStatusEnums();
|
|
||||||
$this->pr(21, compact('enums'));
|
|
||||||
|
|
||||||
foreach ($enums AS $enum => $val) {
|
|
||||||
if (($old_val < $this->occupiedEnumValue()) !=
|
|
||||||
($val < $this->occupiedEnumValue())) {
|
|
||||||
unset($enums[$enum]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->prReturn($enums);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: updateStatus
|
|
||||||
* - Update the given unit to the given status
|
|
||||||
*/
|
|
||||||
function updateStatus($id, $status, $check = false) {
|
|
||||||
$this->prEnter(compact('id', 'status', 'check'));
|
|
||||||
|
|
||||||
/* if ($check) { */
|
|
||||||
/* $old_status = $this->field('status'); */
|
|
||||||
/* $this->pr(17, compact('old_status')); */
|
|
||||||
/* if ($this->statusValue($old_status) < $this->occupiedEnumValue() && */
|
|
||||||
/* $this->statusValue($status) >= $this->occupiedEnumValue()) */
|
|
||||||
/* { */
|
|
||||||
/* die("Can't transition a unit from vacant to occupied"); */
|
|
||||||
/* return $this->prReturn(false); */
|
|
||||||
/* } */
|
|
||||||
/* if ($this->statusValue($old_status) >= $this->occupiedEnumValue() && */
|
|
||||||
/* $this->statusValue($status) < $this->occupiedEnumValue()) */
|
|
||||||
/* { */
|
|
||||||
/* die("Can't transition a unit from occupied to vacant"); */
|
|
||||||
/* return $this->prReturn(false); */
|
|
||||||
/* } */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
if ($check) {
|
|
||||||
if (!array_key_exists($status, $this->allowedStatusSet($id)))
|
|
||||||
return $this->prReturn(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->id = $id;
|
|
||||||
$this->saveField('status', $status);
|
|
||||||
return $this->prReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: update
|
|
||||||
* - Update any cached or calculated fields
|
|
||||||
*/
|
|
||||||
function update($id) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: stats
|
|
||||||
* - Returns summary data from the requested customer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function stats($id = null) {
|
|
||||||
if (!$id)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Get the basic information necessary
|
|
||||||
$unit = $this->find('first',
|
|
||||||
array('contain' => array
|
|
||||||
('Lease' => array
|
|
||||||
('fields' => array('Lease.id')),
|
|
||||||
|
|
||||||
'CurrentLease' => array
|
|
||||||
('fields' => array('CurrentLease.id'))),
|
|
||||||
|
|
||||||
'conditions' => array
|
|
||||||
(array('Unit.id' => $id)),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Get the stats for the current lease
|
|
||||||
$stats['CurrentLease'] = $this->Lease->stats($unit['CurrentLease']['id']);
|
|
||||||
|
|
||||||
// Sum the stats for all leases together
|
|
||||||
foreach ($unit['Lease'] AS $lease) {
|
|
||||||
$this->statsMerge($stats['Lease'], $this->Lease->stats($lease['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the collection
|
|
||||||
return $stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<?php
|
|
||||||
class UnitSize extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array(
|
|
||||||
'UnitType',
|
|
||||||
);
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array(
|
|
||||||
'Unit',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: stats
|
|
||||||
* - Returns summary data from the requested unit size.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function stats($id = null) {
|
|
||||||
$this->prEnter(compact('id'));
|
|
||||||
|
|
||||||
// Right now, we only work with id not null
|
|
||||||
if (!$id)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
$stats = array();
|
|
||||||
|
|
||||||
// Get the total number of units this size
|
|
||||||
$stats['all'] =
|
|
||||||
$this->find('count',
|
|
||||||
array('link' => array('Unit'),
|
|
||||||
'conditions' => array(array('UnitSize.id' => $id)),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Get numbers for units in the various states
|
|
||||||
foreach (array('unavailable', 'vacant', 'occupied', 'locked', 'liened') AS $status) {
|
|
||||||
$statusfunc = 'condition' . ucfirst($status);
|
|
||||||
$stats[$status] =
|
|
||||||
$this->find('count',
|
|
||||||
array('link' => array('Unit'),
|
|
||||||
'conditions' => array(array('UnitSize.id' => $id),
|
|
||||||
$this->Unit->{$statusfunc}()),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count up each unit by physical status
|
|
||||||
foreach
|
|
||||||
($this->find('all',
|
|
||||||
array('link' => array('Unit' => array('fields' => array())),
|
|
||||||
'fields' => array('Unit.status', 'COUNT(Unit.id) AS total'),
|
|
||||||
'conditions' => array(array('UnitSize.id' => $id)),
|
|
||||||
'group' => 'Unit.status',
|
|
||||||
)) AS $status) {
|
|
||||||
$stats['status'][$status['Unit']['status']] = $status[0]['total'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the collection
|
|
||||||
return $this->prReturn($stats);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
class UnitType extends AppModel {
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array(
|
|
||||||
'UnitSize',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: relatedTypes
|
|
||||||
* - Returns an array of types related by similar attributes
|
|
||||||
*/
|
|
||||||
|
|
||||||
function relatedTypes($attribute, $extra = null) {
|
|
||||||
$this->cacheQueries = true;
|
|
||||||
$types = $this->find('all', array
|
|
||||||
('fields' => array('UnitType.id', 'UnitType.name'),
|
|
||||||
'conditions' => array('UnitType.'.$attribute => true),
|
|
||||||
'order' => array('UnitType.name'),
|
|
||||||
) + (isset($extra) ? $extra : array())
|
|
||||||
);
|
|
||||||
$this->cacheQueries = false;
|
|
||||||
|
|
||||||
// Rearrange to be of the form (id => name)
|
|
||||||
$rel_types = array();
|
|
||||||
foreach ($types AS $type) {
|
|
||||||
$rel_types[$type['UnitType']['id']] = $type['UnitType']['name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rel_types;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: xxxTypes
|
|
||||||
* - Returns an array of types suitable for activity xxx
|
|
||||||
*/
|
|
||||||
|
|
||||||
function residentialTypes() { return $this->relatedTypes('residential'); }
|
|
||||||
function enclosedTypes() { return $this->relatedTypes('enclosed'); }
|
|
||||||
function climateTypes() { return $this->relatedTypes('climate'); }
|
|
||||||
function outdoorTypes() { return $this->relatedTypes('outdoor'); }
|
|
||||||
function coveredTypes() { return $this->relatedTypes('covered'); }
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
class User extends AppModel {
|
|
||||||
|
|
||||||
var $hasMany =
|
|
||||||
array('UserOption',
|
|
||||||
'Membership',
|
|
||||||
);
|
|
||||||
|
|
||||||
static $current_user_id;
|
|
||||||
|
|
||||||
function currentUser() {
|
|
||||||
if (!empty($_SERVER['REMOTE_USER']))
|
|
||||||
return $_SERVER['REMOTE_USER'];
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function currentUserId() {
|
|
||||||
if (!empty(self::$current_user_id))
|
|
||||||
return self::$current_user_id;
|
|
||||||
|
|
||||||
$user = $this->find
|
|
||||||
('first',
|
|
||||||
array('recursive' => -1,
|
|
||||||
'conditions' => array('login' => $this->currentUser())));
|
|
||||||
|
|
||||||
if (!empty($user['User']['id']))
|
|
||||||
self::$current_user_id = $user['User']['id'];
|
|
||||||
else
|
|
||||||
// We must force a stop here, since this is typically
|
|
||||||
// called very early on, and so will cause a recursive
|
|
||||||
// crash as we try to render the internal error and
|
|
||||||
// again stumble on this problem.
|
|
||||||
$this->INTERNAL_ERROR('UNKNOWN USER', 0, true);
|
|
||||||
|
|
||||||
return self::$current_user_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
class UserOption extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('User',
|
|
||||||
'OptionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($id, $name = null) {
|
|
||||||
$this->prEnter(compact('id', 'name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['UserOption'] = array();
|
|
||||||
$query['link']['UserOption']['fields'] = array();
|
|
||||||
$query['link']['UserOption']['User'] = array();
|
|
||||||
$query['link']['UserOption']['User']['fields'] = array();
|
|
||||||
$query['conditions'][] = array('User.id' => $id);
|
|
||||||
return $this->prReturn($this->OptionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
class UserPermission extends AppModel {
|
|
||||||
|
|
||||||
var $belongsTo =
|
|
||||||
array('User',
|
|
||||||
'PermissionValue',
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function values($id, $name = null) {
|
|
||||||
$this->prEnter(compact('id', 'name'));
|
|
||||||
|
|
||||||
$query = array();
|
|
||||||
$this->queryInit($query);
|
|
||||||
|
|
||||||
$query['link']['UserPermission'] = array();
|
|
||||||
$query['link']['UserPermission']['fields'] = array();
|
|
||||||
$query['link']['UserPermission']['User'] = array();
|
|
||||||
$query['link']['UserPermission']['User']['fields'] = array();
|
|
||||||
$query['conditions'][] = array('User.id' => $id);
|
|
||||||
return $this->prReturn($this->PermissionValue->values($name, $query));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
N - GATE
|
||||||
|
N - ACH / CREDIT CARD PROCESSING
|
||||||
|
Y - CREDIT CARD ENTRY
|
||||||
|
Y - ACH ENTRY
|
||||||
|
P - INVENTORY TRACKING / POS
|
||||||
|
Y - UNIT TYPES
|
||||||
|
Y - UNIT SIZES
|
||||||
|
Y - UNITS
|
||||||
|
Y - MOVE IN / OUT
|
||||||
|
Y - UNIT TRANSFERS
|
||||||
|
Y - LEASE TRACKING (PDF Generation)
|
||||||
|
Y - LETTERS (PDF Generation)
|
||||||
|
Y - REMINDERS
|
||||||
|
Y - MULTIPLE LATE RENT SCHEDULES (Tenant A vs Tenant B)
|
||||||
|
Y - ACCOUNTING (assign charges to accounts)
|
||||||
|
Y - DETAILED REPORTING (HTML & PDF)
|
||||||
|
Y - SITE MAP; HOT CLICKABLE
|
||||||
|
P - PROSPECTIVE TENANTS
|
||||||
|
Y - MARKETING
|
||||||
|
P - RESERVATIONS
|
||||||
|
P - MOVE OUT NOTICES
|
||||||
|
P - MULTI-SITE (One database, multiple sites)
|
||||||
|
Y - GENERATE GEOGRAPHIC MAP OF CUSTOMERS USING GOOGLE!
|
||||||
|
- Major advantage here... MapPoint only choice with competitors
|
||||||
|
Y - WEB BASED
|
||||||
|
Y - CUSTOMER VIEW / MANAGER VIEW
|
||||||
|
Y - CUSTOMERS CAN CREATE ACCOUNTS, VIEW HISTORY
|
||||||
|
Y - CUSTOMERS CAN SIGN UP FOR AUTO PAY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Operations to be functional
|
||||||
|
'X' marks functionality sufficiently completed
|
||||||
|
|
||||||
|
X - Create Customer ID/Account
|
||||||
|
X - Add Contact information to Customer
|
||||||
|
X - Move Customer into Unit
|
||||||
|
? - Enter Rent Concessions given
|
||||||
|
X - Asses Rent Charges
|
||||||
|
X - Asses Late Charges
|
||||||
|
X - Asses Security Deposits
|
||||||
|
X - Receive and record Checks
|
||||||
|
X - Receive and record Money Orders
|
||||||
|
X - Receive and record Cash
|
||||||
|
X - Receive and record ACH Deposits
|
||||||
|
? - Reverse rent charges (early moveout on prepaid occupancy)
|
||||||
|
X - Handle NSF checks
|
||||||
|
X - Assess NSF Fees
|
||||||
|
X - Determine Lease Paid-Through status
|
||||||
|
- Report: List of customers overdue
|
||||||
|
- Flag unit as overlocked
|
||||||
|
- Flag unit as evicting
|
||||||
|
- Flag unit as normal status
|
||||||
|
- Flag unit as dirty
|
||||||
|
- Enter notes when communicating with Customer
|
||||||
|
X - Accept pre-payments
|
||||||
|
X - Record Customer Move-Out from Unit
|
||||||
|
? - Record utilization of Security Deposit
|
||||||
|
- Record issuing of a refund
|
||||||
|
- Record Deposit into Petty Cash
|
||||||
|
- Record Payment from Petty Cash to expenses
|
||||||
|
- Record Petty Cash to refund.
|
||||||
|
? - Write Off Bad Debt
|
||||||
|
X - Perform a Deposit
|
||||||
|
X - Close the Books (nightly / weekly, etc)
|
||||||
|
X - Determine Rents Collected for a given period.
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ webroot/ [L]
|
||||||
|
RewriteRule (.*) webroot/$1 [L]
|
||||||
|
</IfModule>
|
||||||
@@ -35,442 +35,49 @@
|
|||||||
* @subpackage cake.app
|
* @subpackage cake.app
|
||||||
*/
|
*/
|
||||||
class AppController extends Controller {
|
class AppController extends Controller {
|
||||||
var $uses = array('Option', 'Permission');
|
|
||||||
var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid');
|
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, 'REPORT' => false, 'CONTROLLER' => false, 'ACTION' => false, 'SANDBOX' => false));
|
function sideMenuLinks() {
|
||||||
var $std_area = 10;
|
return array(
|
||||||
var $admin_area = 20;
|
array('name' => 'Common', 'header' => true),
|
||||||
var $dev_area = 30;
|
array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)),
|
||||||
var $op_area = 40;
|
array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')),
|
||||||
var $new_area = 50;
|
array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index')),
|
||||||
|
array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')),
|
||||||
function __construct() {
|
array('name' => 'Accounts', 'url' => array('controller' => 'accounts', 'action' => 'index')),
|
||||||
$this->params['dev'] = false;
|
array('name' => 'Debug', 'header' => true),
|
||||||
$this->params['admin'] = false;
|
array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index')),
|
||||||
parent::__construct();
|
array('name' => 'Ledgers', 'url' => array('controller' => 'ledgers', 'action' => 'index')),
|
||||||
|
array('name' => 'New Ledgers', 'url' => array('controller' => 'accounts', 'action' => 'newledger')),
|
||||||
|
array('name' => 'RESET DATA', 'url' => array('controller' => 'accounts', 'action' => 'reset_data')),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: dev/admin()
|
|
||||||
* - Indicates if the user has dev/admin access
|
|
||||||
*/
|
|
||||||
function dev() { return !empty($this->params['dev']); }
|
|
||||||
function admin() { return !empty($this->params['admin']); }
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: sideMenuAreaVerify
|
|
||||||
* - Verifies the validity of the sidemenu area/subarea/priority,
|
|
||||||
* and ensures the class member is set to appropriately handle it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function sideMenuAreaVerify(&$area, $subarea, $priority = null) {
|
|
||||||
$area = strtoupper($area);
|
|
||||||
if (!array_key_exists($area, $this->sidemenu['areas']))
|
|
||||||
$this->INTERNAL_ERROR("Sidemenu link '{$area}': Unknown");
|
|
||||||
|
|
||||||
if ($area == 'SITE')
|
|
||||||
$name = 'Navigation';
|
|
||||||
elseif ($area == 'CONTROLLER')
|
|
||||||
$name = Inflector::humanize($this->params['controller']);
|
|
||||||
elseif ($area == 'ACTION')
|
|
||||||
$name = Inflector::humanize(Inflector::singularize($this->params['controller']));
|
|
||||||
elseif ($area == 'REPORT')
|
|
||||||
$name = 'Reports';
|
|
||||||
elseif ($area == 'SANDBOX')
|
|
||||||
$name = 'Sandbox';
|
|
||||||
|
|
||||||
if (empty($this->sidemenu['areas'][$area]))
|
|
||||||
$this->sidemenu['areas'][$area]
|
|
||||||
= array('enable' => true, 'name' => $name, 'subareas' => array());
|
|
||||||
|
|
||||||
if (empty($subarea))
|
|
||||||
return;
|
|
||||||
|
|
||||||
$subname = $name;
|
|
||||||
if ($subarea == $this->std_area)
|
|
||||||
$subname .= '';
|
|
||||||
elseif ($subarea == $this->op_area)
|
|
||||||
//$subname .= '-Ops';
|
|
||||||
$subname = 'Actions';
|
|
||||||
elseif ($subarea == $this->new_area)
|
|
||||||
//$subname .= '-New';
|
|
||||||
$subname = 'Creation';
|
|
||||||
elseif ($subarea == $this->admin_area)
|
|
||||||
$subname .= '-Admin';
|
|
||||||
elseif ($subarea == $this->dev_area)
|
|
||||||
$subname .= '-Dev';
|
|
||||||
else
|
|
||||||
$subname .= '-' . $subarea;
|
|
||||||
|
|
||||||
if (empty($this->sidemenu['areas'][$area]['subareas'][$subarea]))
|
|
||||||
$this->sidemenu['areas'][$area]['subareas'][$subarea]
|
|
||||||
= array('enable' => true, 'name' => $subname, 'priorities' => array());
|
|
||||||
|
|
||||||
if (empty($priority))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (empty($this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority]))
|
|
||||||
$this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority]
|
|
||||||
= array();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: sideMenuAreaName
|
|
||||||
* - Sets the name of the sidemenu area/subarea
|
|
||||||
*/
|
|
||||||
|
|
||||||
function sideMenuAreaName($name, $area, $subarea = null) {
|
|
||||||
$this->sideMenuAreaVerify($area, $subarea);
|
|
||||||
if (empty($subarea))
|
|
||||||
$this->sidemenu['areas'][$area]['name'] = $name;
|
|
||||||
else
|
|
||||||
$this->sidemenu['areas'][$area]['subareas'][$subarea]['name'] = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: sideMenuAreaActivate
|
|
||||||
* - Sets the selected area/subarea to be active when the
|
|
||||||
* page is first loaded.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function sideMenuAreaActivate($area, $subarea = null) {
|
|
||||||
$this->sidemenu['active'] = compact('area', 'subarea');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: sideMenuEnable
|
|
||||||
* - Enables/Disables an area or subarea of the sidemenu
|
|
||||||
*/
|
|
||||||
|
|
||||||
function sideMenuEnable($area, $subarea = null, $enable = true) {
|
|
||||||
$this->sideMenuAreaVerify($area, $subarea);
|
|
||||||
if (isset($subarea))
|
|
||||||
$this->sidemenu['areas'][$area]['subareas'][$subarea]['enable'] = $enable;
|
|
||||||
else
|
|
||||||
$this->sidemenu['areas'][$area]['enable'] = $enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: addSideMenuLink
|
|
||||||
* - Adds another link to the sidemenu area/subarea/priority
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addSideMenuLink($name, $url, $extra, $area, $subarea = null, $priority = 10) {
|
|
||||||
if (empty($subarea))
|
|
||||||
$subarea = $this->std_area;
|
|
||||||
$this->sideMenuAreaVerify($area, $subarea);
|
|
||||||
$this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority][]
|
|
||||||
= array('name' => $name, 'url' => $url) + (empty($extra) ? array() : $extra);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: addDefaultSideMenuLinks
|
|
||||||
* - Adds the standard links present on all generated pages
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addDefaultSideMenuLinks() {
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Site Map',
|
|
||||||
array('controller' => 'maps', 'action' => 'view', 1), null,
|
|
||||||
'SITE');
|
|
||||||
$this->addSideMenuLink('Unit Sizes',
|
|
||||||
array('controller' => 'unit_sizes', 'action' => 'index'), null,
|
|
||||||
'SITE');
|
|
||||||
$this->addSideMenuLink('Units',
|
|
||||||
array('controller' => 'units', 'action' => 'index'), null,
|
|
||||||
'SITE');
|
|
||||||
$this->addSideMenuLink('Leases',
|
|
||||||
array('controller' => 'leases', 'action' => 'index'), null,
|
|
||||||
'SITE');
|
|
||||||
$this->addSideMenuLink('Customers',
|
|
||||||
array('controller' => 'customers', 'action' => 'index'), null,
|
|
||||||
'SITE');
|
|
||||||
$this->addSideMenuLink('Deposits',
|
|
||||||
array('controller' => 'transactions', 'action' => 'deposit'), null,
|
|
||||||
'SITE');
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Accounts',
|
|
||||||
array('controller' => 'accounts', 'action' => 'index'), null,
|
|
||||||
'SITE', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Contacts',
|
|
||||||
array('controller' => 'contacts', 'action' => 'index'), null,
|
|
||||||
'SITE', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Ledgers',
|
|
||||||
array('controller' => 'ledgers', 'action' => 'index'), null,
|
|
||||||
'SITE', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Tenders',
|
|
||||||
array('controller' => 'tenders', 'action' => 'index'), null,
|
|
||||||
'SITE', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Transactions',
|
|
||||||
array('controller' => 'transactions', 'action' => 'index'), null,
|
|
||||||
'SITE', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Ldgr Entries',
|
|
||||||
array('controller' => 'ledger_entries', 'action' => 'index'), null,
|
|
||||||
'SITE', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Stmt Entries',
|
|
||||||
array('controller' => 'statement_entries', 'action' => 'index'), null,
|
|
||||||
'SITE', $this->admin_area);
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Un-Nuke',
|
|
||||||
'#', array('htmlAttributes' =>
|
|
||||||
array('onclick' => '$(".pr-section").show(); return false;')),
|
|
||||||
'SITE', $this->dev_area);
|
|
||||||
$this->addSideMenuLink('New Ledgers',
|
|
||||||
array('controller' => 'accounts', 'action' => 'newledger'), null,
|
|
||||||
'SITE', $this->dev_area);
|
|
||||||
//array('name' => 'RESET DATA', array('controller' => 'accounts', 'action' => 'reset_data'));
|
|
||||||
|
|
||||||
|
|
||||||
$this->addSideMenuLink('New Receipt',
|
|
||||||
array('controller' => 'customers', 'action' => 'receipt'), null,
|
|
||||||
'SITE', $this->op_area);
|
|
||||||
$this->addSideMenuLink('New Invoice',
|
|
||||||
array('controller' => 'leases', 'action' => 'invoice'), null,
|
|
||||||
'SITE', $this->op_area);
|
|
||||||
$this->addSideMenuLink('Move-In',
|
|
||||||
array('controller' => 'customers', 'action' => 'move_in'), null,
|
|
||||||
'SITE', $this->op_area);
|
|
||||||
$this->addSideMenuLink('Move-Out',
|
|
||||||
array('controller' => 'leases', 'action' => 'move_out'), null,
|
|
||||||
'SITE', $this->op_area);
|
|
||||||
$this->addSideMenuLink('New Deposit',
|
|
||||||
array('controller' => 'tenders', 'action' => 'deposit'), null,
|
|
||||||
'SITE', $this->op_area);
|
|
||||||
if ($this->admin())
|
|
||||||
$this->addSideMenuLink('Assess Charges',
|
|
||||||
array('controller' => 'leases', 'action' => 'assess_all'), null,
|
|
||||||
'SITE', $this->op_area);
|
|
||||||
|
|
||||||
if ($this->admin()) {
|
|
||||||
$acct = new Account;
|
|
||||||
$this->addSideMenuLink('Collected Rent',
|
|
||||||
array('controller' => 'accounts',
|
|
||||||
'action' => 'collected',
|
|
||||||
$acct->rentAccountID()), null,
|
|
||||||
'REPORT');
|
|
||||||
$this->addSideMenuLink('Unpaid Charges',
|
|
||||||
array('controller' => 'statement_entries', 'action' => 'unpaid'), null,
|
|
||||||
'REPORT');
|
|
||||||
$this->addSideMenuLink('Lease Up',
|
|
||||||
array('controller' => 'leases', 'action' => 'overview'), null,
|
|
||||||
'REPORT');
|
|
||||||
$this->addSideMenuLink('Unit Summary',
|
|
||||||
array('controller' => 'units', 'action' => 'overview'), null,
|
|
||||||
'REPORT');
|
|
||||||
$this->addSideMenuLink('Monthly Charges',
|
|
||||||
array('controller' => 'statement_entries', 'action' => 'chargesbymonth'), null,
|
|
||||||
'REPORT');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->sideMenuEnable('REPORT', null, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$url_components = array('plugin', 'controller', 'action', 'named');
|
|
||||||
if (devbox()) {
|
|
||||||
/* $sources = ConnectionManager::sourceList(); */
|
|
||||||
/* $db = ConnectionManager::getDataSource($sources[0])->config['database']; */
|
|
||||||
/* $this->sideMenuAreaName($db, 'SANDBOX', $this->std_area); */
|
|
||||||
$this->sideMenuAreaName('DevBox', 'SANDBOX', $this->std_area);
|
|
||||||
$this->addSideMenuLink('Rebuild DevBox',
|
|
||||||
array('controller' => 'util', 'action' => 'rebuild_devbox'), null,
|
|
||||||
'SANDBOX');
|
|
||||||
}
|
|
||||||
elseif (sandbox()) {
|
|
||||||
$this->addSideMenuLink('Rebuild Sandbox',
|
|
||||||
array('controller' => 'util', 'action' => 'rebuild_sandbox'), null,
|
|
||||||
'SANDBOX');
|
|
||||||
$this->addSideMenuLink('Leave Sandbox',
|
|
||||||
array('sand_route' => false)
|
|
||||||
+ array_intersect_key($this->params, array_flip($url_components))
|
|
||||||
+ $this->params['pass'],
|
|
||||||
null, 'SANDBOX');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->addSideMenuLink('Enter Sandbox',
|
|
||||||
array('sand_route' => true)
|
|
||||||
+ array_intersect_key($this->params, array_flip($url_components))
|
|
||||||
+ $this->params['pass'],
|
|
||||||
null, 'SANDBOX');
|
|
||||||
}
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090824
|
|
||||||
// Depending on preference, we may put this into the gridView
|
|
||||||
// function, making the links available only when navigating.
|
|
||||||
$this->addGridViewSideMenuLinks();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* virtual: addGridViewSideMenuLinks
|
|
||||||
* - Adds the grid view specific navigation links, if overridden.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function addGridViewSideMenuLinks() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* hook: beforeFilter
|
|
||||||
* - Called just before the action function
|
|
||||||
*/
|
|
||||||
|
|
||||||
function beforeFilter() {
|
|
||||||
$this->params['user'] = $this->Permission->User->currentUser();
|
|
||||||
$this->params['admin'] = $this->Option->enabled('admin');
|
|
||||||
$this->params['dev'] = devbox();
|
|
||||||
|
|
||||||
if ($this->dev() && !$this->Option->enabled('dev'))
|
|
||||||
$this->redirect("/");
|
|
||||||
|
|
||||||
if (!$this->dev())
|
|
||||||
Configure::write('debug', '0');
|
|
||||||
|
|
||||||
$this->addDefaultSideMenuLinks();
|
|
||||||
//$this->sideMenuEnable('SITE', $this->op_area, false);
|
|
||||||
|
|
||||||
foreach ($this->sidemenu['areas'] AS $area_name => $area) {
|
|
||||||
if (!$this->dev())
|
|
||||||
$this->sideMenuEnable($area_name, $this->dev_area, false);
|
|
||||||
if (!$this->admin())
|
|
||||||
$this->sideMenuEnable($area_name, $this->admin_area, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->authorize("controller.{$this->params['controller']}");
|
|
||||||
$this->authorize("action.{$this->params['controller']}.{$this->params['action']}");
|
|
||||||
|
|
||||||
$this->log('----------------------------------------------------------------------', 'request');
|
|
||||||
$this->log('----------------------------------------------------------------------', 'request');
|
|
||||||
$this->log($this->params, 'request');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* hook: beforeRender
|
|
||||||
* - Called just before rendering the page
|
|
||||||
*/
|
|
||||||
|
|
||||||
function beforeRender() {
|
function beforeRender() {
|
||||||
// Stupid Cake... our constructor sets admin/dev,
|
$this->set('sidemenu', $this->sideMenuLinks());
|
||||||
// but cake stomps it somewhere along the way
|
|
||||||
// after constructing the CakeError controller.
|
|
||||||
if ($this->name === 'CakeError') {
|
|
||||||
$this->params['dev'] = false;
|
|
||||||
$this->params['admin'] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->sidemenu['areas'] AS $aname => &$area) {
|
|
||||||
if (empty($area['enable']))
|
|
||||||
$area = array();
|
|
||||||
if (empty($area['subareas']))
|
|
||||||
continue;
|
|
||||||
ksort($area['subareas']);
|
|
||||||
|
|
||||||
foreach ($area['subareas'] AS $sname => &$subarea) {
|
|
||||||
if (empty($subarea['enable']))
|
|
||||||
$subarea = array();
|
|
||||||
if (empty($subarea['priorities']))
|
|
||||||
continue;
|
|
||||||
ksort($subarea['priorities']);
|
|
||||||
|
|
||||||
foreach ($subarea['priorities'] AS $pname => &$priority) {
|
|
||||||
if (empty($priority))
|
|
||||||
unset($subarea['priorities'][$pname]);
|
|
||||||
}
|
|
||||||
unset($priority);
|
|
||||||
|
|
||||||
if (empty($subarea['priorities']))
|
|
||||||
unset($area['subareas'][$sname]);
|
|
||||||
}
|
|
||||||
unset($subarea);
|
|
||||||
|
|
||||||
if (empty($area['subareas']))
|
|
||||||
unset($this->sidemenu['areas'][$aname]);
|
|
||||||
}
|
|
||||||
unset($area);
|
|
||||||
|
|
||||||
// Activate a default section (unless already specified)
|
|
||||||
foreach (array_reverse(array_diff_key($this->sidemenu['areas'], array('SANDBOX'=>1))) AS $area_name => $area) {
|
|
||||||
if (empty($area))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (empty($this->sidemenu['active']) ||
|
|
||||||
empty($this->sidemenu['areas'][$this->sidemenu['active']['area']]))
|
|
||||||
$this->sideMenuAreaActivate($area_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If generating reports, don't display the controller menu.
|
|
||||||
// Each report comes from a controller, but there is no need
|
|
||||||
// to present the controller actions, so remove that section
|
|
||||||
// from the menu.
|
|
||||||
if ($this->sidemenu['active']['area'] == 'REPORT')
|
|
||||||
$this->sideMenuEnable('CONTROLLER', null, false);
|
|
||||||
|
|
||||||
//pr($this->sidemenu);
|
|
||||||
$this->set('sidemenu', $this->sidemenu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reset_data() {
|
||||||
/**************************************************************************
|
$this->layout = null;
|
||||||
**************************************************************************
|
$this->autoLayout = false;
|
||||||
**************************************************************************
|
$this->autoRender = false;
|
||||||
* override: redirect
|
Configure::write('debug', '0');
|
||||||
*/
|
$script = $_SERVER['DOCUMENT_ROOT'] . '/pmgr/build.cmd';
|
||||||
|
echo "<P>" . date('r') . "\n";
|
||||||
function redirect($url, $status = null, $exit = true) {
|
//echo "<P>Script: $script" . "\n";
|
||||||
// OK, since the controller will not be able to
|
$db = & $this->Account->getDataSource();
|
||||||
// utilize our overriden url function in AppHelper,
|
$script .= ' "' . $db->config['database'] . '"';
|
||||||
// we'll have to do it manually here.
|
$script .= ' "' . $db->config['login'] . '"';
|
||||||
App::import('Helper', 'Html');
|
$script .= ' "' . $db->config['password'] . '"';
|
||||||
$url = HtmlHelper::url($url, true);
|
$handle = popen($script . ' 2>&1', 'r');
|
||||||
|
//echo "<P>Handle: $handle; " . gettype($handle) . "\n";
|
||||||
if (headers_sent()) {
|
echo "<P><PRE>\n";
|
||||||
// If we've already sent the headers, it's because
|
while (($read = fread($handle, 2096))) {
|
||||||
// we're debugging, and our debug output has gotten
|
echo $read;
|
||||||
// out before the redirect. That's probably a good
|
|
||||||
// thing, as we don't typically want pages to be
|
|
||||||
// jerked out from under us while trying to read
|
|
||||||
// the debug output. So, since we can't redirect
|
|
||||||
// anyway, we may as well go with the flow and just
|
|
||||||
// render this page instead, using an empty template
|
|
||||||
$this->set('message',
|
|
||||||
("Intended redirect:<P><BR>" .
|
|
||||||
'<A HREF="'.$url.'">'.$url.'</A>'));
|
|
||||||
|
|
||||||
echo $this->render('/empty');
|
|
||||||
if ($exit)
|
|
||||||
$this->_stop();
|
|
||||||
}
|
}
|
||||||
|
echo "</PRE>\n";
|
||||||
return parent::redirect($url, $status, $exit);
|
pclose($handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -480,14 +87,8 @@ class AppController extends Controller {
|
|||||||
* helper: gridView
|
* helper: gridView
|
||||||
* - called by derived controllers to create an index listing
|
* - called by derived controllers to create an index listing
|
||||||
*/
|
*/
|
||||||
function index() {
|
|
||||||
$names = Inflector::humanize(Inflector::pluralize($this->params['controller']));
|
|
||||||
$this->gridView('All ' . $names, 'all');
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridView($title, $action = null, $element = null) {
|
function gridView($title, $action = null, $element = null) {
|
||||||
$this->sideMenuEnable('SITE', $this->op_area);
|
|
||||||
$this->sideMenuAreaActivate('CONTROLLER');
|
|
||||||
$this->set('title', $title);
|
$this->set('title', $title);
|
||||||
// The resulting page will contain a grid, which will
|
// The resulting page will contain a grid, which will
|
||||||
// use ajax to obtain the actual data for this action
|
// use ajax to obtain the actual data for this action
|
||||||
@@ -558,10 +159,16 @@ class AppController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gridDataSetup(&$params) {
|
function gridDataSetup(&$params) {
|
||||||
// Debug only if requested
|
// Assume we're debugging.
|
||||||
$params['debug'] = !empty($this->passedArgs['debug']);
|
// The actual grid request will set this to false
|
||||||
|
$debug = true;
|
||||||
|
|
||||||
if ($params['debug']) {
|
if (isset($this->passedArgs['debug']))
|
||||||
|
$debug = $this->passedArgs['debug'];
|
||||||
|
|
||||||
|
$params['debug'] = $debug;
|
||||||
|
|
||||||
|
if ($debug) {
|
||||||
ob_start();
|
ob_start();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -580,26 +187,17 @@ class AppController extends Controller {
|
|||||||
// This SHOULD always be set, except when debugging
|
// This SHOULD always be set, except when debugging
|
||||||
if (isset($params['post']))
|
if (isset($params['post']))
|
||||||
$params['post'] = unserialize($params['post']);
|
$params['post'] = unserialize($params['post']);
|
||||||
else
|
|
||||||
$params['post'] = array();
|
|
||||||
|
|
||||||
// Unserialize our complex structure of dynamic post data
|
// Unserialize our complex structure of dynamic post data
|
||||||
if (isset($params['dynamic_post']))
|
if (isset($params['dynamic_post']))
|
||||||
$params['dynamic_post'] = unserialize($params['dynamic_post']);
|
$params['dynamic_post'] = unserialize($params['dynamic_post']);
|
||||||
else
|
|
||||||
$params['dynamic_post'] = null;
|
|
||||||
|
|
||||||
// Unserialize our complex structure of dynamic post data
|
|
||||||
if (isset($params['dynamic_post_replace']))
|
|
||||||
$params['dynamic_post_replace'] = unserialize($params['dynamic_post_replace']);
|
|
||||||
else
|
|
||||||
$params['dynamic_post_replace'] = null;
|
|
||||||
|
|
||||||
// Merge the static and dynamic post data
|
// Merge the static and dynamic post data
|
||||||
if (!empty($params['dynamic_post']))
|
if (empty($params['post']) && !empty($params['dynamic_post']))
|
||||||
|
$params['post'] = $params['dynamic_post'];
|
||||||
|
elseif (!empty($params['post']) && !empty($params['dynamic_post']))
|
||||||
|
//$params['post'] = array_merge($params['post'], $params['dynamic_post']);
|
||||||
$params['post'] = array_merge_recursive($params['post'], $params['dynamic_post']);
|
$params['post'] = array_merge_recursive($params['post'], $params['dynamic_post']);
|
||||||
if (!empty($params['dynamic_post_replace']))
|
|
||||||
$params['post'] = array_merge($params['post'], $params['dynamic_post_replace']);
|
|
||||||
|
|
||||||
// This SHOULD always be set, except when debugging
|
// This SHOULD always be set, except when debugging
|
||||||
if (!isset($params['post']['fields']))
|
if (!isset($params['post']['fields']))
|
||||||
@@ -624,7 +222,6 @@ class AppController extends Controller {
|
|||||||
$xml = preg_replace("/</", "<", $xml);
|
$xml = preg_replace("/</", "<", $xml);
|
||||||
$xml = preg_replace("/>/", ">", $xml);
|
$xml = preg_replace("/>/", ">", $xml);
|
||||||
echo ("\n<PRE>\n$xml\n</PRE>\n");
|
echo ("\n<PRE>\n$xml\n</PRE>\n");
|
||||||
$this->render_empty();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,12 +242,15 @@ class AppController extends Controller {
|
|||||||
// Grouping (which would not be typical)
|
// Grouping (which would not be typical)
|
||||||
$query['group'] = $this->gridDataCountGroup($params, $model);
|
$query['group'] = $this->gridDataCountGroup($params, $model);
|
||||||
|
|
||||||
|
// DEBUG PURPOSES ONLY!
|
||||||
|
$params['count_query'] = $query;
|
||||||
|
|
||||||
// Get the number of records prior to pagination
|
// Get the number of records prior to pagination
|
||||||
return $this->gridDataCountExecute($params, $model, $query);
|
return $this->gridDataCountExecute($params, $model, $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataCountExecute(&$params, &$model, $query) {
|
function gridDataCountExecute(&$params, &$model, $query) {
|
||||||
return $this->gridDataFind($params, $model, 'count', $query);
|
return $model->find('count', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataCountTables(&$params, &$model) {
|
function gridDataCountTables(&$params, &$model) {
|
||||||
@@ -868,9 +468,6 @@ class AppController extends Controller {
|
|||||||
$page = ($params['page'] <= 1) ? 1 : (($params['page'] > $total) ? $total : $params['page']);
|
$page = ($params['page'] <= 1) ? 1 : (($params['page'] > $total) ? $total : $params['page']);
|
||||||
$start = $limit * ($page - 1);
|
$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');
|
return compact('record_count', 'limit', 'page', 'start', 'total');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -902,11 +499,14 @@ class AppController extends Controller {
|
|||||||
isset($params['sidx']) ? $params['sidx'] : null,
|
isset($params['sidx']) ? $params['sidx'] : null,
|
||||||
isset($params['sord']) ? $params['sord'] : null);
|
isset($params['sord']) ? $params['sord'] : null);
|
||||||
|
|
||||||
|
// DEBUG PURPOSES ONLY!
|
||||||
|
$params['query'] = $query;
|
||||||
|
|
||||||
return $this->gridDataRecordsExecute($params, $model, $query);
|
return $this->gridDataRecordsExecute($params, $model, $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataRecordsExecute(&$params, &$model, $query) {
|
function gridDataRecordsExecute(&$params, &$model, $query) {
|
||||||
return $this->gridDataFind($params, $model, 'all', $query);
|
return $model->find('all', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
function gridDataTables(&$params, &$model) {
|
||||||
@@ -948,24 +548,12 @@ class AppController extends Controller {
|
|||||||
'value' => $params['filtValue']);
|
'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' => ''),
|
$ops = array('eq' => array('op' => null, 'pre' => '', 'post' => ''),
|
||||||
'ne' => array('op' => '<>', 'pre' => '', 'post' => ''),
|
'ne' => array('op' => '<>', 'pre' => '', 'post' => ''),
|
||||||
'lt' => array('op' => '<', 'pre' => '', 'post' => ''),
|
'lt' => array('op' => '<', 'pre' => '', 'post' => ''),
|
||||||
'le' => array('op' => '<=', 'pre' => '', 'post' => ''),
|
'le' => array('op' => '<=', 'pre' => '', 'post' => ''),
|
||||||
'gt' => array('op' => '>', 'pre' => '', 'post' => ''),
|
'gt' => array('op' => '>', 'pre' => '', 'post' => ''),
|
||||||
'ge' => array('op' => '>=', 'pre' => '', 'post' => ''),
|
'ge' => array('op' => '>=', 'pre' => '', 'post' => ''),
|
||||||
'in' => array('op' => 'IN', 'pre' => '(', 'post' => ')'),
|
|
||||||
'bw' => array('op' => 'LIKE', 'pre' => '', 'post' => '%'),
|
'bw' => array('op' => 'LIKE', 'pre' => '', 'post' => '%'),
|
||||||
'ew' => array('op' => 'LIKE', 'pre' => '%', 'post' => ''),
|
'ew' => array('op' => 'LIKE', 'pre' => '%', 'post' => ''),
|
||||||
'cn' => array('op' => 'LIKE', 'pre' => '%', 'post' => '%'),
|
'cn' => array('op' => 'LIKE', 'pre' => '%', 'post' => '%'),
|
||||||
@@ -1015,13 +603,6 @@ class AppController extends Controller {
|
|||||||
return $start . ', ' . $limit;
|
return $start . ', ' . $limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataFind(&$params, &$model, $type, $query) {
|
|
||||||
if ($params['debug'])
|
|
||||||
$params['queries'][] = compact('type', 'query');
|
|
||||||
|
|
||||||
return $model->find($type, $query);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -1042,7 +623,6 @@ class AppController extends Controller {
|
|||||||
$this->gridDataPostProcessLinks($params, $model, $records, array());
|
$this->gridDataPostProcessLinks($params, $model, $records, array());
|
||||||
|
|
||||||
// DEBUG PURPOSES ONLY!
|
// DEBUG PURPOSES ONLY!
|
||||||
//if ($params['debug'])
|
|
||||||
//$params['records'] = $records;
|
//$params['records'] = $records;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1061,7 +641,7 @@ class AppController extends Controller {
|
|||||||
foreach ($records AS &$record) {
|
foreach ($records AS &$record) {
|
||||||
// Add the calculated fields (if any), to the model fields
|
// Add the calculated fields (if any), to the model fields
|
||||||
if (isset($record[0])) {
|
if (isset($record[0])) {
|
||||||
$record[$model_alias] = $record[0] + $record[$model_alias];
|
$record[$model_alias] += $record[0];
|
||||||
unset($record[0]);
|
unset($record[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1100,15 +680,12 @@ class AppController extends Controller {
|
|||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
// Don't create any links if ordered not to.
|
// Don't create any links if ordered not to.
|
||||||
if (isset($params['post']['nolinks']))
|
if (isset($params['nolinks']))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
App::import('Helper', 'Html');
|
|
||||||
|
|
||||||
foreach ($links AS $table => $fields) {
|
foreach ($links AS $table => $fields) {
|
||||||
$special = array('controller', 'action', 'id');
|
$special = array('controller', 'id');
|
||||||
$controller = Inflector::pluralize(Inflector::underscore($table));
|
$controller = Inflector::pluralize(Inflector::underscore($table));
|
||||||
$action = 'view';
|
|
||||||
$id = 'id';
|
$id = 'id';
|
||||||
extract(array_intersect_key($fields, array_flip($special)));
|
extract(array_intersect_key($fields, array_flip($special)));
|
||||||
foreach ($records AS &$record) {
|
foreach ($records AS &$record) {
|
||||||
@@ -1120,13 +697,12 @@ class AppController extends Controller {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// DEBUG PURPOSES ONLY!
|
// DEBUG PURPOSES ONLY!
|
||||||
//if ($params['debug'])
|
|
||||||
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
|
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
|
||||||
$record[$table][$field] =
|
$record[$table][$field] =
|
||||||
'<A HREF="' .
|
'<A HREF="' .
|
||||||
HtmlHelper::url(array('controller' => $controller,
|
Router::url(array('controller' => $controller,
|
||||||
'action' => $action,
|
'action' => 'view',
|
||||||
$record[$table][$id])) .
|
$record[$table][$id])) .
|
||||||
'">' .
|
'">' .
|
||||||
$record[$table][$field] .
|
$record[$table][$field] .
|
||||||
'</A>';
|
'</A>';
|
||||||
@@ -1151,8 +727,9 @@ class AppController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gridDataOutputHeader(&$params, &$model) {
|
function gridDataOutputHeader(&$params, &$model) {
|
||||||
if (!$params['debug'])
|
if (!$params['debug']) {
|
||||||
header("Content-type: text/xml;charset=utf-8");
|
header("Content-type: text/xml;charset=utf-8");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataOutputXMLHeader(&$params, &$model) {
|
function gridDataOutputXMLHeader(&$params, &$model) {
|
||||||
@@ -1168,8 +745,7 @@ class AppController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gridDataOutputSummary(&$params, &$model, $pagination) {
|
function gridDataOutputSummary(&$params, &$model, $pagination) {
|
||||||
if ($params['debug'])
|
echo " <params><![CDATA[\n" . print_r($params, true) . "\n]]></params>\n";
|
||||||
echo " <params><![CDATA[\n" . print_r($params, true) . "\n]]></params>\n";
|
|
||||||
echo " <page>{$pagination['page']}</page>\n";
|
echo " <page>{$pagination['page']}</page>\n";
|
||||||
echo " <total>{$pagination['total']}</total>\n";
|
echo " <total>{$pagination['total']}</total>\n";
|
||||||
echo " <records>{$pagination['record_count']}</records>\n";
|
echo " <records>{$pagination['record_count']}</records>\n";
|
||||||
@@ -1210,33 +786,11 @@ class AppController extends Controller {
|
|||||||
|
|
||||||
function gridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
|
function gridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
|
||||||
// be sure to put text data in CDATA
|
// be sure to put text data in CDATA
|
||||||
if (preg_match("/^[\d.]*$/", $data))
|
if (preg_match("/^\d*$/", $data))
|
||||||
echo " <cell>$data</cell>\n";
|
echo " <cell>$data</cell>\n";
|
||||||
else
|
else
|
||||||
echo " <cell><![CDATA[$data]]></cell>\n";
|
echo " <cell><![CDATA[$data]]></cell>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
function authorize($name) {
|
|
||||||
if ($this->Permission->deny($name))
|
|
||||||
$this->UNAUTHORIZED("Unauthorized: $name");
|
|
||||||
}
|
|
||||||
|
|
||||||
function UNAUTHORIZED($msg) {
|
|
||||||
//$this->redirect('controller' => '???', 'action' => 'login');
|
|
||||||
//$this->render('/unauthorized');
|
|
||||||
$this->set('message', '<H2>' . $msg . '</H2>');
|
|
||||||
$this->render_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
function INTERNAL_ERROR($msg, $depth = 0) {
|
|
||||||
INTERNAL_ERROR($msg, false, $depth+1);
|
|
||||||
$this->render_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
function render_empty() {
|
|
||||||
echo $this->render('/empty');
|
|
||||||
$this->_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -37,14 +37,5 @@ App::import('Core', 'Helper');
|
|||||||
* @subpackage cake.cake
|
* @subpackage cake.cake
|
||||||
*/
|
*/
|
||||||
class AppHelper extends Helper {
|
class AppHelper extends Helper {
|
||||||
|
|
||||||
function url($url = null, $full = false) {
|
|
||||||
foreach(array('sand_route', 'dev_route') AS $mod) {
|
|
||||||
if (isset($this->params[$mod]) && is_array($url) && !isset($url[$mod]))
|
|
||||||
$url[$mod] = $this->params[$mod];
|
|
||||||
}
|
|
||||||
return parent::url($url, $full);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -42,10 +42,6 @@ class AppModel extends Model {
|
|||||||
var $useNullForEmpty = true;
|
var $useNullForEmpty = true;
|
||||||
var $formatDateFields = true;
|
var $formatDateFields = true;
|
||||||
|
|
||||||
// Loaded related models with no association
|
|
||||||
var $knows = array();
|
|
||||||
var $app_knows = array('Option');
|
|
||||||
|
|
||||||
// Default Log Level, if not specified at the function level
|
// Default Log Level, if not specified at the function level
|
||||||
var $default_log_level = 5;
|
var $default_log_level = 5;
|
||||||
|
|
||||||
@@ -62,35 +58,16 @@ class AppModel extends Model {
|
|||||||
var $max_log_level;
|
var $max_log_level;
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
// REVISIT <AP>: 20090730
|
||||||
**************************************************************************
|
// Why is this constructor crashing?
|
||||||
**************************************************************************
|
// Clearly it's in some sort of infinite
|
||||||
* function: __construct
|
// loop, but it seems the correct way
|
||||||
*/
|
// to have a constructor call the parent...
|
||||||
|
|
||||||
function __construct($id = false, $table = null, $ds = null) {
|
|
||||||
parent::__construct($id, $table, $ds);
|
|
||||||
|
|
||||||
$this->knows = array_merge($this->app_knows, $this->knows);
|
|
||||||
//$this->pr(1, array('knows' => $this->knows));
|
|
||||||
foreach ($this->knows as $alias => $modelName) {
|
|
||||||
if (is_numeric($alias)) {
|
|
||||||
$alias = $modelName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't overwrite any existing alias
|
|
||||||
if (!empty($this->{$alias}) || get_class($this) == $alias)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$model = array('class' => $modelName, 'alias' => $alias);
|
|
||||||
if (PHP5) {
|
|
||||||
$this->{$alias} = ClassRegistry::init($model);
|
|
||||||
} else {
|
|
||||||
$this->{$alias} =& ClassRegistry::init($model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* function __construct() { */
|
||||||
|
/* parent::__construct(); */
|
||||||
|
/* $this->prClassLevel(5, 'Model'); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -104,8 +81,7 @@ class AppModel extends Model {
|
|||||||
$caller = array_shift($trace);
|
$caller = array_shift($trace);
|
||||||
$caller = array_shift($trace);
|
$caller = array_shift($trace);
|
||||||
if (empty($class))
|
if (empty($class))
|
||||||
$class = get_class($this);
|
$class = $caller['class'];
|
||||||
$this->pr(50, compact('class', 'level'));
|
|
||||||
$this->class_log_level[$class] = $level;
|
$this->class_log_level[$class] = $level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,10 +90,9 @@ class AppModel extends Model {
|
|||||||
$caller = array_shift($trace);
|
$caller = array_shift($trace);
|
||||||
$caller = array_shift($trace);
|
$caller = array_shift($trace);
|
||||||
if (empty($class))
|
if (empty($class))
|
||||||
$class = get_class($this);
|
$class = $caller['class'];
|
||||||
if (empty($function))
|
if (empty($function))
|
||||||
$function = $caller['function'];
|
$function = $caller['function'];
|
||||||
$this->pr(50, compact('class', 'function', 'level'));
|
|
||||||
$this->function_log_level["{$class}-{$function}"] = $level;
|
$this->function_log_level["{$class}-{$function}"] = $level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,48 +114,20 @@ class AppModel extends Model {
|
|||||||
$line = $caller['line'];
|
$line = $caller['line'];
|
||||||
|
|
||||||
// So, this caller holds the calling function name
|
// So, this caller holds the calling function name
|
||||||
$caller = $trace[0];
|
$caller = array_shift($trace);
|
||||||
$function = $caller['function'];
|
$function = $caller['function'];
|
||||||
$class = $caller['class'];
|
$class = $caller['class'];
|
||||||
//$class = $this->name;
|
//$class = $this->name;
|
||||||
|
|
||||||
// Use class or function specific log level if available
|
// Adjust the log level from default, if necessary
|
||||||
if (isset($this->class_log_level[$class]))
|
if (isset($this->class_log_level[$class]))
|
||||||
$log_level = $this->class_log_level[$class];
|
$log_level = $this->class_log_level[$class];
|
||||||
if (isset($this->function_log_level["{$class}-{$function}"]))
|
if (isset($this->function_log_level["{$class}-{$function}"]))
|
||||||
$log_level = $this->function_log_level["{$class}-{$function}"];
|
$log_level = $this->function_log_level["{$class}-{$function}"];
|
||||||
|
if (isset($this->min_log_level))
|
||||||
// Establish log level minimums
|
$log_level = max($log_level, $this->min_log_level);
|
||||||
$min_log_level = $this->min_log_level;
|
if (isset($this->max_log_level))
|
||||||
if (is_array($this->min_log_level)) {
|
$log_level = min($log_level, $this->max_log_level);
|
||||||
$min_show_level = $min_log_level['show'];
|
|
||||||
$min_log_level = $min_log_level['log'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establish log level maximums
|
|
||||||
$max_log_level = $this->max_log_level;
|
|
||||||
if (is_array($this->max_log_level)) {
|
|
||||||
$max_show_level = $max_log_level['show'];
|
|
||||||
$max_log_level = $max_log_level['log'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the applicable log and show levels
|
|
||||||
if (is_array($log_level)) {
|
|
||||||
$show_level = $log_level['show'];
|
|
||||||
$log_level = $log_level['log'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adjust log level up/down to min/max
|
|
||||||
if (isset($min_log_level))
|
|
||||||
$log_level = max($log_level, $min_log_level);
|
|
||||||
if (isset($max_log_level))
|
|
||||||
$log_level = min($log_level, $max_log_level);
|
|
||||||
|
|
||||||
// Adjust show level up/down to min/max
|
|
||||||
if (isset($min_show_level))
|
|
||||||
$show_level = max($show_level, $min_show_level);
|
|
||||||
if (isset($max_show_level))
|
|
||||||
$show_level = min($show_level, $max_show_level);
|
|
||||||
|
|
||||||
// If the level is insufficient, bail out
|
// If the level is insufficient, bail out
|
||||||
if ($level > $log_level)
|
if ($level > $log_level)
|
||||||
@@ -194,87 +141,13 @@ class AppModel extends Model {
|
|||||||
$mixed = $chk + array($mixed);
|
$mixed = $chk + array($mixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static $pr_unique_number = 0;
|
echo '<DIV CLASS="pr-caller">';
|
||||||
$pr_id = 'pr-section-class-' . $class . '-print-' . (++$pr_unique_number);
|
echo '<strong>' . substr(str_replace(ROOT, '', $file), 1) . '</strong>';
|
||||||
$pr_trace_id = $pr_id . '-trace';
|
echo ' (line <strong>' . $line . '</strong>)';
|
||||||
$pr_output_id = $pr_id . '-output';
|
echo ' : level-' . $level;
|
||||||
|
echo '</DIV>' . "\n";
|
||||||
|
|
||||||
$pr_entire_base_class = "pr-section";
|
pr(array("{$class}::{$function}()" => $mixed), false, false);
|
||||||
$pr_entire_class_class = $pr_entire_base_class . '-class-' . $class;
|
|
||||||
$pr_entire_function_class = $pr_entire_class_class . '-function-' . $function;
|
|
||||||
$pr_entire_class = "$pr_entire_base_class $pr_entire_class_class $pr_entire_function_class";
|
|
||||||
$pr_header_class = "pr-caller";
|
|
||||||
$pr_trace_class = "pr-trace";
|
|
||||||
$pr_output_base_class = 'pr-output';
|
|
||||||
$pr_output_class_class = $pr_output_base_class . '-class-' . $class;
|
|
||||||
$pr_output_function_class = $pr_output_class_class . '-function-' . $function;
|
|
||||||
$pr_output_class = "$pr_output_base_class $pr_output_class_class $pr_output_function_class";
|
|
||||||
|
|
||||||
echo '<DIV class="'.$pr_entire_class.'" id="'.$pr_id.'">'."\n";
|
|
||||||
echo '<DIV class="'.$pr_header_class.'">'."\n";
|
|
||||||
echo '<DIV class="'.$pr_trace_class.'" id="'.$pr_trace_id.'" style="display:none;">'."\n";
|
|
||||||
echo '<HR />' . "\n";
|
|
||||||
|
|
||||||
// Flip trace around so the sequence flows from top to bottom
|
|
||||||
// Then print out the entire stack trace (in hidden div)
|
|
||||||
$trace = array_reverse($trace);
|
|
||||||
for ($i = 0; $i < count($trace); ++$i) {
|
|
||||||
$bline = $trace[$i]['line'];
|
|
||||||
$bfile = $trace[$i]['file'];
|
|
||||||
$bfile = str_replace(ROOT.DS, '', $bfile);
|
|
||||||
$bfile = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $bfile);
|
|
||||||
|
|
||||||
if ($i > 0) {
|
|
||||||
$bfunc = $trace[$i-1]['function'];
|
|
||||||
$bclas = $trace[$i-1]['class'];
|
|
||||||
} else {
|
|
||||||
$bfunc = null;
|
|
||||||
$bclas = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo("$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")<BR>\n");
|
|
||||||
//echo(($bclas ? "$bclas::$bfunc" : "entry point") . "; $bfile : $bline<BR>\n");
|
|
||||||
}
|
|
||||||
echo '</DIV>' . "\n"; // End pr_trace_class
|
|
||||||
$file = str_replace(ROOT.DS, '', $file);
|
|
||||||
$file = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $file);
|
|
||||||
|
|
||||||
echo "<strong>$file:$line ($class::$function)</strong>" . ";\n";
|
|
||||||
/* $log_show_level = isset($show_level) ? $show_level : '?'; */
|
|
||||||
/* echo ' L' . $level . "({$log_level}/{$log_show_level})" . ";\n"; */
|
|
||||||
echo ' L' . $level . ";\n";
|
|
||||||
echo ' <A HREF="#" onclick="$' . "('#{$pr_trace_id}').slideToggle(); return false;" . '">stack</A>'.";\n";
|
|
||||||
|
|
||||||
echo " this ";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('#{$pr_output_id}').slideToggle(); return false;" . '">t</A>'."/";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('#{$pr_id}').hide(); return false;" . '">n</A>'.";\n";
|
|
||||||
|
|
||||||
echo " $class ";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_class_class}').slideDown(); return false;" . '">s</A>'."/";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_class_class}').slideUp(); return false;" . '">h</A>'."/";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_class_class}').hide(); return false;" . '">n</A>'.";\n";
|
|
||||||
|
|
||||||
echo " $function ";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_function_class}').slideDown(); return false;" . '">s</A>'."/";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_function_class}').slideUp(); return false;" . '">h</A>'."/";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_function_class}').hide(); return false;" . '">n</A>'.";\n";
|
|
||||||
|
|
||||||
echo " all ";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_base_class}').show(); return false;" . '">s</A>'."/";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_output_base_class}').hide(); return false;" . '">h</A>'."/";
|
|
||||||
echo '<A HREF="#" onclick="$' . "('.{$pr_entire_base_class}').hide(); return false;" . '">n</A>'."\n";
|
|
||||||
|
|
||||||
echo '</DIV>' . "\n"; // End pr_header_class
|
|
||||||
|
|
||||||
if (isset($show_level) && $level > $show_level)
|
|
||||||
$display = 'none';
|
|
||||||
else
|
|
||||||
$display = 'block';
|
|
||||||
|
|
||||||
echo '<DIV class="'.$pr_output_class.'" id="'.$pr_output_id.'" style="display:'.$display.';">'."\n";
|
|
||||||
pr($mixed, false, false);
|
|
||||||
echo '</DIV>' . "\n"; // End pr_output_class
|
|
||||||
echo '</DIV>' . "\n"; // End pr_entire_class
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pr($level, $mixed, $checkpoint = null) {
|
function pr($level, $mixed, $checkpoint = null) {
|
||||||
@@ -305,9 +178,7 @@ class AppModel extends Model {
|
|||||||
if (preg_match("/^_/", $name) && !$all)
|
if (preg_match("/^_/", $name) && !$all)
|
||||||
unset($vars[$name]);
|
unset($vars[$name]);
|
||||||
}
|
}
|
||||||
//$vars['class'] = get_class_vars(get_class($this));
|
pr($vars);
|
||||||
|
|
||||||
$this->pr(1, $vars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -429,10 +300,6 @@ class AppModel extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function filter_null($array) {
|
|
||||||
return array_diff_key($array, array_filter($array, 'is_null'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function recursive_array_replace($find, $replace, &$data) {
|
function recursive_array_replace($find, $replace, &$data) {
|
||||||
if (!isset($data))
|
if (!isset($data))
|
||||||
return;
|
return;
|
||||||
@@ -507,12 +374,4 @@ class AppModel extends Model {
|
|||||||
return date('Y-m-d', strtotime($dateString));
|
return date('Y-m-d', strtotime($dateString));
|
||||||
}
|
}
|
||||||
|
|
||||||
function INTERNAL_ERROR($msg, $depth = 0, $force_stop = false) {
|
|
||||||
INTERNAL_ERROR($msg, $force_stop, $depth+1);
|
|
||||||
echo $this->requestAction(array('controller' => 'util',
|
|
||||||
'action' => 'render_empty'),
|
|
||||||
array('return', 'bare' => false)
|
|
||||||
);
|
|
||||||
$this->_stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/* SVN FILE: $Id: bootstrap.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||||
|
/**
|
||||||
|
* Short description for file.
|
||||||
|
*
|
||||||
|
* Long description for file
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
||||||
|
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||||
|
*
|
||||||
|
* Licensed under The MIT License
|
||||||
|
* Redistributions of files must retain the above copyright notice.
|
||||||
|
*
|
||||||
|
* @filesource
|
||||||
|
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||||
|
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
||||||
|
* @package cake
|
||||||
|
* @subpackage cake.app.config
|
||||||
|
* @since CakePHP(tm) v 0.10.8.2117
|
||||||
|
* @version $Revision: 7945 $
|
||||||
|
* @modifiedby $LastChangedBy: gwoo $
|
||||||
|
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This file is loaded automatically by the app/webroot/index.php file after the core bootstrap.php is loaded
|
||||||
|
* This is an application wide file to load any function that is not used within a class define.
|
||||||
|
* You can also use this to include or require any files in your application.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* The settings below can be used to set additional paths to models, views and controllers.
|
||||||
|
* This is related to Ticket #470 (https://trac.cakephp.org/ticket/470)
|
||||||
|
*
|
||||||
|
* $modelPaths = array('full path to models', 'second full path to models', 'etc...');
|
||||||
|
* $viewPaths = array('this path to views', 'second full path to views', 'etc...');
|
||||||
|
* $controllerPaths = array('this path to controllers', 'second full path to controllers', 'etc...');
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//EOF
|
||||||
|
?>
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
/**
|
/**
|
||||||
* The name of CakePHP's session cookie.
|
* The name of CakePHP's session cookie.
|
||||||
*/
|
*/
|
||||||
Configure::write('Session.cookie', 'PMGR');
|
Configure::write('Session.cookie', 'CAKEPHP');
|
||||||
/**
|
/**
|
||||||
* Session time out time (in seconds).
|
* Session time out time (in seconds).
|
||||||
* Actual value depends on 'Security.level' setting.
|
* Actual value depends on 'Security.level' setting.
|
||||||
@@ -10,12 +10,5 @@ class DATABASE_CONFIG {
|
|||||||
'database' => 'property_manager',
|
'database' => 'property_manager',
|
||||||
'prefix' => 'pmgr_',
|
'prefix' => 'pmgr_',
|
||||||
);
|
);
|
||||||
|
|
||||||
function __construct() {
|
|
||||||
if (devbox())
|
|
||||||
$this->default['database'] = 'pmgr_dev';
|
|
||||||
if (sandbox())
|
|
||||||
$this->default['database'] = 'pmgr_sand';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/* SVN FILE: $Id: routes.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||||
|
/**
|
||||||
|
* Short description for file.
|
||||||
|
*
|
||||||
|
* In this file, you set up routes to your controllers and their actions.
|
||||||
|
* Routes are very important mechanism that allows you to freely connect
|
||||||
|
* different urls to chosen controllers and their actions (functions).
|
||||||
|
*
|
||||||
|
* PHP versions 4 and 5
|
||||||
|
*
|
||||||
|
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
||||||
|
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||||
|
*
|
||||||
|
* Licensed under The MIT License
|
||||||
|
* Redistributions of files must retain the above copyright notice.
|
||||||
|
*
|
||||||
|
* @filesource
|
||||||
|
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||||
|
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
||||||
|
* @package cake
|
||||||
|
* @subpackage cake.app.config
|
||||||
|
* @since CakePHP(tm) v 0.2.9
|
||||||
|
* @version $Revision: 7945 $
|
||||||
|
* @modifiedby $LastChangedBy: gwoo $
|
||||||
|
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
||||||
|
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here, we are connecting '/' (base path) to our site map.
|
||||||
|
* It's hardcoded to map #1, but at some point we'll implement
|
||||||
|
* a login mechanism and the default path will be to log on instead.
|
||||||
|
*/
|
||||||
|
Router::connect('/', array('controller' => 'maps', 'action' => 'view', '1'));
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -2,38 +2,33 @@
|
|||||||
|
|
||||||
class AccountsController extends AppController {
|
class AccountsController extends AppController {
|
||||||
|
|
||||||
|
var $uses = array('Account', 'LedgerEntry');
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Accounts', 'header' => true),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'accounts', 'action' => 'all')),
|
||||||
|
array('name' => 'Asset', 'url' => array('controller' => 'accounts', 'action' => 'asset')),
|
||||||
|
array('name' => 'Liability', 'url' => array('controller' => 'accounts', 'action' => 'liability')),
|
||||||
|
array('name' => 'Equity', 'url' => array('controller' => 'accounts', 'action' => 'equity')),
|
||||||
|
array('name' => 'Income', 'url' => array('controller' => 'accounts', 'action' => 'income')),
|
||||||
|
array('name' => 'Expense', 'url' => array('controller' => 'accounts', 'action' => 'expense')),
|
||||||
|
array('name' => 'Deposits', 'header' => true),
|
||||||
|
array('name' => 'Prior Deposits', 'url' => array('controller' => 'transactions', 'action' => 'deposit')),
|
||||||
|
array('name' => 'New Deposit', 'url' => array('controller' => 'tenders', 'action' => 'deposit')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
* override: addGridViewSideMenuLinks
|
* override: sideMenuLinks
|
||||||
* - Adds grid view navigation side menu links
|
* - Generates controller specific links for the side menu
|
||||||
*/
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
function addGridViewSideMenuLinks() {
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
parent::addGridViewSideMenuLinks();
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Asset',
|
|
||||||
array('controller' => 'accounts', 'action' => 'asset'), null,
|
|
||||||
'CONTROLLER', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Liability',
|
|
||||||
array('controller' => 'accounts', 'action' => 'liability'), null,
|
|
||||||
'CONTROLLER', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Equity',
|
|
||||||
array('controller' => 'accounts', 'action' => 'equity'), null,
|
|
||||||
'CONTROLLER', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Income',
|
|
||||||
array('controller' => 'accounts', 'action' => 'income'), null,
|
|
||||||
'CONTROLLER', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('Expense',
|
|
||||||
array('controller' => 'accounts', 'action' => 'expense'), null,
|
|
||||||
'CONTROLLER', $this->admin_area);
|
|
||||||
$this->addSideMenuLink('All',
|
|
||||||
array('controller' => 'accounts', 'action' => 'all'), null,
|
|
||||||
'CONTROLLER', $this->admin_area);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -47,7 +42,7 @@ class AccountsController extends AppController {
|
|||||||
function equity() { $this->gridView('Equity Accounts'); }
|
function equity() { $this->gridView('Equity Accounts'); }
|
||||||
function income() { $this->gridView('Income Accounts'); }
|
function income() { $this->gridView('Income Accounts'); }
|
||||||
function expense() { $this->gridView('Expense Accounts'); }
|
function expense() { $this->gridView('Expense Accounts'); }
|
||||||
function all() { $this->gridView('All Accounts', 'all'); }
|
function all() { $this->gridView('All Accounts', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
@@ -98,9 +93,6 @@ class AccountsController extends AppController {
|
|||||||
$conditions[] = array('Account.type' => strtoupper($params['action']));
|
$conditions[] = array('Account.type' => strtoupper($params['action']));
|
||||||
}
|
}
|
||||||
|
|
||||||
$conditions[] = array('Account.level >=' =>
|
|
||||||
$this->Permission->level('controller.accounts'));
|
|
||||||
|
|
||||||
return $conditions;
|
return $conditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,15 +138,17 @@ class AccountsController extends AppController {
|
|||||||
$this->redirect(array('action'=>'index'));
|
$this->redirect(array('action'=>'index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$payment_accounts = $this->Account->collectableAccounts();
|
||||||
|
//$payment_accounts[$this->Account->nameToID('Closing')] = 'Closing';
|
||||||
|
//$payment_accounts[$this->Account->nameToID('Equity')] = 'Equity';
|
||||||
|
$default_accounts = array_diff_key($this->Account->paymentAccounts(),
|
||||||
|
array($this->Account->concessionAccountID() => 1));
|
||||||
|
$this->set(compact('payment_accounts', 'default_accounts'));
|
||||||
|
|
||||||
$this->Account->recursive = -1;
|
$this->Account->recursive = -1;
|
||||||
$account = $this->Account->read(null, $id);
|
$account = $this->Account->read(null, $id);
|
||||||
$account = $account['Account'];
|
$account = $account['Account'];
|
||||||
|
|
||||||
$accounts = $this->Account->collectableAccounts();
|
|
||||||
$payment_accounts = $accounts['all'];
|
|
||||||
$default_accounts = $accounts['default'];
|
|
||||||
$this->set(compact('payment_accounts', 'default_accounts'));
|
|
||||||
|
|
||||||
$title = ($account['name'] . ': Collected Report');
|
$title = ($account['name'] . ': Collected Report');
|
||||||
$this->set(compact('account', 'title'));
|
$this->set(compact('account', 'title'));
|
||||||
}
|
}
|
||||||
@@ -168,6 +162,12 @@ class AccountsController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function view($id = null) {
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get details about the account and its ledgers (no ledger entries yet)
|
||||||
$account = $this->Account->find
|
$account = $this->Account->find
|
||||||
('first',
|
('first',
|
||||||
array('contain' =>
|
array('contain' =>
|
||||||
@@ -179,32 +179,33 @@ class AccountsController extends AppController {
|
|||||||
array('CloseTransaction' => array
|
array('CloseTransaction' => array
|
||||||
('order' => array('CloseTransaction.stamp' => 'DESC'))),
|
('order' => array('CloseTransaction.stamp' => 'DESC'))),
|
||||||
),
|
),
|
||||||
'conditions' => array(array('Account.id' => $id),
|
'conditions' => array(array('Account.id' => $id)),
|
||||||
array('Account.level >=' =>
|
|
||||||
$this->Permission->level('controller.accounts')),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (empty($account)) {
|
// Get all ledger entries of the CURRENT ledger
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
$entries = $this->Account->ledgerEntries($id);
|
||||||
$this->redirect(array('action'=>'index'));
|
//pr(compact('entries'));
|
||||||
}
|
$account['CurrentLedger']['LedgerEntry'] = $entries;
|
||||||
|
|
||||||
// Obtain stats across ALL ledgers for the summary infobox
|
// Obtain stats across ALL ledgers for the summary infobox
|
||||||
$stats = $this->Account->stats($id, true);
|
$stats = $this->Account->stats($id, true);
|
||||||
$stats = $stats['Ledger'];
|
$stats = $stats['Ledger'];
|
||||||
|
|
||||||
$this->addSideMenuLink('New Ledger',
|
$this->sidemenu_links[] =
|
||||||
array('action' => 'newledger', $id), null,
|
array('name' => 'Operations', 'header' => true);
|
||||||
'ACTION', $this->admin_area);
|
$this->sidemenu_links[] =
|
||||||
$this->addSideMenuLink('Collected',
|
array('name' => 'New Ledger', 'url' => array('action' => 'newledger', $id));
|
||||||
array('action' => 'collected', $id), null,
|
$this->sidemenu_links[] =
|
||||||
'ACTION', $this->admin_area);
|
array('name' => 'Collected', 'url' => array('action' => 'collected', $id));
|
||||||
|
|
||||||
// Prepare to render
|
// Prepare to render
|
||||||
$title = 'Account: ' . $account['Account']['name'];
|
$title = 'Account: ' . $account['Account']['name'];
|
||||||
$this->set(compact('account', 'title', 'stats'));
|
$this->set(compact('account', 'title', 'stats'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tst($id) {
|
||||||
|
//$entries = $this->Account->($id);
|
||||||
|
pr($entries);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,19 @@
|
|||||||
|
|
||||||
class ContactsController extends AppController {
|
class ContactsController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links = array();
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -23,34 +35,19 @@ class ContactsController extends AppController {
|
|||||||
* to jqGrid.
|
* to jqGrid.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function gridDataFilterTablesConfig(&$params, &$model, $table) {
|
|
||||||
$config = parent::gridDataFilterTablesConfig($params, $model, $table);
|
|
||||||
|
|
||||||
// Special case for Customer; We need the Contact/Customer relationship
|
|
||||||
if ($table == 'Customer')
|
|
||||||
$config = array('fields' => array('ContactsCustomer.type',
|
|
||||||
'ContactsCustomer.active'),
|
|
||||||
'conditions' => array('ContactsCustomer.active' => true),
|
|
||||||
);
|
|
||||||
|
|
||||||
return $config;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||||
|
if ($index === 'Contact.last_name') {
|
||||||
// After sorting by whatever the user wants, add these
|
$order[] = 'Contact.first_name ' . $direction;
|
||||||
// defaults into the sort mechanism. If we're already
|
}
|
||||||
// sorting by one of them, it will only be redundant,
|
if ($index === 'Contact.first_name') {
|
||||||
// and should cause no harm (possible a longer query?)
|
$order[] = 'Contact.last_name ' . $direction;
|
||||||
$order[] = 'Contact.last_name ' . $direction;
|
}
|
||||||
$order[] = 'Contact.first_name ' . $direction;
|
|
||||||
|
|
||||||
return $order;
|
return $order;
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
$links['Contact'] = array('display_name');
|
$links['Contact'] = array('id');
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,9 +78,13 @@ class ContactsController extends AppController {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// Set up dynamic menu items
|
// Set up dynamic menu items
|
||||||
$this->addSideMenuLink('Edit',
|
$this->sidemenu_links[] =
|
||||||
array('action' => 'edit', $id), null,
|
array('name' => 'Operations', 'header' => true);
|
||||||
'ACTION');
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Edit',
|
||||||
|
'url' => array('action' => 'edit',
|
||||||
|
$id));
|
||||||
|
|
||||||
// Prepare to render.
|
// Prepare to render.
|
||||||
$title = 'Contact: ' . $contact['Contact']['display_name'];
|
$title = 'Contact: ' . $contact['Contact']['display_name'];
|
||||||
@@ -125,6 +126,8 @@ class ContactsController extends AppController {
|
|||||||
|
|
||||||
// Now that the work is done, let the user view the updated contact
|
// Now that the work is done, let the user view the updated contact
|
||||||
$this->redirect(array('action'=>'view', $this->data['Contact']['id']));
|
$this->redirect(array('action'=>'view', $this->data['Contact']['id']));
|
||||||
|
//$this->render('/empty');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($id) {
|
if ($id) {
|
||||||
@@ -0,0 +1,457 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class CustomersController extends AppController {
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Customers', 'header' => true),
|
||||||
|
array('name' => 'Current', 'url' => array('controller' => 'customers', 'action' => 'current')),
|
||||||
|
array('name' => 'Past', 'url' => array('controller' => 'customers', 'action' => 'past')),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'customers', 'action' => 'all')),
|
||||||
|
array('name' => 'Add Customer', 'url' => array('controller' => 'customers', 'action' => 'add')),
|
||||||
|
);
|
||||||
|
|
||||||
|
//var $components = array('RequestHandler');
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: index / current / past / all
|
||||||
|
* - Creates a list of customers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->current(); }
|
||||||
|
function current() { $this->gridView('Current Tenants', 'current'); }
|
||||||
|
function past() { $this->gridView('Past Tenants'); }
|
||||||
|
function all() { $this->gridView('All Customers'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* 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(// Models
|
||||||
|
'PrimaryContact',
|
||||||
|
'CurrentLease' => array('fields' => array()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataTables(&$params, &$model) {
|
||||||
|
$link = $this->gridDataCountTables($params, $model);
|
||||||
|
// StatementEntry is needed to determine customer balance
|
||||||
|
$link['link']['StatementEntry'] = array('fields' => array());
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataFields(&$params, &$model) {
|
||||||
|
$fields = parent::gridDataFields($params, $model);
|
||||||
|
$fields[] = ('COUNT(DISTINCT CurrentLease.id) AS lease_count');
|
||||||
|
return array_merge($fields,
|
||||||
|
$this->Customer->StatementEntry->chargePaymentFields(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::gridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if ($params['action'] === 'current') {
|
||||||
|
$conditions[] = 'CurrentLease.id IS NOT NULL';
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'past') {
|
||||||
|
$conditions[] = 'CurrentLease.id IS NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
$order = array();
|
||||||
|
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
|
||||||
|
|
||||||
|
if ($index !== 'PrimaryContact.last_name')
|
||||||
|
$order[] = parent::gridDataOrder($params, $model,
|
||||||
|
'PrimaryContact.last_name', $direction);
|
||||||
|
if ($index !== 'PrimaryContact.first_name')
|
||||||
|
$order[] = parent::gridDataOrder($params, $model,
|
||||||
|
'PrimaryContact.first_name', $direction);
|
||||||
|
if ($index !== 'Customer.id')
|
||||||
|
$order[] = parent::gridDataOrder($params, $model,
|
||||||
|
'Customer.id', $direction);
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataCount(&$params, &$model) {
|
||||||
|
|
||||||
|
if ($params['action'] != 'current')
|
||||||
|
return parent::gridDataCount($params, $model);
|
||||||
|
|
||||||
|
// OK, for current customers, we have an issue.
|
||||||
|
// We don't have a good way to use the query to obtain
|
||||||
|
// our count. The problem is that we're relying on the
|
||||||
|
// group by for the query, but that simply won't work
|
||||||
|
// for the count. However, it's not difficult to simply
|
||||||
|
// derive it since 'current' customers are mutually
|
||||||
|
// exclusive to 'past' customers.
|
||||||
|
|
||||||
|
$tmp_params = $params;
|
||||||
|
$tmp_params['action'] = 'all';
|
||||||
|
$all_count = parent::gridDataCount($tmp_params, $model);
|
||||||
|
$tmp_params['action'] = 'past';
|
||||||
|
$past_count = parent::gridDataCount($tmp_params, $model);
|
||||||
|
|
||||||
|
// The current customer count is simply calculated
|
||||||
|
// as all customers that are not past customers.
|
||||||
|
return $all_count - $past_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Customer'] = array('name');
|
||||||
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: move_in
|
||||||
|
* - Sets up the move-in page for the given customer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function move_in($id = null) {
|
||||||
|
$customer = array();
|
||||||
|
$unit = array();
|
||||||
|
|
||||||
|
if (isset($id)) {
|
||||||
|
$this->Customer->recursive = -1;
|
||||||
|
$customer = current($this->Customer->read(null, $id));
|
||||||
|
}
|
||||||
|
$this->set(compact('customer', 'unit'));
|
||||||
|
|
||||||
|
$title = 'Customer Move-In';
|
||||||
|
$this->set(compact('title'));
|
||||||
|
$this->render('/leases/move');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: move_out
|
||||||
|
* - prepare to move a customer out of one of their units
|
||||||
|
*/
|
||||||
|
|
||||||
|
function move_out($id) {
|
||||||
|
|
||||||
|
$customer = $this->Customer->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'Lease' =>
|
||||||
|
array('conditions' => array('Lease.moveout_date' => null),
|
||||||
|
// Models
|
||||||
|
'Unit' =>
|
||||||
|
array('order' => array('sort_order'),
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array('Customer.id' => $id),
|
||||||
|
));
|
||||||
|
$this->set('customer', $lease['Customer']);
|
||||||
|
$this->set('unit', array());
|
||||||
|
|
||||||
|
$redirect = array('controller' => 'customers',
|
||||||
|
'action' => 'view',
|
||||||
|
$id);
|
||||||
|
|
||||||
|
$title = $customer['Customer']['name'] . ': Prepare Move-Out';
|
||||||
|
$this->set(compact('title', 'customer', 'redirect'));
|
||||||
|
$this->render('/leases/move');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific customer
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* //$result = $this->Customer->securityDeposits($id); */
|
||||||
|
/* $result = $this->Customer->excessPayments($id); */
|
||||||
|
/* //$result = $this->Customer->unreconciledCharges($id); */
|
||||||
|
/* echo('<HR>'); */
|
||||||
|
/* pr($result); */
|
||||||
|
/* $this->autoRender = false; */
|
||||||
|
/* return; */
|
||||||
|
|
||||||
|
$customer = $this->Customer->details($id);
|
||||||
|
//pr($customer);
|
||||||
|
$outstanding_balance = $customer['stats']['balance'];
|
||||||
|
$outstanding_deposit = $this->Customer->securityDepositBalance($id);
|
||||||
|
|
||||||
|
// Figure out if this customer has any non-closed leases
|
||||||
|
$show_moveout = false;
|
||||||
|
$show_payment = false;
|
||||||
|
foreach ($customer['Lease'] AS $lease) {
|
||||||
|
if (!isset($lease['close_date']))
|
||||||
|
$show_payment = true;
|
||||||
|
if (!isset($lease['moveout_date']))
|
||||||
|
$show_moveout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up dynamic menu items
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Edit',
|
||||||
|
'url' => array('action' => 'edit',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Move-In',
|
||||||
|
'url' => array('action' => 'move_in',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
/* if ($show_moveout) { */
|
||||||
|
/* $this->sidemenu_links[] = */
|
||||||
|
/* array('name' => 'Move-Out', */
|
||||||
|
/* 'url' => array('action' => 'move_out', */
|
||||||
|
/* $id)); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
if ($show_payment) {
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Payment',
|
||||||
|
'url' => array('action' => 'receipt',
|
||||||
|
$id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = 'Customer: ' . $customer['Customer']['name'];
|
||||||
|
$this->set(compact('customer', 'title',
|
||||||
|
'outstanding_balance',
|
||||||
|
'outstanding_deposit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* 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['Customer']['id']))
|
||||||
|
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||||
|
else
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have at least one contact
|
||||||
|
if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) {
|
||||||
|
$this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true);
|
||||||
|
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure there is a primary contact
|
||||||
|
if (!isset($this->data['Customer']['primary_contact_entry'])) {
|
||||||
|
$this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true);
|
||||||
|
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through each customer and strip the bogus ID if new
|
||||||
|
foreach ($this->data['Contact'] AS &$contact) {
|
||||||
|
if (isset($contact['source']) && $contact['source'] === 'new')
|
||||||
|
unset($contact['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the customer and all associated data
|
||||||
|
if (!$this->Customer->saveCustomer($this->data['Customer']['id'],
|
||||||
|
$this->data,
|
||||||
|
$this->data['Customer']['primary_contact_entry'])) {
|
||||||
|
$this->Session->setFlash("CUSTOMER SAVE FAILED", true);
|
||||||
|
pr("CUSTOMER SAVE FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
|
// If existing customer, then view it. Otherwise, since
|
||||||
|
// this is a new customer, go to the move in screen.
|
||||||
|
if ($this->data['Customer']['id'])
|
||||||
|
$this->redirect(array('action'=>'view', $this->Customer->id));
|
||||||
|
else
|
||||||
|
$this->redirect(array('action'=>'move_in', $this->Customer->id));
|
||||||
|
|
||||||
|
// For debugging, only if the redirects above have been
|
||||||
|
// commented out, otherwise this section isn't reached.
|
||||||
|
$this->render('/empty');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($id) {
|
||||||
|
$this->data = $this->Customer->details($id);
|
||||||
|
$title = 'Customer: ' . $this->data['Customer']['name'] . " : Edit";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$title = "Enter New Customer";
|
||||||
|
$this->data = array('Contact' => array(), 'PrimaryContact' => null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact_types = array_flip($this->Customer->ContactsCustomer->getEnumValues('type'));
|
||||||
|
unset($contact_types[0]);
|
||||||
|
$contact_types = array_combine($contact_types, $contact_types);
|
||||||
|
$this->set(compact('contact_types'));
|
||||||
|
|
||||||
|
$contacts = $this->Customer->Contact->contactList();
|
||||||
|
$this->set(compact('contacts'));
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
//pr($this->data);
|
||||||
|
$this->set(compact('title'));
|
||||||
|
$this->render('edit');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: add
|
||||||
|
* - Add a new customer
|
||||||
|
*/
|
||||||
|
|
||||||
|
function add() {
|
||||||
|
$this->edit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: receipt
|
||||||
|
* - Sets up the receipt entry page for the given customer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function receipt($id = null) {
|
||||||
|
if (isset($id)) {
|
||||||
|
$this->Customer->recursive = -1;
|
||||||
|
$customer = $this->Customer->read(null, $id);
|
||||||
|
$customer = $customer['Customer'];
|
||||||
|
$unreconciled = $this->Customer->unreconciledCharges($id);
|
||||||
|
//pr($unreconciled);
|
||||||
|
$charges = $unreconciled['entries'];
|
||||||
|
$stats = $unreconciled['summary']['Charge'];
|
||||||
|
// Kludge until we update receipt to have the unpaid
|
||||||
|
// charges grid generated from a dynamic query instead
|
||||||
|
// of simply pre-providing the list of charge IDs
|
||||||
|
foreach ($charges AS &$charge)
|
||||||
|
$charge['id'] = $charge['StatementEntry']['id'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$customer = null;
|
||||||
|
$charges = array();
|
||||||
|
$stats = array('balance' => 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$TT = new TenderType();
|
||||||
|
$payment_types = $TT->paymentTypes();
|
||||||
|
$default_type = $TT->defaultPaymentType();
|
||||||
|
$this->set(compact('payment_types', 'default_type'));
|
||||||
|
|
||||||
|
$title = ($customer['name'] . ': Payment Entry');
|
||||||
|
$this->set(compact('customer', 'charges', 'stats', 'title'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: refund
|
||||||
|
* - Refunds customer charges
|
||||||
|
*/
|
||||||
|
|
||||||
|
function refund() {
|
||||||
|
$entries = $this->Customer->StatementEntry->find
|
||||||
|
('all', array
|
||||||
|
('contain' => false,
|
||||||
|
'conditions' => array('StatementEntry.id' =>
|
||||||
|
//array(199,200,201)
|
||||||
|
61
|
||||||
|
),
|
||||||
|
));
|
||||||
|
pr(compact('entries'));
|
||||||
|
|
||||||
|
$this->Customer->StatementEntry->reverse($entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: unreconciled
|
||||||
|
* - returns the list of unreconciled entries
|
||||||
|
*/
|
||||||
|
|
||||||
|
function unreconciled($id) {
|
||||||
|
|
||||||
|
//$this->layout = 'ajax';
|
||||||
|
$this->layout = null;
|
||||||
|
$this->autoLayout = false;
|
||||||
|
$this->autoRender = false;
|
||||||
|
//Configure::write('debug', '0');
|
||||||
|
//header("Content-type: text/xml;charset=utf-8");
|
||||||
|
|
||||||
|
App::import('Helper', 'Xml');
|
||||||
|
$xml = new XmlHelper();
|
||||||
|
|
||||||
|
// Find the unreconciled entries, then manipulate the structure
|
||||||
|
// slightly to accomodate the format necessary for XML Helper.
|
||||||
|
$unreconciled = $this->Customer->unreconciledCharges($id);
|
||||||
|
$unreconciled = array('entries' =>
|
||||||
|
array_intersect_key($unreconciled['debit'],
|
||||||
|
array('entry'=>1, 'balance'=>1)));
|
||||||
|
|
||||||
|
// XML Helper will dump an empty tag if the array is empty
|
||||||
|
if (!count($unreconciled['entries']['entry']))
|
||||||
|
unset($unreconciled['entries']['entry']);
|
||||||
|
|
||||||
|
//pr($unreconciled);
|
||||||
|
//$reconciled = $cust->reconcileNewStatementEntry($cust_id, 'credit', $amount);
|
||||||
|
|
||||||
|
$opts = array();
|
||||||
|
//$opts['format'] = 'tags';
|
||||||
|
echo $xml->header();
|
||||||
|
echo $xml->serialize($unreconciled, $opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class DoubleEntriesController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Entry and related fields
|
||||||
|
$entry = $this->DoubleEntry->find
|
||||||
|
('first',
|
||||||
|
array('contain' => array('DebitEntry', 'CreditEntry'),
|
||||||
|
'conditions' => array('DoubleEntry.id' => $id),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}";
|
||||||
|
$this->set(compact('entry', 'title'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,563 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class LeasesController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Leases', 'header' => true),
|
||||||
|
array('name' => 'Active', 'url' => array('controller' => 'leases', 'action' => 'active')),
|
||||||
|
array('name' => 'Closed', 'url' => array('controller' => 'leases', 'action' => 'closed')),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'leases', 'action' => 'all')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: index / active / closed / all
|
||||||
|
* - Generate a listing of leases
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->all(); }
|
||||||
|
function active() { $this->gridView('Active Leases'); }
|
||||||
|
function closed() { $this->gridView('Closed Leases'); }
|
||||||
|
function all() { $this->gridView('All Leases', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: gridData
|
||||||
|
* - With the application controller handling the gridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function gridDataSetup(&$params) {
|
||||||
|
parent::gridDataSetup($params);
|
||||||
|
if (!isset($params['action']))
|
||||||
|
$params['action'] = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataCountTables(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('link' => array('Unit' => array('fields' => array('id', 'name')),
|
||||||
|
'Customer' => array('fields' => array('id', 'name'))));
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataTables(&$params, &$model) {
|
||||||
|
$link = $this->gridDataCountTables($params, $model);
|
||||||
|
$link['link']['StatementEntry'] = array('fields' => array());
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataFields(&$params, &$model) {
|
||||||
|
$fields = parent::gridDataFields($params, $model);
|
||||||
|
return array_merge($fields,
|
||||||
|
$this->Lease->StatementEntry->chargePaymentFields(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::gridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if ($params['action'] === 'active') {
|
||||||
|
$conditions[] = 'Lease.close_date IS NULL';
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'closed') {
|
||||||
|
$conditions[] = 'Lease.close_date IS NOT NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($customer_id))
|
||||||
|
$conditions[] = array('Lease.customer_id' => $customer_id);
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
// Do not sort by number, which is type varchar and
|
||||||
|
// sorts on an ascii basis. Sort by ID instead.
|
||||||
|
if ($index === 'Lease.number')
|
||||||
|
$index = 'Lease.id';
|
||||||
|
|
||||||
|
// Instead of sorting by name, sort by defined order
|
||||||
|
if ($index === 'Unit.name')
|
||||||
|
$index = 'Unit.sort_order';
|
||||||
|
|
||||||
|
$order = array();
|
||||||
|
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
|
||||||
|
|
||||||
|
// If sorting by anything other than id/number
|
||||||
|
// add sorting by id as a secondary condition.
|
||||||
|
if ($index !== 'Lease.id' && $index !== 'Lease.number')
|
||||||
|
$order[] = parent::gridDataOrder($params, $model,
|
||||||
|
'Lease.id', $direction);
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* function gridDataPostProcess(&$params, &$model, &$records) { */
|
||||||
|
/* foreach ($records AS &$record) { */
|
||||||
|
/* $record['Lease']['through_date'] */
|
||||||
|
/* = $this->Lease->rentChargeThrough($record['Lease']['id']); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* parent::gridDataPostProcess($params, $model, $records); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Lease'] = array('number');
|
||||||
|
$links['Unit'] = array('name');
|
||||||
|
$links['Customer'] = array('name');
|
||||||
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: move_in
|
||||||
|
* - execute a move in on a new lease
|
||||||
|
*/
|
||||||
|
|
||||||
|
function move_in() {
|
||||||
|
if (!$this->data)
|
||||||
|
die("Should have some data");
|
||||||
|
|
||||||
|
// Handle the move in based on the data given
|
||||||
|
//pr(array('Move-in data', $this->data));
|
||||||
|
|
||||||
|
$lid = $this->Lease->moveIn($this->data['Lease']['customer_id'],
|
||||||
|
$this->data['Lease']['unit_id'],
|
||||||
|
null, null,
|
||||||
|
$this->data['Lease']['movein_date'],
|
||||||
|
$this->data['Lease']['comment']
|
||||||
|
);
|
||||||
|
|
||||||
|
// Since this is a new lease, go to the invoice
|
||||||
|
// screen so we can start assessing charges.
|
||||||
|
$this->redirect(array('action'=>'invoice', $lid));
|
||||||
|
|
||||||
|
// For debugging, only if the redirect above have been
|
||||||
|
// commented out, otherwise this section isn't reached.
|
||||||
|
$this->render('/empty');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: move_out
|
||||||
|
* - prepare or execute a move out on a specific lease
|
||||||
|
*/
|
||||||
|
|
||||||
|
function move_out($id = null) {
|
||||||
|
if ($this->data) {
|
||||||
|
// Handle the move out based on the data given
|
||||||
|
//pr($this->data);
|
||||||
|
|
||||||
|
$this->Lease->moveOut($this->data['Lease']['id'],
|
||||||
|
'VACANT',
|
||||||
|
$this->data['Lease']['moveout_date'],
|
||||||
|
//true // Close this lease, if able
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->redirect($this->data['redirect']);
|
||||||
|
$this->autoRender = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($id))
|
||||||
|
die("Oh Nooooo!!");
|
||||||
|
|
||||||
|
$lease = $this->Lease->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'Unit' =>
|
||||||
|
array('order' => array('sort_order'),
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Customer' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array(array('Lease.id' => $id),
|
||||||
|
array('Lease.close_date' => null),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
$this->set('customer', $lease['Customer']);
|
||||||
|
$this->set('unit', $lease['Unit']);
|
||||||
|
$this->set('lease', $lease['Lease']);
|
||||||
|
|
||||||
|
$redirect = array('controller' => 'leases',
|
||||||
|
'action' => 'view',
|
||||||
|
$id);
|
||||||
|
|
||||||
|
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||||
|
$lease['Unit']['name'] . ': ' .
|
||||||
|
$lease['Customer']['name'] . ': Prepare Move-Out');
|
||||||
|
$this->set(compact('title', 'redirect'));
|
||||||
|
$this->render('/leases/move');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: apply_deposit
|
||||||
|
* - Applies the security deposit to charges. This is much
|
||||||
|
* like a receipt, but it's separated to keep it simple and
|
||||||
|
* to prevent feature overload on the receipt page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function apply_deposit($id = null) {
|
||||||
|
// Create some models for convenience
|
||||||
|
$A = new Account();
|
||||||
|
|
||||||
|
if ($this->data) {
|
||||||
|
// Handle the move out based on the data given
|
||||||
|
pr($this->data);
|
||||||
|
$this->Lease->releaseSecurityDeposits($this->data['Lease']['id']);
|
||||||
|
die();
|
||||||
|
|
||||||
|
// Assume this will succeed
|
||||||
|
$ret = true;
|
||||||
|
|
||||||
|
// Go through the entered payments
|
||||||
|
$receipt_transaction = array_intersect_key($this->data,
|
||||||
|
array('Transaction'=>1,
|
||||||
|
'transaction_id'=>1));
|
||||||
|
foreach ($data['StatementEntry'] AS $entry) {
|
||||||
|
// Create the receipt entry, and reconcile the credit side
|
||||||
|
// of the double-entry (which should be A/R) as a payment.
|
||||||
|
$ids = $this->StatementEntry->Ledger->Account->postLedgerEntry
|
||||||
|
($receipt_transaction,
|
||||||
|
array_intersect_key($entry, array('MonetarySource'=>1))
|
||||||
|
+ array_intersect_key($entry, array('account_id'=>1)),
|
||||||
|
array('debit_ledger_id' => $A->currentLedgerID($entry['account_id']),
|
||||||
|
'credit_ledger_id' => $A->currentLedgerID($A->receiptAccountID()),
|
||||||
|
'customer_id' => $customer_id,
|
||||||
|
'lease_id' => $lease_id)
|
||||||
|
+ $entry,
|
||||||
|
'receipt');
|
||||||
|
|
||||||
|
if ($ids['error'])
|
||||||
|
$ret = false;
|
||||||
|
|
||||||
|
$db = &$model->getDataSource();
|
||||||
|
$fields = $db->fields($model, $model->alias);
|
||||||
|
$fields[] = ("SUM(IF(Account.id IS NULL, 0," .
|
||||||
|
" IF(LedgerEntry.debit_ledger_id = Account.id," .
|
||||||
|
" 1, -1))" .
|
||||||
|
" * IF(LedgerEntry.amount IS NULL, 0, LedgerEntry.amount))" .
|
||||||
|
" AS 'balance'");
|
||||||
|
return $fields;
|
||||||
|
$receipt_transaction = array_intersect_key($ids,
|
||||||
|
array('transaction_id'=>1,
|
||||||
|
'split_transaction_id'=>1));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->Lease->moveOut($this->data['Lease']['id'],
|
||||||
|
'VACANT',
|
||||||
|
$this->data['Lease']['moveout_date'],
|
||||||
|
//true // Close this lease, if able
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->redirect(array('controller' => 'leases',
|
||||||
|
'action' => 'view',
|
||||||
|
$this->data['Lease']['id']));
|
||||||
|
$this->autoRender = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$A = new Account();
|
||||||
|
|
||||||
|
$lease = $this->Lease->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'Unit' =>
|
||||||
|
array('order' => array('sort_order'),
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Customer' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array(array('Lease.id' => $id),
|
||||||
|
array('Lease.close_date' => null),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
// Get the lease balance, part of lease stats
|
||||||
|
$this->Lease->statsMerge($lease['Lease'],
|
||||||
|
array('stats' => $this->Lease->stats($id)));
|
||||||
|
|
||||||
|
// Determine the lease security deposit
|
||||||
|
$deposit_balance = $this->Lease->securityDeposits($lease['Lease']['id']);
|
||||||
|
$this->set(compact('deposit_balance'));
|
||||||
|
$this->set('customer', $lease['Customer']);
|
||||||
|
$this->set('unit', $lease['Unit']);
|
||||||
|
$this->set('lease', $lease['Lease']);
|
||||||
|
$this->set('account', array('id' => $A->securityDepositAccountID()));
|
||||||
|
|
||||||
|
/* $redirect = array('controller' => 'leases', */
|
||||||
|
/* 'action' => 'view', */
|
||||||
|
/* $id); */
|
||||||
|
|
||||||
|
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||||
|
$lease['Unit']['name'] . ': ' .
|
||||||
|
$lease['Customer']['name'] . ': Utilize Security Deposit');
|
||||||
|
$this->set(compact('title', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: bad_debt
|
||||||
|
* - Writes off remaining charges on a lease.
|
||||||
|
* REVISIT <AP>: 20090710
|
||||||
|
* Should this be a customer function? What customer
|
||||||
|
* would have only one lease that results in bad debt.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function bad_debt($id) {
|
||||||
|
$A = new Account();
|
||||||
|
|
||||||
|
$lease = $this->Lease->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'Unit' =>
|
||||||
|
array('order' => array('sort_order'),
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Customer' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array(array('Lease.id' => $id),
|
||||||
|
array('Lease.close_date' => null),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
// Get the lease balance, part of lease stats
|
||||||
|
$this->Lease->statsMerge($lease['Lease'],
|
||||||
|
array('stats' => $this->Lease->stats($id)));
|
||||||
|
|
||||||
|
// Determine the lease security deposit
|
||||||
|
$deposit_balance = $this->Lease->securityDepositBalance($lease['Lease']['id']);
|
||||||
|
if ($deposit_balance > 0)
|
||||||
|
die("Still have un-utilized security deposit");
|
||||||
|
|
||||||
|
$this->set('customer', $lease['Customer']);
|
||||||
|
$this->set('unit', $lease['Unit']);
|
||||||
|
$this->set('lease', $lease['Lease']);
|
||||||
|
$this->set('account', array('id' => $A->badDebtAccountID()));
|
||||||
|
|
||||||
|
/* $redirect = array('controller' => 'leases', */
|
||||||
|
/* 'action' => 'view', */
|
||||||
|
/* $id); */
|
||||||
|
|
||||||
|
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||||
|
$lease['Unit']['name'] . ': ' .
|
||||||
|
$lease['Customer']['name'] . ': Write Off Bad Debt');
|
||||||
|
$this->set(compact('title', 'redirect'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: refund
|
||||||
|
* - Provides user with a refund
|
||||||
|
* REVISIT <AP>: 20090710
|
||||||
|
* Should this be a customer function?
|
||||||
|
*/
|
||||||
|
|
||||||
|
function refund($id) {
|
||||||
|
/* // Obtain the overall lease balance */
|
||||||
|
/* $stats = $this->Lease->stats($id); */
|
||||||
|
/* $outstanding_balance = $stats['balance']; */
|
||||||
|
|
||||||
|
/* // Determine the lease security deposit */
|
||||||
|
/* $deposits = $this->Lease->securityDeposits($id); */
|
||||||
|
/* $outstanding_deposit = $deposits['summary']['balance']; */
|
||||||
|
|
||||||
|
|
||||||
|
/* $this->set(compact('lease', 'title', */
|
||||||
|
/* 'outstanding_deposit', */
|
||||||
|
/* 'outstanding_balance')); */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: close
|
||||||
|
* - Closes a lease to any further action
|
||||||
|
*/
|
||||||
|
|
||||||
|
function close($id) {
|
||||||
|
// REVISIT <AP>: 20090708
|
||||||
|
// We should probably seek confirmation first...
|
||||||
|
$this->Lease->close($id);
|
||||||
|
$this->redirect(array('action'=>'view', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: invoice
|
||||||
|
* - Sets up the invoice entry page for the given customer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function invoice($id = null, $type = null) {
|
||||||
|
|
||||||
|
$lease = $this->Lease->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'Unit' =>
|
||||||
|
array('order' => array('sort_order'),
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Customer' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array(array('Lease.id' => $id),
|
||||||
|
array('Lease.close_date' => null),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
$A = new Account();
|
||||||
|
$charge_accounts = $A->chargeAccounts();
|
||||||
|
$default_account = $A->rentAccountID();
|
||||||
|
$this->set(compact('charge_accounts', 'default_account'));
|
||||||
|
|
||||||
|
// REVISIT <AP> 20090705:
|
||||||
|
// Of course, the late charge should come from the late_schedule
|
||||||
|
$default_rent = $lease['Lease']['rent'];
|
||||||
|
$default_late = 10;
|
||||||
|
$this->set(compact('default_rent', 'default_late'));
|
||||||
|
|
||||||
|
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||||
|
$lease['Unit']['name'] . ': ' .
|
||||||
|
$lease['Customer']['name'] . ': Charge Entry');
|
||||||
|
$this->set(compact('title', 'lease', 'charge'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific lease
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get details about the lease and its ledgers (no ledger entries yet)
|
||||||
|
$lease = $this->Lease->find
|
||||||
|
('first',
|
||||||
|
array('contain' =>
|
||||||
|
array(// Models
|
||||||
|
'LeaseType',
|
||||||
|
'Unit',
|
||||||
|
'Customer',
|
||||||
|
),
|
||||||
|
'conditions' => array(array('Lease.id' => $id)),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$lease['Lease']['paid_through'] = $this->Lease->rentPaidThrough($id);
|
||||||
|
|
||||||
|
|
||||||
|
$this->set('charge_gaps', $this->Lease->rentChargeGaps($id));
|
||||||
|
$this->set('charge_through', $this->Lease->rentChargeThrough($id));
|
||||||
|
|
||||||
|
// Obtain the overall lease balance
|
||||||
|
$this->Lease->statsMerge($lease['Lease'],
|
||||||
|
array('stats' => $this->Lease->stats($id)));
|
||||||
|
$outstanding_balance = $lease['Lease']['stats']['balance'];
|
||||||
|
|
||||||
|
// Determine the lease security deposit
|
||||||
|
$outstanding_deposit = $this->Lease->securityDepositBalance($lease['Lease']['id']);
|
||||||
|
|
||||||
|
// Set up dynamic menu items
|
||||||
|
if (!isset($lease['Lease']['close_date'])) {
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
|
||||||
|
if (!isset($lease['Lease']['moveout_date']))
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Charges', 'url' => array('action' => 'invoice',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Payments', 'url' => array('controller' => 'customers',
|
||||||
|
'action' => 'receipt',
|
||||||
|
$lease['Customer']['id']));
|
||||||
|
|
||||||
|
if (isset($lease['Lease']['moveout_date']) && $outstanding_deposit > 0 && $outstanding_balance > 0)
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Apply Deposit', 'url' => array('action' => 'apply_deposit',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
if (isset($lease['Lease']['moveout_date']) &&
|
||||||
|
$outstanding_balance <= 0 &&
|
||||||
|
($outstanding_deposit - $outstanding_balance) > 0)
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Issue Refund', 'url' => array('action' => 'refund',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
if (isset($lease['Lease']['moveout_date']) && $outstanding_deposit == 0 && $outstanding_balance > 0)
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Write-Off', 'url' => array('action' => 'bad_debt',
|
||||||
|
$id));
|
||||||
|
|
||||||
|
if ($this->Lease->closeable($id))
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Close', 'url' => array('action' => 'close',
|
||||||
|
$id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare to render
|
||||||
|
$title = 'Lease: #' . $lease['Lease']['id'];
|
||||||
|
$this->set(compact('lease', 'title',
|
||||||
|
'outstanding_deposit',
|
||||||
|
'outstanding_balance'));
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-34
@@ -2,17 +2,20 @@
|
|||||||
|
|
||||||
class LedgerEntriesController extends AppController {
|
class LedgerEntriesController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links = array();
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
* action: index / current / past / all
|
* override: sideMenuLinks
|
||||||
* - Creates a list of ledger entries
|
* - Generates controller specific links for the side menu
|
||||||
*/
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
function index() { $this->gridView('All Ledger Entries'); }
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -117,12 +120,8 @@ class LedgerEntriesController extends AppController {
|
|||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
$links['LedgerEntry'] = array('id');
|
$links['LedgerEntry'] = array('id');
|
||||||
$links['Transaction'] = array('id');
|
$links['Transaction'] = array('id');
|
||||||
// REVISIT <AP>: 20090827
|
$links['Ledger'] = array('id');
|
||||||
// Need to take 'level' into account
|
$links['Account'] = array('controller' => 'accounts', 'name');
|
||||||
if ($this->Permission->allow('controller.accounts')) {
|
|
||||||
$links['Ledger'] = array('id');
|
|
||||||
$links['Account'] = array('name');
|
|
||||||
}
|
|
||||||
$links['Tender'] = array('name');
|
$links['Tender'] = array('name');
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
}
|
}
|
||||||
@@ -136,6 +135,12 @@ class LedgerEntriesController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function view($id = null) {
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Entry and related fields
|
||||||
$entry = $this->LedgerEntry->find
|
$entry = $this->LedgerEntry->find
|
||||||
('first',
|
('first',
|
||||||
array('contain' => array
|
array('contain' => array
|
||||||
@@ -148,16 +153,13 @@ class LedgerEntriesController extends AppController {
|
|||||||
array('fields' => array('id', 'sequence', 'name'),
|
array('fields' => array('id', 'sequence', 'name'),
|
||||||
'Account' =>
|
'Account' =>
|
||||||
array('fields' => array('id', 'name', 'type'),
|
array('fields' => array('id', 'name', 'type'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
'Tender' =>
|
'Tender' =>
|
||||||
array('fields' => array('id', 'name'),
|
array('fields' => array('id', 'name'),
|
||||||
),
|
),
|
||||||
|
|
||||||
'DebitDoubleEntry' => array('id'),
|
|
||||||
'CreditDoubleEntry' => array('id'),
|
|
||||||
|
|
||||||
'DebitEntry' => array('fields' => array('id', 'crdr')),
|
'DebitEntry' => array('fields' => array('id', 'crdr')),
|
||||||
'CreditEntry' => array('fields' => array('id', 'crdr')),
|
'CreditEntry' => array('fields' => array('id', 'crdr')),
|
||||||
),
|
),
|
||||||
@@ -165,11 +167,6 @@ class LedgerEntriesController extends AppController {
|
|||||||
'conditions' => array('LedgerEntry.id' => $id),
|
'conditions' => array('LedgerEntry.id' => $id),
|
||||||
));
|
));
|
||||||
|
|
||||||
if (empty($entry) || empty($entry['Ledger']['Account'])) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($entry['DebitEntry']) && !empty($entry['CreditEntry']))
|
if (!empty($entry['DebitEntry']) && !empty($entry['CreditEntry']))
|
||||||
die("LedgerEntry has both a matching DebitEntry and CreditEntry");
|
die("LedgerEntry has both a matching DebitEntry and CreditEntry");
|
||||||
if (empty($entry['DebitEntry']) && empty($entry['CreditEntry']))
|
if (empty($entry['DebitEntry']) && empty($entry['CreditEntry']))
|
||||||
@@ -184,18 +181,6 @@ class LedgerEntriesController extends AppController {
|
|||||||
else
|
else
|
||||||
$entry['MatchingEntry'] = $entry['DebitEntry'][0];
|
$entry['MatchingEntry'] = $entry['DebitEntry'][0];
|
||||||
|
|
||||||
if (empty($entry['DebitDoubleEntry']['id']))
|
|
||||||
$entry['DoubleEntry'] = $entry['CreditDoubleEntry'];
|
|
||||||
else
|
|
||||||
$entry['DoubleEntry'] = $entry['DebitDoubleEntry'];
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090816
|
|
||||||
// This page doesn't seem very useful, let's just keep it
|
|
||||||
// all to the double entry view.
|
|
||||||
$this->redirect(array('controller' => 'double_entries',
|
|
||||||
'action' => 'view',
|
|
||||||
$entry['DoubleEntry']['id']));
|
|
||||||
|
|
||||||
// Prepare to render.
|
// Prepare to render.
|
||||||
$title = "Ledger Entry #{$entry['LedgerEntry']['id']}";
|
$title = "Ledger Entry #{$entry['LedgerEntry']['id']}";
|
||||||
$this->set(compact('entry', 'title'));
|
$this->set(compact('entry', 'title'));
|
||||||
@@ -2,29 +2,25 @@
|
|||||||
|
|
||||||
class LedgersController extends AppController {
|
class LedgersController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Ledgers', 'header' => true),
|
||||||
|
array('name' => 'Current', 'url' => array('controller' => 'ledgers', 'action' => 'current')),
|
||||||
|
array('name' => 'Closed', 'url' => array('controller' => 'ledgers', 'action' => 'closed')),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'ledgers', 'action' => 'all')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
* override: addGridViewSideMenuLinks
|
* override: sideMenuLinks
|
||||||
* - Adds grid view navigation side menu links
|
* - Generates controller specific links for the side menu
|
||||||
*/
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
function addGridViewSideMenuLinks() {
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
parent::addGridViewSideMenuLinks();
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Current',
|
|
||||||
array('controller' => 'ledgers', 'action' => 'current'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Closed',
|
|
||||||
array('controller' => 'ledgers', 'action' => 'closed'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('All',
|
|
||||||
array('controller' => 'ledgers', 'action' => 'all'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -54,21 +50,24 @@ class LedgersController extends AppController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gridDataCountTables(&$params, &$model) {
|
function gridDataCountTables(&$params, &$model) {
|
||||||
|
// Our count should NOT include anything extra,
|
||||||
|
// so we need the virtual function to prevent
|
||||||
|
// the base class from just calling our
|
||||||
|
// gridDataTables function.
|
||||||
|
return parent::gridDataTables($params, $model);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataTables(&$params, &$model) {
|
||||||
return array
|
return array
|
||||||
('link' =>
|
('link' =>
|
||||||
array(// Models
|
array(// Models
|
||||||
'Account',
|
'Account',
|
||||||
|
'LedgerEntry',
|
||||||
|
'CloseTransaction',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
|
||||||
$tables = $this->gridDataCountTables($params, $model);
|
|
||||||
$tables['link'][] = 'LedgerEntry';
|
|
||||||
$tables['link'][] = 'CloseTransaction';
|
|
||||||
return $tables;
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridDataFields(&$params, &$model) {
|
function gridDataFields(&$params, &$model) {
|
||||||
$fields = parent::gridDataFields($params, $model);
|
$fields = parent::gridDataFields($params, $model);
|
||||||
$fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence';
|
$fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence';
|
||||||
@@ -86,32 +85,28 @@ class LedgersController extends AppController {
|
|||||||
$conditions[] = array('Ledger.close_transaction_id !=' => null);
|
$conditions[] = array('Ledger.close_transaction_id !=' => null);
|
||||||
}
|
}
|
||||||
|
|
||||||
$conditions[] = array('Account.level >=' =>
|
|
||||||
$this->Permission->level('controller.accounts'));
|
|
||||||
|
|
||||||
return $conditions;
|
return $conditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
$id_sequence = false;
|
||||||
|
if ($index === 'id_sequence') {
|
||||||
|
$id_sequence = true;
|
||||||
|
$index = 'Ledger.account_id';
|
||||||
|
}
|
||||||
|
|
||||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||||
|
|
||||||
// After sorting by whatever the user wants, add these
|
if ($id_sequence) {
|
||||||
// defaults into the sort mechanism. If we're already
|
$order[] = 'Ledger.sequence ' . $direction;
|
||||||
// sorting by one of them, it will only be redundant,
|
}
|
||||||
// and should cause no harm (possible a longer query?)
|
|
||||||
$order[] = 'Account.name ' . $direction;
|
|
||||||
$order[] = 'Ledger.sequence ' . $direction;
|
|
||||||
|
|
||||||
return $order;
|
return $order;
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
// REVISIT <AP>: 20090827
|
$links['Ledger'] = array('id_sequence');
|
||||||
// Need to take 'level' into account
|
$links['Account'] = array('name');
|
||||||
if ($this->Permission->allow('controller.accounts')) {
|
|
||||||
$links['Ledger'] = array('sequence');
|
|
||||||
$links['Account'] = array('name');
|
|
||||||
}
|
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,24 +119,22 @@ class LedgersController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function view($id = null) {
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get details about the ledger itself (no entries yet)
|
||||||
$ledger = $this->Ledger->find
|
$ledger = $this->Ledger->find
|
||||||
('first',
|
('first',
|
||||||
array('contain' =>
|
array('contain' =>
|
||||||
array(// Models
|
array(// Models
|
||||||
'Account',
|
'Account',
|
||||||
),
|
),
|
||||||
'conditions' => array(array('Ledger.id' => $id),
|
'conditions' => array(array('Ledger.id' => $id)),
|
||||||
array('Account.level >=' =>
|
|
||||||
$this->Permission->level('controller.accounts')),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (empty($ledger)) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get ledger stats for our summary box
|
// Get ledger stats for our summary box
|
||||||
$stats = $this->Ledger->stats($id);
|
$stats = $this->Ledger->stats($id);
|
||||||
|
|
||||||
@@ -52,7 +52,6 @@ class MapsController extends AppController {
|
|||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
$this->redirect(array('action'=>'index'));
|
$this->redirect(array('action'=>'index'));
|
||||||
}
|
}
|
||||||
$this->sideMenuEnable('SITE', $this->op_area);
|
|
||||||
$this->set('info', $this->mapInfo($id, $requested_width));
|
$this->set('info', $this->mapInfo($id, $requested_width));
|
||||||
$this->set('title', "Site Map");
|
$this->set('title', "Site Map");
|
||||||
}
|
}
|
||||||
@@ -86,35 +85,11 @@ class MapsController extends AppController {
|
|||||||
'units' => array());
|
'units' => array());
|
||||||
|
|
||||||
// Find all of the map/unit information from this SiteArea
|
// Find all of the map/unit information from this SiteArea
|
||||||
$map = $this->Map->find('first', array('contain' => false,
|
$this->Map->recursive = 2;
|
||||||
'conditions' => array('id' => $id)));
|
$this->Map->SiteArea->unbindModel(array('hasOne' => array('Map')));
|
||||||
|
$map = $this->Map->read(null, $id);
|
||||||
$units = $this->Map->Unit->find
|
//pr($map);
|
||||||
('all',
|
|
||||||
array('link' =>
|
|
||||||
array('Map' =>
|
|
||||||
array('fields' => array()),
|
|
||||||
|
|
||||||
'CurrentLease' =>
|
|
||||||
array('fields' => array('id', 'paid_through_date',
|
|
||||||
$this->Map->Unit->CurrentLease->
|
|
||||||
delinquentField('CurrentLease')),
|
|
||||||
'Customer'),
|
|
||||||
|
|
||||||
'UnitSize' =>
|
|
||||||
array('fields' => array('id', 'depth', 'width',
|
|
||||||
'MapsUnit.pt_top',
|
|
||||||
'MapsUnit.pt_left',
|
|
||||||
'MapsUnit.transpose')),
|
|
||||||
),
|
|
||||||
'fields' => array('id', 'name', 'status'),
|
|
||||||
'conditions' => array('Map.id' => $id),
|
|
||||||
));
|
|
||||||
|
|
||||||
/* pr(compact('map', 'units')); */
|
|
||||||
/* $this->render('/empty'); */
|
|
||||||
/* return; */
|
|
||||||
|
|
||||||
/*****
|
/*****
|
||||||
* The preference would be to leave all things "screen" related
|
* The preference would be to leave all things "screen" related
|
||||||
* to reside in the view. However, two separate views need this
|
* to reside in the view. However, two separate views need this
|
||||||
@@ -138,7 +113,7 @@ class MapsController extends AppController {
|
|||||||
$info['depth'] = $bottom * $screen_adjustment_factor;
|
$info['depth'] = $bottom * $screen_adjustment_factor;
|
||||||
|
|
||||||
// Go through each unit in the map, calculating the map location
|
// Go through each unit in the map, calculating the map location
|
||||||
foreach ($units AS $unit) {
|
foreach ($map['Unit'] AS $unit) {
|
||||||
$lft = $unit['MapsUnit']['pt_left'] + $boundary_adjustment;
|
$lft = $unit['MapsUnit']['pt_left'] + $boundary_adjustment;
|
||||||
$top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment;
|
$top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment;
|
||||||
|
|
||||||
@@ -157,9 +132,10 @@ class MapsController extends AppController {
|
|||||||
$width *= $screen_adjustment_factor;
|
$width *= $screen_adjustment_factor;
|
||||||
$depth *= $screen_adjustment_factor;
|
$depth *= $screen_adjustment_factor;
|
||||||
|
|
||||||
|
//$info['units'][$unit['id']] =
|
||||||
$info['units'][] =
|
$info['units'][] =
|
||||||
array( 'id' => $unit['Unit']['id'],
|
array( 'id' => $unit['id'],
|
||||||
'name' => $unit['Unit']['name'],
|
'name' => $unit['name'],
|
||||||
'left' => $lft,
|
'left' => $lft,
|
||||||
'right' => $lft + $width,
|
'right' => $lft + $width,
|
||||||
'top' => $top,
|
'top' => $top,
|
||||||
@@ -167,15 +143,11 @@ class MapsController extends AppController {
|
|||||||
'width' => $width,
|
'width' => $width,
|
||||||
'depth' => $depth,
|
'depth' => $depth,
|
||||||
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
|
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
|
||||||
'status' => (($unit['Unit']['status'] === 'OCCUPIED' &&
|
'status' => $unit['status']
|
||||||
!empty($unit[0]['delinquent']))
|
|
||||||
? 'LATE' : $unit['Unit']['status']),
|
|
||||||
'data' => $unit,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pr($info); */
|
//pr($info);
|
||||||
/* $this->render('/empty'); exit(); */
|
|
||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,10 +160,8 @@ class MapsController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function legend($id = null, $requested_width = 400) {
|
function legend($id = null, $requested_width = 400) {
|
||||||
$status = array_keys($this->Map->Unit->activeStatusEnums());
|
$status = $this->Map->Unit->activeStatusEnums();
|
||||||
$occupied_key = array_search('OCCUPIED', $status);
|
//pr($status);
|
||||||
array_splice($status, $occupied_key+1, 0, array('LATE'));
|
|
||||||
|
|
||||||
$rows = 2;
|
$rows = 2;
|
||||||
$cols = (int)((count($status) + $rows - 1) / $rows);
|
$cols = (int)((count($status) + $rows - 1) / $rows);
|
||||||
|
|
||||||
@@ -221,7 +191,7 @@ class MapsController extends AppController {
|
|||||||
$item_width *= $screen_adjustment_factor;
|
$item_width *= $screen_adjustment_factor;
|
||||||
$item_depth *= $screen_adjustment_factor;
|
$item_depth *= $screen_adjustment_factor;
|
||||||
|
|
||||||
foreach ($status AS $code) {
|
foreach ($status AS $code => $value) {
|
||||||
$info['units'][] = array('name' => $code,
|
$info['units'][] = array('name' => $code,
|
||||||
'status' => $code,
|
'status' => $code,
|
||||||
'width' => $item_width,
|
'width' => $item_width,
|
||||||
@@ -271,9 +241,9 @@ class MapsController extends AppController {
|
|||||||
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
|
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
|
||||||
$info['palate']['unit']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
|
$info['palate']['unit']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
|
||||||
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
|
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
|
||||||
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
|
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
|
||||||
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
|
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 128, 'blue' => 128);
|
||||||
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 0, 'blue' => 128);
|
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
|
||||||
|
|
||||||
// Determine text color to go with each background
|
// Determine text color to go with each background
|
||||||
foreach ($info['palate']['unit'] AS &$code) {
|
foreach ($info['palate']['unit'] AS &$code) {
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class StatementEntriesController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: 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) {
|
||||||
|
$link =
|
||||||
|
array(// Models
|
||||||
|
'Transaction' =>
|
||||||
|
array('fields' => array('id', 'stamp'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Customer' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Lease' =>
|
||||||
|
array('fields' => array('id', 'number'),
|
||||||
|
'Unit' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($params['post']['custom']['statement_entry_id'])) {
|
||||||
|
$link['PaymentEntry'] = array();
|
||||||
|
$link['ChargeEntry'] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['post']['custom']['account_id'])) {
|
||||||
|
$link['LedgerEntry'] = array('fields' => array('id'));
|
||||||
|
$link['LedgerEntry']['Account'] = array('fields' => array('id', 'name', 'type'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if (count(array_intersect($params['fields'], array('applied'))) == 1) { */
|
||||||
|
/* $link['PaymentEntry'] = array(); */
|
||||||
|
/* $link['ChargeEntry'] = array(); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
return array('link' => $link);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataTables(&$params, &$model) {
|
||||||
|
$tables = $this->gridDataCountTables($params, $model);
|
||||||
|
$tables['link']['LedgerEntry'] = array('fields' => array('id'));
|
||||||
|
$tables['link']['LedgerEntry']['Account'] = array('fields' => array('id', 'name', 'type'));
|
||||||
|
return $tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataFields(&$params, &$model) {
|
||||||
|
//foreach(
|
||||||
|
$fields = parent::gridDataFields($params, $model);
|
||||||
|
|
||||||
|
$fields[] = "COUNT(LedgerEntry.id) AS ledger_entry_count";
|
||||||
|
|
||||||
|
if (in_array('applied', $params['post']['fields'])) {
|
||||||
|
$fields[] = ("IF(StatementEntry.type = 'CHARGE'," .
|
||||||
|
" SUM(COALESCE(PaymentEntry.amount,0))," .
|
||||||
|
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||||
|
" AS 'applied'");
|
||||||
|
$fields[] = ("StatementEntry.amount - (" .
|
||||||
|
"IF(StatementEntry.type = 'CHARGE'," .
|
||||||
|
" SUM(COALESCE(PaymentEntry.amount,0))," .
|
||||||
|
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||||
|
") AS 'balance'");
|
||||||
|
}
|
||||||
|
|
||||||
|
$fields = array_merge($fields,
|
||||||
|
$this->StatementEntry->chargePaymentFields());
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::gridDataConditions($params, $model);
|
||||||
|
extract($params['post']['custom']);
|
||||||
|
|
||||||
|
if (!empty($from_date))
|
||||||
|
$conditions[]
|
||||||
|
= array('Transaction.stamp >=' =>
|
||||||
|
$this->StatementEntry->Transaction->dateFormatBeforeSave($from_date));
|
||||||
|
|
||||||
|
if (!empty($through_date))
|
||||||
|
$conditions[]
|
||||||
|
= array('Transaction.stamp <=' =>
|
||||||
|
$this->StatementEntry->Transaction->dateFormatBeforeSave($through_date . ' 23:59:59'));
|
||||||
|
|
||||||
|
if (isset($account_id))
|
||||||
|
$conditions[] = array('LedgerEntry.account_id' => $account_id);
|
||||||
|
|
||||||
|
if (isset($statement_entry_id)) {
|
||||||
|
$conditions[] = array('OR' =>
|
||||||
|
array(array('ChargeEntry.id' => $statement_entry_id),
|
||||||
|
array('PaymentEntry.id' => $statement_entry_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataPostProcessCalculatedFields(&$params, &$model, &$records) {
|
||||||
|
parent::gridDataPostProcessCalculatedFields($params, $model, $records);
|
||||||
|
foreach ($records AS &$record) {
|
||||||
|
if ($record['StatementEntry']['ledger_entry_count'] > 1)
|
||||||
|
$record['Account']['name'] = 'Multiple';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['StatementEntry'] = array('id');
|
||||||
|
$links['Transaction'] = array('id');
|
||||||
|
$links['Account'] = array('name');
|
||||||
|
$links['Customer'] = array('name');
|
||||||
|
$links['Lease'] = array('number');
|
||||||
|
$links['Unit'] = array('name');
|
||||||
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||||
|
|
||||||
|
// After sorting by whatever the user wants, add these
|
||||||
|
// defaults into the sort mechanism. If we're already
|
||||||
|
// sorting by one of them, it will only be redundant,
|
||||||
|
// and should cause no harm (possible a longer query?)
|
||||||
|
$order[] = 'Transaction.stamp ' . $direction;
|
||||||
|
$order[] = 'StatementEntry.effective_date ' . $direction;
|
||||||
|
$order[] = 'StatementEntry.id ' . $direction;
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataRecordsExecute(&$params, &$model, $query) {
|
||||||
|
if (in_array('applied', $params['post']['fields'])) {
|
||||||
|
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
|
||||||
|
$tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," .
|
||||||
|
" SUM(COALESCE(StatementFraction.amount,0))," .
|
||||||
|
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||||
|
" AS 'applied'",
|
||||||
|
|
||||||
|
"StatementEntry.amount - (" .
|
||||||
|
"IF(StatementEntry.type = 'CHARGE'," .
|
||||||
|
" SUM(COALESCE(PaymentEntry.amount,0))," .
|
||||||
|
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||||
|
") AS 'balance'",
|
||||||
|
);
|
||||||
|
|
||||||
|
//pr(compact('tquery'));
|
||||||
|
$total = $model->find('first', $tquery);
|
||||||
|
$params['userdata']['total'] = $total[0]['applied'];
|
||||||
|
$params['userdata']['balance'] = $total[0]['balance'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
|
||||||
|
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
|
||||||
|
$total = $model->find('first', $tquery);
|
||||||
|
$params['userdata']['total'] = $total[0]['total'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::gridDataRecordsExecute($params, $model, $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: reverse the ledger entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
function reverse($id) {
|
||||||
|
$this->StatementEntry->reverse($id);
|
||||||
|
$this->redirect(array('action'=>'view', $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the StatementEntry and related fields
|
||||||
|
$this->StatementEntry->prClassLevel(30, 'Model');
|
||||||
|
$entry = $this->StatementEntry->find
|
||||||
|
('first',
|
||||||
|
array('contain' => array
|
||||||
|
('Transaction' => array('fields' => array('id', 'stamp')),
|
||||||
|
'Customer' => array('fields' => array('id', 'name')),
|
||||||
|
'Lease' => array('fields' => array('id')),
|
||||||
|
'LedgerEntry' => array('fields' => array('id'),
|
||||||
|
'Account' => array('id', 'name', 'type')),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array('StatementEntry.id' => $id),
|
||||||
|
));
|
||||||
|
pr($entry);
|
||||||
|
//die();
|
||||||
|
|
||||||
|
$reconciled = $this->StatementEntry->reconciledEntries($id);
|
||||||
|
|
||||||
|
|
||||||
|
/* // REVISIT <AP>: 20090711 */
|
||||||
|
/* // It's not clear whether we should be able to reverse charges that have */
|
||||||
|
/* // already been paid/cleared/reconciled. Certainly, that will be the */
|
||||||
|
/* // case when someone has pre-paid and then moves out early. However, this */
|
||||||
|
/* // will work well for items accidentally charged but not yet paid for. */
|
||||||
|
/* if ((!$entry['DebitLedger']['Account']['trackable'] || */
|
||||||
|
/* $stats['debit']['amount_reconciled'] == 0) && */
|
||||||
|
/* (!$entry['CreditLedger']['Account']['trackable'] || */
|
||||||
|
/* $stats['credit']['amount_reconciled'] == 0) */
|
||||||
|
|
||||||
|
/* && 0 */
|
||||||
|
|
||||||
|
/* ) */
|
||||||
|
/* { */
|
||||||
|
/* // Set up dynamic menu items */
|
||||||
|
/* $this->sidemenu_links[] = */
|
||||||
|
/* array('name' => 'Operations', 'header' => true); */
|
||||||
|
|
||||||
|
/* $this->sidemenu_links[] = */
|
||||||
|
/* array('name' => 'Undo', */
|
||||||
|
/* 'url' => array('action' => 'reverse', */
|
||||||
|
/* $id)); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if ($this->StatementEntry->Ledger->Account->type */
|
||||||
|
/* ($entry['CreditLedger']['Account']['id']) == 'INCOME') */
|
||||||
|
/* { */
|
||||||
|
/* // Set up dynamic menu items */
|
||||||
|
/* $this->sidemenu_links[] = */
|
||||||
|
/* array('name' => 'Operations', 'header' => true); */
|
||||||
|
|
||||||
|
/* $this->sidemenu_links[] = */
|
||||||
|
/* array('name' => 'Reverse', */
|
||||||
|
/* 'url' => array('action' => 'reverse', */
|
||||||
|
/* $id)); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
$stats = $this->StatementEntry->stats($id);
|
||||||
|
|
||||||
|
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE')
|
||||||
|
$stats = $stats['Charge'];
|
||||||
|
else
|
||||||
|
$stats = $stats['Payment'];
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = "Statement Entry #{$entry['StatementEntry']['id']}";
|
||||||
|
$this->set(compact('entry', 'title', 'reconciled', 'stats'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,7 +2,20 @@
|
|||||||
|
|
||||||
class TendersController extends AppController {
|
class TendersController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -62,7 +75,7 @@ class TendersController extends AppController {
|
|||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
$links['Tender'] = array('name', 'id');
|
$links['Tender'] = array('name', 'id');
|
||||||
$links['Customer'] = array('name');
|
$links['Customer'] = array('name');
|
||||||
//$links['TenderType'] = array('name');
|
$links['TenderType'] = array('name');
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,33 +115,15 @@ class TendersController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function nsf($id = null) {
|
function nsf($id = null) {
|
||||||
if ($this->data) {
|
|
||||||
$result = $this->Tender->nsf
|
|
||||||
($this->data['Tender']['id'],
|
|
||||||
$this->data['Transaction']['stamp'],
|
|
||||||
$this->data['Transaction']['comment']);
|
|
||||||
$this->redirect(array('controller' => 'tenders',
|
|
||||||
'action' => 'view',
|
|
||||||
$this->data['Tender']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$id) {
|
if (!$id) {
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
$this->redirect(array('action'=>'index'));
|
$this->redirect(array('action'=>'index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->Tender->id = $id;
|
$this->Tender->nsf($id);
|
||||||
$tender = $this->Tender->find
|
$this->redirect(array('action'=>'view', $id));
|
||||||
('first', array
|
|
||||||
('contain' => array('Customer', 'LedgerEntry' => array('Transaction')),
|
|
||||||
));
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']} : NSF";
|
|
||||||
$this->set(compact('tender', 'title'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -143,7 +138,6 @@ class TendersController extends AppController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the Tender and related fields
|
// Get the Tender and related fields
|
||||||
$this->Tender->id = $id;
|
|
||||||
$tender = $this->Tender->find
|
$tender = $this->Tender->find
|
||||||
('first', array
|
('first', array
|
||||||
('contain' => array('TenderType', 'Customer', 'LedgerEntry' => array('Transaction')),
|
('contain' => array('TenderType', 'Customer', 'LedgerEntry' => array('Transaction')),
|
||||||
@@ -154,87 +148,20 @@ class TendersController extends AppController {
|
|||||||
&& empty($tender['Tender']['nsf_transaction_id'])
|
&& empty($tender['Tender']['nsf_transaction_id'])
|
||||||
// Hard to tell what types of items can come back as NSF.
|
// Hard to tell what types of items can come back as NSF.
|
||||||
// For now, assume iff it is a named item, it can be NSF.
|
// For now, assume iff it is a named item, it can be NSF.
|
||||||
// (or if we're in development mode)
|
&& !empty($tender['TenderType']['data1_name'])
|
||||||
&& (!empty($tender['TenderType']['data1_name']) || !empty($this->params['dev']))
|
|
||||||
) {
|
) {
|
||||||
$this->addSideMenuLink('NSF',
|
// Set up dynamic menu items
|
||||||
array('action' => 'nsf', $id), null,
|
$this->sidemenu_links[] =
|
||||||
'ACTION');
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'NSF',
|
||||||
|
'url' => array('action' => 'nsf',
|
||||||
|
$id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch out for the special "Closing" entries, which have
|
|
||||||
// tender_type_id set to NULL. Otherwise, allow editing.
|
|
||||||
if (!empty($tender['TenderType']['id']))
|
|
||||||
$this->addSideMenuLink('Edit',
|
|
||||||
array('action' => 'edit', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
// Prepare to render.
|
// Prepare to render.
|
||||||
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']}";
|
$title = "Tender #{$tender['Tender']['id']}";
|
||||||
$this->set(compact('tender', 'title'));
|
$this->set(compact('tender', 'title'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: edit
|
|
||||||
* - Edit tender information
|
|
||||||
*/
|
|
||||||
|
|
||||||
function edit($id = null) {
|
|
||||||
if (isset($this->data)) {
|
|
||||||
// Check to see if the operation was cancelled.
|
|
||||||
if (isset($this->params['form']['cancel'])) {
|
|
||||||
if (empty($this->data['Tender']['id']))
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['Tender']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we have tender data
|
|
||||||
if (empty($this->data['Tender']) || empty($this->data['Tender']['id']))
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
|
|
||||||
// Figure out which tender type was chosen
|
|
||||||
// REVISIT <AP>: 20090810; Not ready to change tender type
|
|
||||||
// $tender_type_id = $this->data['Tender']['tender_type_id'];
|
|
||||||
$tender_type_id = $this->Tender->field('tender_type_id');
|
|
||||||
if (empty($tender_type_id))
|
|
||||||
$this->redirect(array('action'=>'view', $this->data['Tender']['id']));
|
|
||||||
|
|
||||||
// Get data fields from the selected tender type
|
|
||||||
$this->data['Tender'] += $this->data['type'][$tender_type_id];
|
|
||||||
unset($this->data['type']);
|
|
||||||
|
|
||||||
// Save the tender and all associated data
|
|
||||||
$this->Tender->create();
|
|
||||||
$this->Tender->id = $this->data['Tender']['id'];
|
|
||||||
if (!$this->Tender->save($this->data, false)) {
|
|
||||||
$this->Session->setFlash("TENDER SAVE FAILED", true);
|
|
||||||
pr("TENDER SAVE FAILED");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->redirect(array('action'=>'view', $this->Tender->id));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($id) {
|
|
||||||
$this->data = $this->Tender->findById($id);
|
|
||||||
} else {
|
|
||||||
$this->redirect(array('action'=>'index'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$tender_types = $this->Tender->TenderType->find
|
|
||||||
('list', array('order' => array('name')));
|
|
||||||
$this->set(compact('tender_types'));
|
|
||||||
|
|
||||||
$types = $this->Tender->TenderType->find('all', array('contain' => false));
|
|
||||||
$this->set(compact('types'));
|
|
||||||
|
|
||||||
// Prepare to render.
|
|
||||||
$title = ('Tender #' . $this->data['Tender']['id'] .
|
|
||||||
' : ' . $this->data['Tender']['name'] .
|
|
||||||
" : Edit");
|
|
||||||
$this->set(compact('title'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+67
-214
@@ -4,38 +4,26 @@ class TransactionsController extends AppController {
|
|||||||
|
|
||||||
var $components = array('RequestHandler');
|
var $components = array('RequestHandler');
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Transactions', 'header' => true),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'transactions', 'action' => 'all')),
|
||||||
|
array('name' => 'Invoices', 'url' => array('controller' => 'transactions', 'action' => 'invoice')),
|
||||||
|
array('name' => 'Receipts', 'url' => array('controller' => 'transactions', 'action' => 'receipt')),
|
||||||
|
array('name' => 'Deposits', 'url' => array('controller' => 'transactions', 'action' => 'deposit')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
* override: addGridViewSideMenuLinks
|
* override: sideMenuLinks
|
||||||
* - Adds grid view navigation side menu links
|
* - Generates controller specific links for the side menu
|
||||||
*/
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
function addGridViewSideMenuLinks() {
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
parent::addGridViewSideMenuLinks();
|
|
||||||
|
|
||||||
$this->addSideMenuLink('Invoices',
|
|
||||||
array('controller' => 'transactions', 'action' => 'invoice'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Receipts',
|
|
||||||
array('controller' => 'transactions', 'action' => 'receipt'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('Deposits',
|
|
||||||
array('controller' => 'transactions', 'action' => 'deposit'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
$this->addSideMenuLink('All',
|
|
||||||
array('controller' => 'transactions', 'action' => 'all'), null,
|
|
||||||
'CONTROLLER');
|
|
||||||
|
|
||||||
// REVISIT <AP>: 20090824
|
|
||||||
// Right now, we wish to keep things simple. Don't make these
|
|
||||||
// links available to non-admin users.
|
|
||||||
if (empty($this->params['admin']))
|
|
||||||
$this->sideMenuEnable('CONTROLLER', $this->std_area, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -47,18 +35,7 @@ class TransactionsController extends AppController {
|
|||||||
function all() { $this->gridView('All Transactions', 'all'); }
|
function all() { $this->gridView('All Transactions', 'all'); }
|
||||||
function invoice() { $this->gridView('Invoices'); }
|
function invoice() { $this->gridView('Invoices'); }
|
||||||
function receipt() { $this->gridView('Receipts'); }
|
function receipt() { $this->gridView('Receipts'); }
|
||||||
function deposit() {
|
function deposit() { $this->gridView('Deposits'); }
|
||||||
/* $this->addSideMenuLink('New Deposit', */
|
|
||||||
/* array('controller' => 'tenders', 'action' => 'deposit'), null, */
|
|
||||||
/* 'CONTROLLER', $this->new_area); */
|
|
||||||
$this->gridView('Deposits');
|
|
||||||
}
|
|
||||||
|
|
||||||
function gridView($title, $action = null, $element = null) {
|
|
||||||
if ($title != 'Deposits')
|
|
||||||
$this->set('include', array('Customer'));
|
|
||||||
parent::gridView($title, $action, $element);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
@@ -71,19 +48,13 @@ class TransactionsController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function gridDataCountTables(&$params, &$model) {
|
function gridDataCountTables(&$params, &$model) {
|
||||||
return array
|
return parent::gridDataTables($params, $model);
|
||||||
('link' =>
|
|
||||||
array(// Models
|
|
||||||
'Account' => array('fields' => array()),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
function gridDataTables(&$params, &$model) {
|
||||||
$link = $this->gridDataCountTables($params, $model);
|
$link = $this->gridDataCountTables($params, $model);
|
||||||
$link['link']['StatementEntry'] = array('fields' => array());
|
$link['link']['StatementEntry'] = array('fields' => array());
|
||||||
$link['link']['DepositTender'] = array('fields' => array());
|
$link['link']['DepositTender'] = array('fields' => array());
|
||||||
$link['link']['Customer'] = array('fields' => array('id', 'name'));
|
|
||||||
return $link;
|
return $link;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +77,7 @@ class TransactionsController extends AppController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
|
$links['Transaction'] = array('id');
|
||||||
? 'deposit_slip' : 'view'));
|
|
||||||
$links['Customer'] = array('name');
|
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +89,7 @@ class TransactionsController extends AppController {
|
|||||||
* - handles the creation of a charge invoice
|
* - handles the creation of a charge invoice
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function postInvoice($redirect = true) {
|
function postInvoice() {
|
||||||
if (!$this->RequestHandler->isPost()) {
|
if (!$this->RequestHandler->isPost()) {
|
||||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||||
return;
|
return;
|
||||||
@@ -135,17 +104,6 @@ class TransactionsController extends AppController {
|
|||||||
die("<H1>INVOICE FAILED</H1>");
|
die("<H1>INVOICE FAILED</H1>");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($redirect) {
|
|
||||||
if (!empty($this->data['Customer']['id']))
|
|
||||||
$this->redirect(array('controller' => 'customers',
|
|
||||||
'action' => 'receipt',
|
|
||||||
$this->data['Customer']['id']));
|
|
||||||
else
|
|
||||||
$this->redirect(array('controller' => 'leases',
|
|
||||||
'action' => 'view',
|
|
||||||
$this->data['Lease']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->layout = null;
|
$this->layout = null;
|
||||||
$this->autoLayout = false;
|
$this->autoLayout = false;
|
||||||
$this->autoRender = false;
|
$this->autoRender = false;
|
||||||
@@ -156,10 +114,10 @@ class TransactionsController extends AppController {
|
|||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
* action: postReceipt
|
* action: postReceipt
|
||||||
* - handles the creation of a receipt
|
* - handles the creation of a payment receipt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function postReceipt($redirect = true) {
|
function postReceipt() {
|
||||||
if (!$this->RequestHandler->isPost()) {
|
if (!$this->RequestHandler->isPost()) {
|
||||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||||
return;
|
return;
|
||||||
@@ -183,11 +141,6 @@ class TransactionsController extends AppController {
|
|||||||
die("<H1>RECEIPT FAILED</H1>");
|
die("<H1>RECEIPT FAILED</H1>");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($redirect)
|
|
||||||
$this->redirect(array('controller' => 'customers',
|
|
||||||
'action' => 'view',
|
|
||||||
$this->data['Customer']['id']));
|
|
||||||
|
|
||||||
$this->layout = null;
|
$this->layout = null;
|
||||||
$this->autoLayout = false;
|
$this->autoLayout = false;
|
||||||
$this->autoRender = false;
|
$this->autoRender = false;
|
||||||
@@ -300,7 +253,7 @@ class TransactionsController extends AppController {
|
|||||||
$this->Session->setFlash(__('Unable to Create Deposit', true));
|
$this->Session->setFlash(__('Unable to Create Deposit', true));
|
||||||
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
|
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present the deposit slip to the user
|
// Present the deposit slip to the user
|
||||||
$this->redirect(array('controller' => 'transactions',
|
$this->redirect(array('controller' => 'transactions',
|
||||||
'action' => 'deposit_slip',
|
'action' => 'deposit_slip',
|
||||||
@@ -308,107 +261,6 @@ class TransactionsController extends AppController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: postWriteOff
|
|
||||||
* - handles the write off of bad debt
|
|
||||||
*/
|
|
||||||
|
|
||||||
function postWriteOff() {
|
|
||||||
if (!$this->RequestHandler->isPost()) {
|
|
||||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->data;
|
|
||||||
if (empty($data['Customer']['id']))
|
|
||||||
$data['Customer']['id'] = null;
|
|
||||||
if (empty($data['Lease']['id']))
|
|
||||||
$data['Lease']['id'] = null;
|
|
||||||
|
|
||||||
pr(compact('data'));
|
|
||||||
|
|
||||||
if (!$this->Transaction->addWriteOff($data,
|
|
||||||
$data['Customer']['id'],
|
|
||||||
$data['Lease']['id'])) {
|
|
||||||
$this->Session->setFlash("WRITE OFF FAILED", true);
|
|
||||||
// REVISIT <AP> 20090706:
|
|
||||||
// Until we can work out the session problems,
|
|
||||||
// just die.
|
|
||||||
die("<H1>WRITE-OFF FAILED</H1>");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return to viewing the lease/customer
|
|
||||||
if (empty($data['Lease']['id']))
|
|
||||||
$this->redirect(array('controller' => 'customers',
|
|
||||||
'action' => 'view',
|
|
||||||
$data['Customer']['id']));
|
|
||||||
else
|
|
||||||
$this->redirect(array('controller' => 'leases',
|
|
||||||
'action' => 'view',
|
|
||||||
$data['Lease']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: postRefund
|
|
||||||
* - handles issuing a customer refund
|
|
||||||
*/
|
|
||||||
|
|
||||||
function postRefund() {
|
|
||||||
if (!$this->RequestHandler->isPost()) {
|
|
||||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->data;
|
|
||||||
if (empty($data['Customer']['id']))
|
|
||||||
$data['Customer']['id'] = null;
|
|
||||||
if (empty($data['Lease']['id']))
|
|
||||||
$data['Lease']['id'] = null;
|
|
||||||
|
|
||||||
if (!$this->Transaction->addRefund($data,
|
|
||||||
$data['Customer']['id'],
|
|
||||||
$data['Lease']['id'])) {
|
|
||||||
$this->Session->setFlash("REFUND FAILED", true);
|
|
||||||
// REVISIT <AP> 20090706:
|
|
||||||
// Until we can work out the session problems,
|
|
||||||
// just die.
|
|
||||||
die("<H1>REFUND FAILED</H1>");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return to viewing the lease/customer
|
|
||||||
if (empty($data['Lease']['id']))
|
|
||||||
$this->redirect(array('controller' => 'customers',
|
|
||||||
'action' => 'view',
|
|
||||||
$data['Customer']['id']));
|
|
||||||
else
|
|
||||||
$this->redirect(array('controller' => 'leases',
|
|
||||||
'action' => 'view',
|
|
||||||
$data['Lease']['id']));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* action: destroy
|
|
||||||
* - Deletes a transaction and associated entries
|
|
||||||
* - !!WARNING!! This should be used with EXTREME caution, as it
|
|
||||||
* irreversibly destroys the data. It is not for normal use.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function destroy($id) {
|
|
||||||
$this->Transaction->id = $id;
|
|
||||||
$customer_id = $this->Transaction->field('customer_id');
|
|
||||||
$this->Transaction->destroy($id);
|
|
||||||
$this->redirect(array('controller' => 'customers', 'action' => 'view', $customer_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -417,39 +269,34 @@ class TransactionsController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function view($id = null) {
|
function view($id = null) {
|
||||||
$transaction = $this->Transaction->find
|
if (!$id) {
|
||||||
('first',
|
|
||||||
array('contain' =>
|
|
||||||
array(// Models
|
|
||||||
'Account(id,name,level)',
|
|
||||||
'Ledger(id,sequence)',
|
|
||||||
'NsfTender(id,name)',
|
|
||||||
),
|
|
||||||
'conditions' => array(array('Transaction.id' => $id),
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
if (empty($transaction)) {
|
|
||||||
$this->Session->setFlash(__('Invalid Item.', true));
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
$this->redirect(array('action'=>'index'));
|
$this->redirect(array('action'=>'index'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$transaction['Account']['link'] =
|
$transaction = $this->Transaction->find
|
||||||
$transaction['Account']['level'] >=
|
('first',
|
||||||
$this->Permission->level('controller.accounts');
|
array('contain' =>
|
||||||
|
array(// Models
|
||||||
|
'Account' =>
|
||||||
|
array('fields' => array('Account.id',
|
||||||
|
'Account.name'),
|
||||||
|
),
|
||||||
|
|
||||||
if ($transaction['Transaction']['type'] === 'DEPOSIT')
|
'Ledger' =>
|
||||||
$this->addSideMenuLink('View Slip',
|
array('fields' => array('Ledger.id',
|
||||||
array('action' => 'deposit_slip', $id), null,
|
'Ledger.name'),
|
||||||
'ACTION');
|
),
|
||||||
|
),
|
||||||
|
'conditions' => array('Transaction.id' => $id),
|
||||||
|
));
|
||||||
|
|
||||||
$this->addSideMenuLink('Destroy',
|
if ($transaction['Transaction']['type'] === 'DEPOSIT') {
|
||||||
array('action' => 'destroy', $id),
|
$this->sidemenu_links[] =
|
||||||
array('confirmMessage' =>
|
array('name' => 'Operations', 'header' => true);
|
||||||
"This may leave the database in an unstable state." .
|
$this->sidemenu_links[] =
|
||||||
" Do NOT do this unless you know what you're doing." .
|
array('name' => 'View Slip', 'url' => array('action' => 'deposit_slip', $id));
|
||||||
" Proceed anyway?"),
|
}
|
||||||
'ACTION', $this->admin_area);
|
|
||||||
|
|
||||||
// OK, prepare to render.
|
// OK, prepare to render.
|
||||||
$title = 'Transaction #' . $transaction['Transaction']['id'];
|
$title = 'Transaction #' . $transaction['Transaction']['id'];
|
||||||
@@ -466,12 +313,15 @@ class TransactionsController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function deposit_slip($id) {
|
function deposit_slip($id) {
|
||||||
// Find the deposit transaction
|
// Build a container for the deposit slip data
|
||||||
$this->Transaction->id = $id;
|
$deposit = array('types' => array());
|
||||||
$deposit = $this->Transaction->find('first', array('contain' => false));
|
|
||||||
|
$this->id = $id;
|
||||||
|
$deposit +=
|
||||||
|
$this->Transaction->find('first', array('contain' => false));
|
||||||
|
|
||||||
// Get a summary of all forms of tender in the deposit
|
// Get a summary of all forms of tender in the deposit
|
||||||
$tenders = $this->Transaction->find
|
$result = $this->Transaction->find
|
||||||
('all',
|
('all',
|
||||||
array('link' => array('DepositTender' =>
|
array('link' => array('DepositTender' =>
|
||||||
array('fields' => array(),
|
array('fields' => array(),
|
||||||
@@ -486,29 +336,32 @@ class TransactionsController extends AppController {
|
|||||||
'group' => 'TenderType.id',
|
'group' => 'TenderType.id',
|
||||||
));
|
));
|
||||||
|
|
||||||
// Verify the deposit exists, and that something was actually deposited
|
if (empty($result)) {
|
||||||
if (empty($deposit) || empty($tenders)) {
|
die();
|
||||||
$this->Session->setFlash(__('Invalid Deposit.', true));
|
$this->Session->setFlash(__('Invalid Deposit.', true));
|
||||||
$this->redirect(array('action'=>'deposit'));
|
$this->redirect(array('action'=>'deposit'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the summary to our deposit slip data container
|
// Add the summary to our deposit slip data container
|
||||||
$deposit['types'] = array();
|
foreach ($result AS $type) {
|
||||||
foreach ($tenders AS $tender) {
|
$deposit['types'][$type['TenderType']['id']] =
|
||||||
$deposit['types'][$tender['TenderType']['id']] =
|
$type['TenderType'] + $type[0];
|
||||||
$tender['TenderType'] + $tender[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$deposit_total = 0;
|
// For each form of tender in the deposit, get the deposit items
|
||||||
foreach ($deposit['types'] AS $type)
|
/* foreach ($deposit['types'] AS $type_id => &$type) { */
|
||||||
$deposit_total += $type['total'];
|
/* $type['entries'] = $this->Transaction->DepositTender->find */
|
||||||
|
/* ('all', */
|
||||||
|
/* array('contain' => array('Customer', 'LedgerEntry'), */
|
||||||
|
/* 'conditions' => array(array('DepositTender.deposit_transaction_id' => $id), */
|
||||||
|
/* array('DepositTender.tender_type_id' => $type_id)), */
|
||||||
|
/* )); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
if ($deposit['Transaction']['amount'] != $deposit_total)
|
$this->sidemenu_links[] =
|
||||||
$this->INTERNAL_ERROR("Deposit items do not add up to deposit slip total");
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
$this->sidemenu_links[] =
|
||||||
$this->addSideMenuLink('View',
|
array('name' => 'View Transaction', 'url' => array('action' => 'view', $id));
|
||||||
array('action' => 'view', $id), null,
|
|
||||||
'ACTION');
|
|
||||||
|
|
||||||
$title = 'Deposit Slip';
|
$title = 'Deposit Slip';
|
||||||
$this->set(compact('title', 'deposit'));
|
$this->set(compact('title', 'deposit'));
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class UnitsController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Units', 'header' => true),
|
||||||
|
array('name' => 'Occupied', 'url' => array('controller' => 'units', 'action' => 'occupied')),
|
||||||
|
array('name' => 'Vacant', 'url' => array('controller' => 'units', 'action' => 'vacant')),
|
||||||
|
array('name' => 'Unavailable', 'url' => array('controller' => 'units', 'action' => 'unavailable')),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'units', 'action' => 'all')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: index / unavailable / vacant / occupied / all
|
||||||
|
* - Generate a listing of units
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->all(); }
|
||||||
|
function unavailable() { $this->gridView('Unavailable Units'); }
|
||||||
|
function vacant() { $this->gridView('Vacant Units'); }
|
||||||
|
function occupied() { $this->gridView('Occupied Units'); }
|
||||||
|
function all() { $this->gridView('All Units', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: gridData
|
||||||
|
* - With the application controller handling the gridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function gridDataSetup(&$params) {
|
||||||
|
parent::gridDataSetup($params);
|
||||||
|
if (!isset($params['action']))
|
||||||
|
$params['action'] = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataCountTables(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('link' => array('UnitSize' => array('fields' => array('id', 'name')),
|
||||||
|
'CurrentLease' => array('fields' => array('id'))));
|
||||||
|
|
||||||
|
/* if ($params['action'] === 'occupied') */
|
||||||
|
/* $link['Lease'] = array('fields' => array(), */
|
||||||
|
/* // Models */
|
||||||
|
/* 'Contact' => array('fields' => array('display_name'), */
|
||||||
|
/* //'type' => 'LEFT', */
|
||||||
|
/* ), */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataTables(&$params, &$model) {
|
||||||
|
$link = $this->gridDataCountTables($params, $model);
|
||||||
|
$link['link']['CurrentLease']['StatementEntry'] = array('fields' => array());
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* function gridDataTables(&$params, &$model) { */
|
||||||
|
/* return array */
|
||||||
|
/* ('link' => array('Unit' => array('fields' => array('Unit.id', 'Unit.name')), */
|
||||||
|
/* 'Customer' => array('fields' => array('Customer.id', 'Customer.name')))); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
function gridDataFields(&$params, &$model) {
|
||||||
|
$fields = parent::gridDataFields($params, $model);
|
||||||
|
|
||||||
|
return array_merge($fields,
|
||||||
|
$this->Unit->Lease->StatementEntry->chargePaymentFields(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::gridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if ($params['action'] === 'unavailable') {
|
||||||
|
$conditions[] = $this->Unit->conditionUnavailable();
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'vacant') {
|
||||||
|
$conditions[] = $this->Unit->conditionVacant();
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'occupied') {
|
||||||
|
$conditions[] = $this->Unit->conditionOccupied();
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'unoccupied') {
|
||||||
|
$conditions[] = array('NOT' => array($this->Unit->conditionOccupied()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
// Instead of sorting by name, sort by defined order
|
||||||
|
if ($index === 'Unit.name')
|
||||||
|
$index = 'Unit.sort_order';
|
||||||
|
|
||||||
|
$order = array();
|
||||||
|
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
|
||||||
|
|
||||||
|
// If sorting by anything other than name (defined order)
|
||||||
|
// add the sort-order as a secondary condition
|
||||||
|
if ($index !== 'Unit.name')
|
||||||
|
$order[] = parent::gridDataOrder($params, $model,
|
||||||
|
'Unit.sort_order', $direction);
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Unit'] = array('name');
|
||||||
|
$links['UnitSize'] = array('name');
|
||||||
|
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: move_in
|
||||||
|
* - Sets up the move-in page for the given unit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function move_in($id = null) {
|
||||||
|
$customer = array();
|
||||||
|
$unit = array();
|
||||||
|
|
||||||
|
if (isset($id)) {
|
||||||
|
$this->Unit->recursive = -1;
|
||||||
|
$unit = current($this->Unit->read(null, $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = 'Unit Move-In';
|
||||||
|
$this->set(compact('customer', 'unit', 'title'));
|
||||||
|
$this->render('/leases/move');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: move_out
|
||||||
|
* - prepare or execute a move out on a specific lease
|
||||||
|
*/
|
||||||
|
|
||||||
|
function move_out($id) {
|
||||||
|
|
||||||
|
$unit = $this->Unit->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'CurrentLease' =>
|
||||||
|
array(//'conditions' => array('Lease.moveout_date' => null),
|
||||||
|
// Models
|
||||||
|
'Customer' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'conditions' => array('Unit.id' => $id),
|
||||||
|
));
|
||||||
|
$this->set('customer', $unit['CurrentLease']['Customer']);
|
||||||
|
$this->set('unit', $unit['Unit']);
|
||||||
|
$this->set('lease', $unit['CurrentLease']);
|
||||||
|
|
||||||
|
$redirect = array('controller' => 'units',
|
||||||
|
'action' => 'view',
|
||||||
|
$id);
|
||||||
|
|
||||||
|
$title = ('Lease #' . $unit['CurrentLease']['number'] . ': ' .
|
||||||
|
$unit['Unit']['name'] . ': ' .
|
||||||
|
$unit['CurrentLease']['Customer']['name'] . ': Prepare Move-Out');
|
||||||
|
$this->set(compact('title', 'redirect'));
|
||||||
|
$this->render('/leases/move');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific unit
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>''));
|
||||||
|
}
|
||||||
|
|
||||||
|
$unit = $this->Unit->find
|
||||||
|
('first',
|
||||||
|
array('contain' =>
|
||||||
|
array(// Models
|
||||||
|
'UnitSize',
|
||||||
|
'Lease' => array('Customer'),
|
||||||
|
'CurrentLease' => array('Customer')
|
||||||
|
),
|
||||||
|
'conditions' => array('Unit.id' => $id),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Get the balance on each lease.
|
||||||
|
foreach ($unit['Lease'] AS &$lease) {
|
||||||
|
$stats = $this->Unit->Lease->stats($lease['id']);
|
||||||
|
$lease['balance'] = $stats['balance'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$outstanding_balance = 0;
|
||||||
|
$outstanding_deposit = 0;
|
||||||
|
if (isset($unit['CurrentLease']['id'])) {
|
||||||
|
// Figure out the outstanding balance of the current lease.
|
||||||
|
$stats = $this->Unit->stats($id);
|
||||||
|
$outstanding_balance =
|
||||||
|
$stats['CurrentLease']['balance'];
|
||||||
|
|
||||||
|
// Figure out the total security deposit for the current lease.
|
||||||
|
$deposits = $this->Unit->Lease->securityDeposits($unit['CurrentLease']['id']);
|
||||||
|
$outstanding_deposit = $this->Unit->Lease->securityDepositBalance($unit['CurrentLease']['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up dynamic menu items
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
|
||||||
|
if (isset($unit['CurrentLease']['id']) &&
|
||||||
|
!isset($unit['CurrentLease']['moveout_date'])) {
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
|
||||||
|
$id));
|
||||||
|
} else {
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Move-In', 'url' => array('action' => 'move_in',
|
||||||
|
$id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($unit['CurrentLease']['id']) &&
|
||||||
|
!isset($unit['CurrentLease']['close_date'])) {
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Payment', 'url' => array('controller' => 'customers',
|
||||||
|
'action' => 'receipt',
|
||||||
|
$unit['CurrentLease']['customer_id']));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = 'Unit ' . $unit['Unit']['name'];
|
||||||
|
$this->set(compact('unit', 'title',
|
||||||
|
'outstanding_balance',
|
||||||
|
'outstanding_deposit'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -121,42 +121,22 @@ class Account extends AppModel {
|
|||||||
* - Returns the ID of the desired account
|
* - Returns the ID of the desired account
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function lookup($name, $check = true) {
|
function securityDepositAccountID() { return $this->nameToID('Security Deposit'); }
|
||||||
$id = $this->nameToID($name);
|
function rentAccountID() { return $this->nameToID('Rent'); }
|
||||||
if (empty($id) && $check)
|
function lateChargeAccountID() { return $this->nameToID('Late Charge'); }
|
||||||
$this->INTERNAL_ERROR("Missing Account '$name'");
|
function nsfAccountID() { return $this->nameToID('NSF'); }
|
||||||
return $id;
|
function nsfChargeAccountID() { return $this->nameToID('NSF Charge'); }
|
||||||
}
|
function taxAccountID() { return $this->nameToID('Tax'); }
|
||||||
|
function accountReceivableAccountID() { return $this->nameToID('A/R'); }
|
||||||
|
function cashAccountID() { return $this->nameToID('Cash'); }
|
||||||
|
function checkAccountID() { return $this->nameToID('Check'); }
|
||||||
|
function moneyOrderAccountID() { return $this->nameToID('Money Order'); }
|
||||||
|
function concessionAccountID() { return $this->nameToID('Concession'); }
|
||||||
|
function pettyCashAccountID() { return $this->nameToID('Petty Cash'); }
|
||||||
|
function invoiceAccountID() { return $this->nameToID('Invoice'); }
|
||||||
|
function receiptAccountID() { return $this->nameToID('Receipt'); }
|
||||||
|
function badDebtAccountID() { return $this->nameToID('Bad Debt'); }
|
||||||
|
|
||||||
function securityDepositAccountID() { return $this->lookup('Security Deposit'); }
|
|
||||||
function rentAccountID() { return $this->lookup('Rent'); }
|
|
||||||
function lateChargeAccountID() { return $this->lookup('Late Charge'); }
|
|
||||||
function nsfAccountID() { return $this->lookup('NSF'); }
|
|
||||||
function nsfChargeAccountID() { return $this->lookup('NSF Charge'); }
|
|
||||||
function taxAccountID() { return $this->lookup('Tax'); }
|
|
||||||
function accountReceivableAccountID() { return $this->lookup('A/R'); }
|
|
||||||
function accountPayableAccountID() { return $this->lookup('A/P'); }
|
|
||||||
function cashAccountID() { return $this->lookup('Cash'); }
|
|
||||||
function checkAccountID() { return $this->lookup('Check'); }
|
|
||||||
function moneyOrderAccountID() { return $this->lookup('Money Order'); }
|
|
||||||
function achAccountID() { return $this->lookup('ACH'); }
|
|
||||||
function concessionAccountID() { return $this->lookup('Concession'); }
|
|
||||||
function waiverAccountID() { return $this->lookup('Waiver'); }
|
|
||||||
function pettyCashAccountID() { return $this->lookup('Petty Cash'); }
|
|
||||||
function invoiceAccountID() { return $this->lookup('Invoice'); }
|
|
||||||
function receiptAccountID() { return $this->lookup('Receipt'); }
|
|
||||||
function badDebtAccountID() { return $this->lookup('Bad Debt'); }
|
|
||||||
function customerCreditAccountID() { return $this->lookup(
|
|
||||||
// REVISIT <AP>: 20090816
|
|
||||||
// Use of A/R works, and saves an excess of accounts.
|
|
||||||
// However, a dedicated account is nice, since it can
|
|
||||||
// quickly be spotted how much is _really_ due, vs
|
|
||||||
// how much has been pre-paid. Customer credits in
|
|
||||||
// A/R is not as clear, although a report is an
|
|
||||||
// obvious solution.
|
|
||||||
//'A/R'
|
|
||||||
'Credit'
|
|
||||||
); }
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -188,7 +168,8 @@ class Account extends AppModel {
|
|||||||
function relatedAccounts($attribute, $extra = null) {
|
function relatedAccounts($attribute, $extra = null) {
|
||||||
$this->cacheQueries = true;
|
$this->cacheQueries = true;
|
||||||
$accounts = $this->find('all', array
|
$accounts = $this->find('all', array
|
||||||
('fields' => array('Account.id', 'Account.name'),
|
('contain' => array('CurrentLedger'),
|
||||||
|
'fields' => array('Account.id', 'Account.type', 'Account.name', 'CurrentLedger.id'),
|
||||||
'conditions' => array('Account.'.$attribute => true),
|
'conditions' => array('Account.'.$attribute => true),
|
||||||
'order' => array('Account.name'),
|
'order' => array('Account.name'),
|
||||||
) + (isset($extra) ? $extra : array())
|
) + (isset($extra) ? $extra : array())
|
||||||
@@ -212,10 +193,17 @@ class Account extends AppModel {
|
|||||||
* - Returns an array of accounts suitable for activity xxx
|
* - Returns an array of accounts suitable for activity xxx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function invoiceAccounts() { return $this->relatedAccounts('invoices'); }
|
function chargeAccounts() {
|
||||||
function receiptAccounts() { return $this->relatedAccounts('receipts'); }
|
return $this->relatedAccounts('charges', array('order' => 'name'));
|
||||||
function depositAccounts() { return $this->relatedAccounts('deposits'); }
|
}
|
||||||
function refundAccounts() { return $this->relatedAccounts('refunds'); }
|
|
||||||
|
function paymentAccounts() {
|
||||||
|
return $this->relatedAccounts('payments', array('order' => 'name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function depositAccounts() {
|
||||||
|
return $this->relatedAccounts('deposits', array('order' => 'name'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
@@ -226,30 +214,14 @@ class Account extends AppModel {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function collectableAccounts() {
|
function collectableAccounts() {
|
||||||
$accounts = $this->receiptAccounts();
|
$accounts = $this->paymentAccounts();
|
||||||
|
|
||||||
foreach(array($this->customerCreditAccountID(),
|
foreach(array($this->nsfAccountID(),
|
||||||
$this->securityDepositAccountID(),
|
$this->securityDepositAccountID())
|
||||||
$this->nsfAccountID(),
|
|
||||||
$this->waiverAccountID(),
|
|
||||||
$this->badDebtAccountID(),
|
|
||||||
//$this->lookup('Closing'),
|
|
||||||
//$this->lookup('Equity'),
|
|
||||||
)
|
|
||||||
AS $account_id) {
|
AS $account_id) {
|
||||||
$accounts[$account_id] = $this->name($account_id);
|
$accounts[$account_id] = $this->name($account_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$accounts['all'] = $accounts['default'] = $accounts;
|
|
||||||
|
|
||||||
foreach(array($this->concessionAccountID(),
|
|
||||||
$this->waiverAccountID(),
|
|
||||||
$this->badDebtAccountID(),
|
|
||||||
)
|
|
||||||
AS $account_id) {
|
|
||||||
unset($accounts['default'][$account_id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $accounts;
|
return $accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +337,6 @@ class Account extends AppModel {
|
|||||||
$this->queryInit($query);
|
$this->queryInit($query);
|
||||||
$query['link'] = array('Account' => $query['link']);
|
$query['link'] = array('Account' => $query['link']);
|
||||||
|
|
||||||
$stats = array();
|
|
||||||
foreach ($this->ledgers($id, $all) AS $ledger)
|
foreach ($this->ledgers($id, $all) AS $ledger)
|
||||||
$this->statsMerge($stats['Ledger'],
|
$this->statsMerge($stats['Ledger'],
|
||||||
$this->Ledger->stats($ledger, $query));
|
$this->Ledger->stats($ledger, $query));
|
||||||
@@ -41,15 +41,14 @@ class Contact extends AppModel {
|
|||||||
function saveContact($id, $data) {
|
function saveContact($id, $data) {
|
||||||
|
|
||||||
// Establish a display name if not already given
|
// Establish a display name if not already given
|
||||||
if (!$data['Contact']['display_name'] &&
|
if (!$data['Contact']['display_name'])
|
||||||
$data['Contact']['first_name'] && $data['Contact']['last_name'])
|
|
||||||
$data['Contact']['display_name'] =
|
$data['Contact']['display_name'] =
|
||||||
$data['Contact']['last_name'] . ', ' . $data['Contact']['first_name'];
|
(($data['Contact']['first_name'] &&
|
||||||
|
$data['Contact']['last_name'])
|
||||||
foreach (array('last_name', 'first_name', 'company_name') AS $fld) {
|
? $data['Contact']['last_name'] . ', ' . $data['Contact']['first_name']
|
||||||
if (!$data['Contact']['display_name'] && $data['Contact'][$fld])
|
: ($data['Contact']['first_name']
|
||||||
$data['Contact']['display_name'] = $data['Contact'][$fld];
|
? $data['Contact']['first_name']
|
||||||
}
|
: $data['Contact']['last_name']));
|
||||||
|
|
||||||
// Save the contact data
|
// Save the contact data
|
||||||
$this->create();
|
$this->create();
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
<?php
|
||||||
|
class Customer extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Customer';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'name' => array('notempty'),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'PrimaryContact' => array(
|
||||||
|
'className' => 'Contact',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'CurrentLease' => array(
|
||||||
|
'className' => 'Lease',
|
||||||
|
'conditions' => 'CurrentLease.close_date IS NULL',
|
||||||
|
),
|
||||||
|
'Lease',
|
||||||
|
'StatementEntry',
|
||||||
|
'ContactsCustomer',
|
||||||
|
|
||||||
|
'Transaction',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasAndBelongsToMany = array(
|
||||||
|
'Contact',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: accountId
|
||||||
|
* - Returns the account ID for the given customer
|
||||||
|
*/
|
||||||
|
function accountId($id) {
|
||||||
|
$this->cacheQueries = true;
|
||||||
|
$customer = $this->find('first',
|
||||||
|
array('contain' => false,
|
||||||
|
'fields' => array('account_id'),
|
||||||
|
'conditions' => array(array('Customer.id' => $id))));
|
||||||
|
$this->cacheQueries = false;
|
||||||
|
|
||||||
|
return $customer['Customer']['account_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: leaseIds
|
||||||
|
* - Returns the lease IDs for the given customer
|
||||||
|
*/
|
||||||
|
function leaseIds($id) {
|
||||||
|
$this->cacheQueries = true;
|
||||||
|
$customer = $this->find('first',
|
||||||
|
array('contain' =>
|
||||||
|
array('Lease' => array('fields' => array('id'))),
|
||||||
|
'fields' => array(),
|
||||||
|
'conditions' => array(array('Customer.id' => $id))));
|
||||||
|
$this->cacheQueries = false;
|
||||||
|
|
||||||
|
$ids = array();
|
||||||
|
foreach ($customer['Lease'] AS $lease)
|
||||||
|
$ids[] = $lease['id'];
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: securityDeposits
|
||||||
|
* - Returns an array of security deposit entries
|
||||||
|
*/
|
||||||
|
function securityDeposits($id, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
if (!isset($query['link']['Customer']))
|
||||||
|
$query['link']['Customer'] = array();
|
||||||
|
if (!isset($query['link']['Customer']['fields']))
|
||||||
|
$query['link']['Customer']['fields'] = array();
|
||||||
|
|
||||||
|
$query['conditions'][] = array('Customer.id' => $id);
|
||||||
|
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||||
|
$this->StatementEntry->LedgerEntry->Account->securityDepositAccountID());
|
||||||
|
|
||||||
|
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
||||||
|
return $this->prReturn($set);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: securityDepositBalance
|
||||||
|
* - Returns the balance of the customer security deposit(s)
|
||||||
|
*/
|
||||||
|
|
||||||
|
function securityDepositBalance($id, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
if (!isset($query['link']['Lease']))
|
||||||
|
$query['link']['Lease'] = array();
|
||||||
|
if (!isset($query['link']['Lease']['fields']))
|
||||||
|
$query['link']['Lease']['fields'] = array();
|
||||||
|
|
||||||
|
$query['conditions'][] = array('Lease.id' => $id);
|
||||||
|
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||||
|
$this->StatementEntry->LedgerEntry->Account->securityDepositAccountID());
|
||||||
|
|
||||||
|
$stats = $this->StatementEntry->stats(null, $query);
|
||||||
|
$balance = $stats['Charge']['reconciled'] - $stats['Payment']['reconciled'];
|
||||||
|
return $this->prReturn($balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: unreconciledCharges
|
||||||
|
* - Returns charges have not yet been fully paid
|
||||||
|
*/
|
||||||
|
|
||||||
|
function unreconciledCharges($id, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
if (!isset($query['link']['Customer']))
|
||||||
|
$query['link']['Customer'] = array();
|
||||||
|
if (!isset($query['link']['Customer']['fields']))
|
||||||
|
$query['link']['Customer']['fields'] = array();
|
||||||
|
/* if (!isset($query['link']['StatementEntry'])) */
|
||||||
|
/* $query['link']['StatementEntry'] = array(); */
|
||||||
|
/* if (!isset($query['link']['StatementEntry']['Customer'])) */
|
||||||
|
/* $query['link']['StatementEntry']['Customer'] = array(); */
|
||||||
|
/* if (!isset($query['link']['StatementEntry']['Customer']['fields'])) */
|
||||||
|
/* $query['link']['StatementEntry']['Customer']['fields'] = array(); */
|
||||||
|
|
||||||
|
$query['conditions'][] = array('Customer.id' => $id);
|
||||||
|
|
||||||
|
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
|
||||||
|
return $this->prReturn($set);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: excessPayments
|
||||||
|
* - Returns payments which have not yet been fully utilized
|
||||||
|
*/
|
||||||
|
|
||||||
|
function excessPayments($id, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
if (!isset($query['link']['StatementEntry']))
|
||||||
|
$query['link']['StatementEntry'] = array();
|
||||||
|
/* if (!isset($query['link']['StatementEntry']['Customer'])) */
|
||||||
|
/* $query['link']['StatementEntry']['Customer'] = array(); */
|
||||||
|
/* if (!isset($query['link']['StatementEntry']['Customer']['fields'])) */
|
||||||
|
/* $query['link']['StatementEntry']['Customer']['fields'] = array(); */
|
||||||
|
|
||||||
|
$query['conditions'][] = array('Customer.id' => $id);
|
||||||
|
|
||||||
|
$set = $this->StatementEntry->reconciledSet('PAYMENT', $query, true);
|
||||||
|
return $this->prReturn($set);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: details
|
||||||
|
* - Returns detail information for the customer
|
||||||
|
*/
|
||||||
|
|
||||||
|
function details($id = null) {
|
||||||
|
$this->prEnter(compact('id'));
|
||||||
|
|
||||||
|
// Query the DB for need information.
|
||||||
|
$customer = $this->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'Contact' =>
|
||||||
|
array('order' => array('Contact.display_name'),
|
||||||
|
// Models
|
||||||
|
'ContactPhone',
|
||||||
|
'ContactEmail',
|
||||||
|
'ContactAddress',
|
||||||
|
),
|
||||||
|
'Lease' =>
|
||||||
|
array('Unit' =>
|
||||||
|
array('order' => array('sort_order'),
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array('Customer.id' => $id),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Figure out the outstanding balance for this customer
|
||||||
|
$customer['stats'] = $this->stats($id);
|
||||||
|
|
||||||
|
// Figure out the total security deposit for the current lease.
|
||||||
|
$customer['deposits'] = $this->securityDeposits($id);
|
||||||
|
|
||||||
|
return $this->prReturn($customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: saveCustomer
|
||||||
|
* - Saves the customer and related data
|
||||||
|
*/
|
||||||
|
|
||||||
|
function saveCustomer($id, $data, $primary_contact_entry) {
|
||||||
|
|
||||||
|
// Go through each contact, and create new ones as needed
|
||||||
|
foreach ($data['Contact'] AS &$contact) {
|
||||||
|
if (isset($contact['id']))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$I = new Contact();
|
||||||
|
$I->create();
|
||||||
|
if (!$I->save($contact, false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$contact['id'] = $I->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the primary contact ID based on caller selection
|
||||||
|
$data['Customer']['primary_contact_id']
|
||||||
|
= $data['Contact'][$primary_contact_entry]['id'];
|
||||||
|
|
||||||
|
// Provide a default customer name if not specified
|
||||||
|
if (!$data['Customer']['name']) {
|
||||||
|
$this->Contact->recursive = -1;
|
||||||
|
$pcontact = $this->Contact->read(null, $data['Customer']['primary_contact_id']);
|
||||||
|
$data['Customer']['name'] = $pcontact['Contact']['display_name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the customer data
|
||||||
|
$this->create();
|
||||||
|
if ($id)
|
||||||
|
$this->id = $id;
|
||||||
|
if (!$this->save($data, false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$id = $this->id;
|
||||||
|
|
||||||
|
// Remove all associated Customer Contacts, as it ensures
|
||||||
|
// any entries deleted by the user actually get deleted
|
||||||
|
// in the system. We'll recreate the needed ones anyway.
|
||||||
|
// REVISIT <AP>: 20090706
|
||||||
|
// Appears that $this->save() is already doing the
|
||||||
|
// delete. I would have thought this would only happen
|
||||||
|
// on a saveAll??
|
||||||
|
/* $this->ContactsCustomer->deleteAll */
|
||||||
|
/* (array('customer_id' => $id), false); */
|
||||||
|
|
||||||
|
// At this point, since we've saved data to customer,
|
||||||
|
// 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 entry of this customer method
|
||||||
|
foreach ($data['Contact'] AS &$contact) {
|
||||||
|
// Update the ContactsCustomer to reflect the appropriate IDs
|
||||||
|
$contact['ContactsCustomer']['customer_id'] = $id;
|
||||||
|
$contact['ContactsCustomer']['contact_id'] = $contact['id'];
|
||||||
|
|
||||||
|
// Save the relationship between customer and contact
|
||||||
|
$CM = new ContactsCustomer();
|
||||||
|
if (!$CM->save($contact['ContactsCustomer'], false)) {
|
||||||
|
$ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the result
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested customer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function stats($id = null, $query = null) {
|
||||||
|
//$this->prFunctionLevel(20);
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
if (!$id)
|
||||||
|
return $this->prExit(null);
|
||||||
|
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
// REVISIT <AP>: 20090725
|
||||||
|
// We'll need to go directly to the statement entries if
|
||||||
|
// transactions are not always associated with the customer.
|
||||||
|
// This could happen if either we remove the customer_id
|
||||||
|
// field from Transaction, or we allow multiple customers
|
||||||
|
// to be part of the same transaction (essentially making
|
||||||
|
// the Transaction.customer_id meaningless).
|
||||||
|
|
||||||
|
/* $stats = $this->StatementEntry->find */
|
||||||
|
/* ('first', array */
|
||||||
|
/* ('contain' => false, */
|
||||||
|
/* 'fields' => $this->StatementEntry->chargePaymentFields(true), */
|
||||||
|
/* 'conditions' => array('StatementEntry.customer_id' => $id), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
$find_stats = $this->StatementEntry->find
|
||||||
|
('first', array
|
||||||
|
('contain' => false,
|
||||||
|
'fields' => $this->StatementEntry->chargePaymentFields(true),
|
||||||
|
'conditions' => array('StatementEntry.customer_id' => $id),
|
||||||
|
));
|
||||||
|
$find_stats = $find_stats[0];
|
||||||
|
$this->pr(17, compact('find_stats'));
|
||||||
|
|
||||||
|
$tquery = $query;
|
||||||
|
$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||||
|
$statement_stats = $this->StatementEntry->stats(null, $tquery);
|
||||||
|
$statement_stats['balance'] = $statement_stats['Charge']['balance'];
|
||||||
|
$this->pr(17, compact('statement_stats'));
|
||||||
|
|
||||||
|
$tquery = $query;
|
||||||
|
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||||
|
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
||||||
|
$transaction_stats = $this->Transaction->stats(null, $tquery);
|
||||||
|
$transaction_stats += $transaction_stats['StatementEntry'];
|
||||||
|
$this->pr(17, compact('transaction_stats'));
|
||||||
|
|
||||||
|
$tquery = $query;
|
||||||
|
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||||
|
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
||||||
|
$ar_transaction_stats = $this->Transaction->stats(null, $tquery,
|
||||||
|
$this->Transaction->Account->accountReceivableAccountID());
|
||||||
|
$ar_transaction_stats += $ar_transaction_stats['LedgerEntry'];
|
||||||
|
$this->pr(17, compact('ar_transaction_stats'));
|
||||||
|
|
||||||
|
//$stats = $ar_transaction_stats;
|
||||||
|
$stats = $find_stats;
|
||||||
|
return $this->prReturn($stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -53,27 +53,12 @@ class DoubleEntry extends AppModel {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function addDoubleEntry($entry1, $entry2, $entry1_tender = null) {
|
function addDoubleEntry($entry1, $entry2, $entry1_tender = null) {
|
||||||
//$this->prFunctionLevel(16);
|
/* pr(array('DoubleEntry::addDoubleEntry' => */
|
||||||
$this->prEnter(compact('entry1', 'entry2', 'entry1_tender'));
|
/* compact('entry1', 'entry2', 'entry1_tender'))); */
|
||||||
|
|
||||||
$ret = array();
|
$ret = array();
|
||||||
if (!$this->verifyDoubleEntry($entry1, $entry2, $entry1_tender))
|
if (!$this->verifyDoubleEntry($entry1, $entry2, $entry1_tender))
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
return array('error' => true) + $ret;
|
||||||
|
|
||||||
// Handle the case where a double entry involves the same
|
|
||||||
// exact ledger. This would not serve any useful purpose.
|
|
||||||
// It is not, however, an error. It is semantically correct
|
|
||||||
// just not really logically correct. To make this easier,
|
|
||||||
// just ensure ledger_id is set for each entry, even though
|
|
||||||
// it would be handled later by the LedgerEntry model.
|
|
||||||
//array($entry1, $entry2) AS &$entry) {
|
|
||||||
for ($i=1; $i <= 2; ++$i) {
|
|
||||||
if (empty(${'entry'.$i}['ledger_id']))
|
|
||||||
${'entry'.$i}['ledger_id'] =
|
|
||||||
$this->DebitEntry->Account->currentLedgerID(${'entry'.$i}['account_id']);
|
|
||||||
}
|
|
||||||
if ($entry1['ledger_id'] == $entry2['ledger_id'])
|
|
||||||
return $this->prReturn(array('error' => false));
|
|
||||||
|
|
||||||
// Since this model only relates to DebitEntry and CreditEntry...
|
// Since this model only relates to DebitEntry and CreditEntry...
|
||||||
$LE = new LedgerEntry();
|
$LE = new LedgerEntry();
|
||||||
@@ -82,13 +67,13 @@ class DoubleEntry extends AppModel {
|
|||||||
$result = $LE->addLedgerEntry($entry1, $entry1_tender);
|
$result = $LE->addLedgerEntry($entry1, $entry1_tender);
|
||||||
$ret['Entry1'] = $result;
|
$ret['Entry1'] = $result;
|
||||||
if ($result['error'])
|
if ($result['error'])
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
return array('error' => true) + $ret;
|
||||||
|
|
||||||
// Add the second ledger entry to the database
|
// Add the second ledger entry to the database
|
||||||
$result = $LE->addLedgerEntry($entry2);
|
$result = $LE->addLedgerEntry($entry2);
|
||||||
$ret['Entry2'] = $result;
|
$ret['Entry2'] = $result;
|
||||||
if ($result['error'])
|
if ($result['error'])
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
return array('error' => true) + $ret;
|
||||||
|
|
||||||
// Now link them as a double entry
|
// Now link them as a double entry
|
||||||
$double_entry = array();
|
$double_entry = array();
|
||||||
@@ -97,13 +82,15 @@ class DoubleEntry extends AppModel {
|
|||||||
$double_entry['credit_entry_id'] =
|
$double_entry['credit_entry_id'] =
|
||||||
($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
|
($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
|
||||||
|
|
||||||
$ret['data'] = $double_entry;
|
/* pr(array('DoubleEntry::addDoubleEntry' => */
|
||||||
|
/* array('checkpoint' => 'Pre-Save') */
|
||||||
|
/* + compact('double_entry'))); */
|
||||||
|
|
||||||
$this->create();
|
$this->create();
|
||||||
if (!$this->save($double_entry))
|
if (!$this->save($double_entry))
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
return array('error' => true) + $ret;
|
||||||
|
|
||||||
$ret['double_entry_id'] = $this->id;
|
$ret['double_entry_id'] = $this->id;
|
||||||
return $this->prReturn($ret + array('error' => false));
|
return $ret + array('error' => false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,527 @@
|
|||||||
|
<?php
|
||||||
|
class Lease extends AppModel {
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'LeaseType',
|
||||||
|
'Unit',
|
||||||
|
'Customer',
|
||||||
|
'LateSchedule',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'StatementEntry',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: securityDeposits
|
||||||
|
* - Returns an array of security deposit entries
|
||||||
|
*/
|
||||||
|
function securityDeposits($id, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
if (!isset($query['link']['Lease']))
|
||||||
|
$query['link']['Lease'] = array();
|
||||||
|
if (!isset($query['link']['Lease']['fields']))
|
||||||
|
$query['link']['Lease']['fields'] = array();
|
||||||
|
|
||||||
|
$query['conditions'][] = array('Lease.id' => $id);
|
||||||
|
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||||
|
$this->StatementEntry->LedgerEntry->Account->securityDepositAccountID());
|
||||||
|
|
||||||
|
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
||||||
|
|
||||||
|
/* $set['summary'] = array('total' => $set['summary']['Charge']['total'], */
|
||||||
|
/* 'balance' => $set['summary']['Charge']['reconciled'], */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
return $this->prReturn($set);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: securityDepositBalance
|
||||||
|
* - Returns the balance of the lease security deposit(s)
|
||||||
|
*/
|
||||||
|
|
||||||
|
function securityDepositBalance($id, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
if (!isset($query['link']['Lease']))
|
||||||
|
$query['link']['Lease'] = array();
|
||||||
|
if (!isset($query['link']['Lease']['fields']))
|
||||||
|
$query['link']['Lease']['fields'] = array();
|
||||||
|
|
||||||
|
$query['conditions'][] = array('Lease.id' => $id);
|
||||||
|
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||||
|
$this->StatementEntry->LedgerEntry->Account->securityDepositAccountID());
|
||||||
|
|
||||||
|
$stats = $this->StatementEntry->stats(null, $query);
|
||||||
|
$balance = $stats['Charge']['reconciled'] - $stats['Payment']['reconciled'];
|
||||||
|
return $this->prReturn($balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: releaseSecurityDeposits
|
||||||
|
* - Releases all security deposits associated with this lease.
|
||||||
|
* That simply makes a payment out of them, which can be used
|
||||||
|
* to pay outstanding customer charges, or simply to become
|
||||||
|
* a customer surplus (customer credit).
|
||||||
|
*/
|
||||||
|
function releaseSecurityDeposits($id, $query = null) {
|
||||||
|
$this->prFunctionLevel(30);
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
|
||||||
|
$secdeps = $this->securityDeposits($id, $query);
|
||||||
|
$secdeps = $secdeps['entries'];
|
||||||
|
$this->pr(20, compact('secdeps'));
|
||||||
|
|
||||||
|
$this->securityDepositBalance($id, $query);
|
||||||
|
die();
|
||||||
|
|
||||||
|
// If there are no paid security deposits, then
|
||||||
|
// we can consider all security deposits released.
|
||||||
|
if (count($secdeps) == 0)
|
||||||
|
return $this->prReturn(true);
|
||||||
|
|
||||||
|
// Build a transaction
|
||||||
|
$release = array('Transaction' => array(), 'Entry' => array());
|
||||||
|
$release['Transaction']['comment'] = "Security Deposit Release";
|
||||||
|
foreach ($secdeps AS $charge) {
|
||||||
|
if ($charge['StatementEntry']['type'] !== 'CHARGE')
|
||||||
|
die("INTERNAL ERROR: SECURITY DEPOSIT IS NOT CHARGE");
|
||||||
|
|
||||||
|
// Since security deposits are being released, this also means
|
||||||
|
// we're reducing any oustanding amount on a security deposit
|
||||||
|
// since we no longer expect it to be owed.
|
||||||
|
// REVISIT <AP>: 20090730
|
||||||
|
// This is kludgy, and I really don't like it. However, this
|
||||||
|
// is not presently something that even happens at the moment,
|
||||||
|
// so this solution will have to work until we come up with
|
||||||
|
// something more robust, like flagging those charges as defunct.
|
||||||
|
if ($charge['StatementEntry']['balance'] > 0) {
|
||||||
|
$this->StatementEntry->id = $charge['StatementEntry']['id'];
|
||||||
|
$this->StatementEntry->saveField('amount', $charge['StatementEntry']['reconciled']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$release['Entry'][] =
|
||||||
|
array('amount' => $charge['StatementEntry']['reconciled'],
|
||||||
|
'account_id' => $this->StatementEntry->LedgerEntry->Account->securityDepositAccountID(),
|
||||||
|
'comment' => "Released Security Deposit",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$customer_id = $secdeps[0]['StatementEntry']['customer_id'];
|
||||||
|
$lease_id = $secdeps[0]['StatementEntry']['lease_id'];
|
||||||
|
|
||||||
|
$result = $this->StatementEntry->Transaction->addReceipt
|
||||||
|
($release, $customer_id, $lease_id);
|
||||||
|
|
||||||
|
return $this->prReturn($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: rentLastCharges
|
||||||
|
* - Returns a list of rent charges from this lease that
|
||||||
|
* do not have sequential followup charges. Under normal
|
||||||
|
* circumstances, there would only be one entry, which is
|
||||||
|
* the most recent rent charge. However, it's possible
|
||||||
|
* that there are several, indicating a problem with lease.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function rentLastCharges($id) {
|
||||||
|
$this->prEnter(compact('id'));
|
||||||
|
$rent_account_id = $this->StatementEntry->LedgerEntry->Account->rentAccountID();
|
||||||
|
$entries = $this->find
|
||||||
|
('all',
|
||||||
|
array('link' =>
|
||||||
|
array(// Models
|
||||||
|
'StatementEntry',
|
||||||
|
|
||||||
|
'SEx' =>
|
||||||
|
array('class' => 'StatementEntry',
|
||||||
|
'fields' => array(),
|
||||||
|
'conditions' => array
|
||||||
|
('SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
|
||||||
|
'SEx.lease_id = StatementEntry.lease_id',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
||||||
|
'fields' => array(),
|
||||||
|
'conditions' => array(array('Lease.id' => $id),
|
||||||
|
array('StatementEntry.type' => 'CHARGE'),
|
||||||
|
array('StatementEntry.account_id' => $rent_account_id),
|
||||||
|
array('SEx.id' => null),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->prReturn($entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: rentChargeGaps
|
||||||
|
* - Checks for gaps in rent charges
|
||||||
|
*/
|
||||||
|
|
||||||
|
function rentChargeGaps($id) {
|
||||||
|
$this->prEnter(compact('id'));
|
||||||
|
$entries = $this->rentLastCharges($id);
|
||||||
|
if ($entries && count($entries) > 1)
|
||||||
|
return $this->prReturn(true);
|
||||||
|
return $this->prReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: rentChargeThrough
|
||||||
|
* - Determines the date that rent has been charged through
|
||||||
|
* Returns one of:
|
||||||
|
* null: There are gaps in the charges
|
||||||
|
* false: There are not yet any charges
|
||||||
|
* date: The date rent has been charged through
|
||||||
|
*/
|
||||||
|
|
||||||
|
function rentChargeThrough($id) {
|
||||||
|
$this->prEnter(compact('id'));
|
||||||
|
$entries = $this->rentLastCharges($id);
|
||||||
|
if (!$entries)
|
||||||
|
return $this->prReturn(false);
|
||||||
|
if (count($entries) != 1)
|
||||||
|
return $this->prReturn(null);
|
||||||
|
return $this->prReturn($entries[0]['StatementEntry']['through_date']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: rentPaidThrough
|
||||||
|
* - Determines the date of the first unpaid rent
|
||||||
|
*/
|
||||||
|
|
||||||
|
function rentPaidThrough($id) {
|
||||||
|
$this->prEnter(compact('id'));
|
||||||
|
$rent_account_id = $this->StatementEntry->LedgerEntry->Account->rentAccountID();
|
||||||
|
|
||||||
|
// First, see if we can find any unpaid entries. Of course,
|
||||||
|
// the first unpaid entry gives us a very direct indication
|
||||||
|
// of when the customer is paid up through, which is 1 day
|
||||||
|
// prior to the effective date of that first unpaid charge.
|
||||||
|
$rent = $this->StatementEntry->reconciledSet
|
||||||
|
('CHARGE',
|
||||||
|
array('fields' =>
|
||||||
|
array('StatementEntry.*',
|
||||||
|
'DATE_SUB(StatementEntry.effective_date, INTERVAL 1 DAY) AS paid_through',
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' =>
|
||||||
|
array(array('StatementEntry.lease_id' => $id),
|
||||||
|
array('StatementEntry.account_id' => $rent_account_id)),
|
||||||
|
|
||||||
|
'order' => array('StatementEntry.effective_date'),
|
||||||
|
),
|
||||||
|
true);
|
||||||
|
$this->pr(20, $rent, "Unpaid rent");
|
||||||
|
|
||||||
|
if ($rent['entries'])
|
||||||
|
return $this->prReturn($rent['entries'][0]['StatementEntry']['paid_through']);
|
||||||
|
|
||||||
|
|
||||||
|
// If we don't have any unpaid charges (great!), then the
|
||||||
|
// customer is paid up through the last day of the last
|
||||||
|
// charge. So, search for paid charges, which already
|
||||||
|
// have the paid through date saved as part of the entry.
|
||||||
|
$rent = $this->StatementEntry->reconciledSet
|
||||||
|
('CHARGE',
|
||||||
|
array('conditions' =>
|
||||||
|
array(array('StatementEntry.lease_id' => $id),
|
||||||
|
array('StatementEntry.account_id' => $rent_account_id)),
|
||||||
|
|
||||||
|
'order' => array('StatementEntry.through_date DESC'),
|
||||||
|
),
|
||||||
|
false);
|
||||||
|
$this->pr(20, $rent, "Paid rent");
|
||||||
|
|
||||||
|
if ($rent['entries'])
|
||||||
|
return $this->prReturn($rent['entries'][0]['StatementEntry']['through_date']);
|
||||||
|
|
||||||
|
|
||||||
|
// After all that, having found that there are no unpaid
|
||||||
|
// charges, and in fact, no paid charges either, we cannot
|
||||||
|
// possibly say when the customer is paid through.
|
||||||
|
return $this->prReturn(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: moveIn
|
||||||
|
* - Moves the specified customer into the specified lease
|
||||||
|
*/
|
||||||
|
|
||||||
|
function moveIn($customer_id, $unit_id,
|
||||||
|
$deposit = null, $rent = null,
|
||||||
|
$stamp = null, $comment = null)
|
||||||
|
{
|
||||||
|
$this->prEnter(compact('customer_id', 'unit_id',
|
||||||
|
'deposit', 'rent', 'stamp', 'comment'));
|
||||||
|
|
||||||
|
$lt = $this->LeaseType->find('first',
|
||||||
|
array('conditions' =>
|
||||||
|
array('code' => 'SL')));
|
||||||
|
|
||||||
|
// Use NOW if not given a movein date
|
||||||
|
if (!isset($stamp))
|
||||||
|
$stamp = date('Y-m-d G:i:s');
|
||||||
|
|
||||||
|
if (!$comment)
|
||||||
|
$comment = null;
|
||||||
|
|
||||||
|
if (!isset($deposit) || !isset($rent)) {
|
||||||
|
$rates = $this->Unit->find
|
||||||
|
('first',
|
||||||
|
array('contain' =>
|
||||||
|
array('UnitSize' =>
|
||||||
|
array('deposit', 'rent'),
|
||||||
|
),
|
||||||
|
'fields' => array('deposit', 'rent'),
|
||||||
|
'conditions' => array('Unit.id' => $unit_id),
|
||||||
|
));
|
||||||
|
|
||||||
|
$deposit =
|
||||||
|
(isset($deposit)
|
||||||
|
? $deposit
|
||||||
|
: (isset($rates['Unit']['deposit'])
|
||||||
|
? $rates['Unit']['deposit']
|
||||||
|
: (isset($rates['UnitSize']['deposit'])
|
||||||
|
? $rates['UnitSize']['deposit']
|
||||||
|
: 0)));
|
||||||
|
|
||||||
|
$rent =
|
||||||
|
(isset($rent)
|
||||||
|
? $rent
|
||||||
|
: (isset($rates['Unit']['rent'])
|
||||||
|
? $rates['Unit']['rent']
|
||||||
|
: (isset($rates['UnitSize']['rent'])
|
||||||
|
? $rates['UnitSize']['rent']
|
||||||
|
: 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Save this new lease.
|
||||||
|
$this->create();
|
||||||
|
if (!$this->save(array('lease_type_id' => $lt['LeaseType']['id'],
|
||||||
|
'unit_id' => $unit_id,
|
||||||
|
'customer_id' => $customer_id,
|
||||||
|
'lease_date' => $stamp,
|
||||||
|
'movein_date' => $stamp,
|
||||||
|
'deposit' => $deposit,
|
||||||
|
'rent' => $rent,
|
||||||
|
'comment' => $comment), false)) {
|
||||||
|
return $this->prReturn(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the lease number to be the same as the lease ID
|
||||||
|
$this->id;
|
||||||
|
$this->saveField('number', $this->id);
|
||||||
|
|
||||||
|
// Update the unit status
|
||||||
|
$this->Unit->updateStatus($unit_id, 'OCCUPIED');
|
||||||
|
|
||||||
|
// REVISIT <AP>: 20090702
|
||||||
|
// We need to assess the security deposit charge,
|
||||||
|
// and probably rent as well. Rent, however, will
|
||||||
|
// require user parameters to indicate whether it
|
||||||
|
// was waived, pro-rated, etc.
|
||||||
|
|
||||||
|
// Return the new lease ID
|
||||||
|
return $this->prReturn($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: moveOut
|
||||||
|
* - Moves the customer out of the specified lease
|
||||||
|
*/
|
||||||
|
|
||||||
|
function moveOut($id, $status = 'VACANT',
|
||||||
|
$stamp = null, $close = false)
|
||||||
|
{
|
||||||
|
$this->prEnter(compact('id', 'status', 'stamp', 'close'));
|
||||||
|
|
||||||
|
// Use NOW if not given a moveout date
|
||||||
|
if (!isset($stamp))
|
||||||
|
$stamp = date('Y-m-d G:i:s');
|
||||||
|
|
||||||
|
// Reset the data
|
||||||
|
$this->create();
|
||||||
|
$this->id = $id;
|
||||||
|
|
||||||
|
// Set the customer move-out date
|
||||||
|
$this->data['Lease']['moveout_date'] = $stamp;
|
||||||
|
|
||||||
|
// Save it!
|
||||||
|
$this->save($this->data, false);
|
||||||
|
|
||||||
|
// Close the lease, if so requested
|
||||||
|
if ($close)
|
||||||
|
$this->close($id, $stamp);
|
||||||
|
|
||||||
|
// Finally, update the unit status
|
||||||
|
$this->recursive = -1;
|
||||||
|
$this->read();
|
||||||
|
$this->Unit->updateStatus($this->data['Lease']['unit_id'], $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: close
|
||||||
|
* - Closes the lease to further action
|
||||||
|
*/
|
||||||
|
|
||||||
|
function close($id, $stamp = null) {
|
||||||
|
$this->prEnter(compact('id', 'stamp'));
|
||||||
|
|
||||||
|
if (!$this->closeable($id))
|
||||||
|
return $this->prReturn(false);
|
||||||
|
|
||||||
|
// Reset the data
|
||||||
|
$this->create();
|
||||||
|
$this->id = $id;
|
||||||
|
|
||||||
|
// Use NOW if not given a moveout date
|
||||||
|
if (!isset($stamp))
|
||||||
|
$stamp = date('Y-m-d G:i:s');
|
||||||
|
|
||||||
|
// Set the close date
|
||||||
|
$this->data['Lease']['close_date'] = $stamp;
|
||||||
|
|
||||||
|
// Save it!
|
||||||
|
$this->save($this->data, false);
|
||||||
|
return $this->prReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: closeable
|
||||||
|
* - Indicates whether or not the lease can be closed
|
||||||
|
*/
|
||||||
|
|
||||||
|
function closeable($id) {
|
||||||
|
$this->prEnter(compact('id'));
|
||||||
|
|
||||||
|
$this->recursive = -1;
|
||||||
|
$this->read(null, $id);
|
||||||
|
|
||||||
|
// We can't close a lease that's still in use
|
||||||
|
if (!isset($this->data['Lease']['moveout_date']))
|
||||||
|
return $this->prReturn(false);
|
||||||
|
|
||||||
|
// We can't close a lease that's already closed
|
||||||
|
if (isset($this->data['Lease']['close_date']))
|
||||||
|
return $this->prReturn(false);
|
||||||
|
|
||||||
|
$deposit_balance = $this->securityDepositBalance($id);
|
||||||
|
$stats = $this->stats($id);
|
||||||
|
|
||||||
|
// A lease can only be closed if there are no outstanding
|
||||||
|
// security deposits, and if the account balance is zero.
|
||||||
|
if ($deposit_balance != 0)
|
||||||
|
return $this->prReturn(false);
|
||||||
|
|
||||||
|
// Apparently this lease meets all the criteria!
|
||||||
|
return $this->prReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addCharge
|
||||||
|
* - Adds an additional charge to the lease
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addCharge($id, $charge) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested lease.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function stats($id = null, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
if (!$id)
|
||||||
|
return $this->prReturn(null);
|
||||||
|
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
//$query['link'] = array('Lease' => $query['link']);
|
||||||
|
/* if (!isset($query['link']['StatementEntry'])) */
|
||||||
|
/* $query['link']['StatementEntry'] = array(); */
|
||||||
|
/* if (!isset($query['link']['StatementEntry']['ChargeEntry'])) */
|
||||||
|
/* $query['link']['StatementEntry']['ChargeEntry'] = array(); */
|
||||||
|
|
||||||
|
/* $query['link']['StatementEntry']['fields'] = array(); */
|
||||||
|
/* $query['link']['ChargeEntry']['fields'] = array(); */
|
||||||
|
/* $query['link']['ChargeEntry']['Account']['fields'] = array(); */
|
||||||
|
/* $query['link']['ChargeEntry']['StatementEntry']['fields'] = array(); */
|
||||||
|
/* $query['link']['ChargeEntry']['StatementEntry']['Invoice']['fields'] = array(); */
|
||||||
|
|
||||||
|
if (!isset($query['fields']))
|
||||||
|
$query['fields'] = array();
|
||||||
|
|
||||||
|
$query['fields'] = array_merge($query['fields'],
|
||||||
|
$this->StatementEntry->chargePaymentFields(true));
|
||||||
|
|
||||||
|
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
||||||
|
|
||||||
|
$query['group'] = null;
|
||||||
|
|
||||||
|
$stats = $this->StatementEntry->find('first', $query);
|
||||||
|
//$this->pr(20, compact('query', 'stats'));
|
||||||
|
|
||||||
|
// The fields are all tucked into the [0] index,
|
||||||
|
// and the rest of the array is useless (empty).
|
||||||
|
$stats = $stats[0];
|
||||||
|
|
||||||
|
// Make sure we have a non-null balance
|
||||||
|
if (!isset($stats['balance']))
|
||||||
|
$stats['balance'] = 0;
|
||||||
|
|
||||||
|
return $this->prReturn($stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -8,22 +8,8 @@ class LedgerEntry extends AppModel {
|
|||||||
);
|
);
|
||||||
|
|
||||||
var $hasOne = array(
|
var $hasOne = array(
|
||||||
'Tender' => array(
|
'Tender',
|
||||||
'dependent' => true,
|
'DoubleEntry',
|
||||||
),
|
|
||||||
'DebitDoubleEntry' => array(
|
|
||||||
'className' => 'DoubleEntry',
|
|
||||||
'foreignKey' => 'debit_entry_id',
|
|
||||||
'dependent' => true,
|
|
||||||
),
|
|
||||||
'CreditDoubleEntry' => array(
|
|
||||||
'className' => 'DoubleEntry',
|
|
||||||
'foreignKey' => 'credit_entry_id',
|
|
||||||
'dependent' => true,
|
|
||||||
),
|
|
||||||
'DoubleEntry' => array(
|
|
||||||
'foreignKey' => false,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var $hasMany = array(
|
var $hasMany = array(
|
||||||
@@ -47,6 +33,12 @@ class LedgerEntry extends AppModel {
|
|||||||
'foreignKey' => 'debit_entry_id',
|
'foreignKey' => 'debit_entry_id',
|
||||||
'associationForeignKey' => 'credit_entry_id',
|
'associationForeignKey' => 'credit_entry_id',
|
||||||
),
|
),
|
||||||
|
|
||||||
|
//
|
||||||
|
'StatementEntry' => array(
|
||||||
|
'joinTable' => 'statement_fractions',
|
||||||
|
'fields' => 'StatementFraction.amount',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@@ -127,20 +119,24 @@ class LedgerEntry extends AppModel {
|
|||||||
* - Inserts new Ledger Entry into the database
|
* - Inserts new Ledger Entry into the database
|
||||||
*/
|
*/
|
||||||
function addLedgerEntry($entry, $tender = null) {
|
function addLedgerEntry($entry, $tender = null) {
|
||||||
//$this->prFunctionLevel(16);
|
/* pr(array('LedgerEntry::addLedgerEntry' => */
|
||||||
$this->prEnter(compact('entry', 'tender'));
|
/* compact('entry', 'tender'))); */
|
||||||
|
|
||||||
$ret = array('data' => $entry);
|
$ret = array();
|
||||||
if (!$this->verifyLedgerEntry($entry, $tender))
|
if (!$this->verifyLedgerEntry($entry, $tender))
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
return array('error' => true) + $ret;
|
||||||
|
|
||||||
if (empty($entry['ledger_id']))
|
if (empty($entry['ledger_id']))
|
||||||
$entry['ledger_id'] =
|
$entry['ledger_id'] =
|
||||||
$this->Account->currentLedgerID($entry['account_id']);
|
$this->Account->currentLedgerID($entry['account_id']);
|
||||||
|
|
||||||
|
/* pr(array('LedgerEntry::addLedgerEntry' => */
|
||||||
|
/* array('checkpoint' => 'Pre-Save') */
|
||||||
|
/* + compact('entry'))); */
|
||||||
|
|
||||||
$this->create();
|
$this->create();
|
||||||
if (!$this->save($entry))
|
if (!$this->save($entry))
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
return array('error' => true) + $ret;
|
||||||
|
|
||||||
$ret['ledger_entry_id'] = $this->id;
|
$ret['ledger_entry_id'] = $this->id;
|
||||||
|
|
||||||
@@ -150,10 +146,10 @@ class LedgerEntry extends AppModel {
|
|||||||
$result = $this->Tender->addTender($tender);
|
$result = $this->Tender->addTender($tender);
|
||||||
$ret['Tender'] = $result;
|
$ret['Tender'] = $result;
|
||||||
if ($result['error'])
|
if ($result['error'])
|
||||||
return $this->prReturn(array('error' => true) + $ret);
|
return array('error' => true) + $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->prReturn($ret + array('error' => false));
|
return $ret + array('error' => false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -165,13 +161,55 @@ class LedgerEntry extends AppModel {
|
|||||||
*/
|
*/
|
||||||
function stats($id = null, $query = null, $set = null) {
|
function stats($id = null, $query = null, $set = null) {
|
||||||
$this->queryInit($query);
|
$this->queryInit($query);
|
||||||
|
unset($query['group']);
|
||||||
|
|
||||||
// REVISIT <AP>: 20090816
|
if (!isset($query['link']['DoubleEntry']))
|
||||||
// This function appeared to be dramatically broken,
|
$query['link']['DoubleEntry'] = array();
|
||||||
// a throwback to an earlier time. I deleted its
|
/* if (!isset($query['link']['DoubleEntry']['fields'])) */
|
||||||
// contents and added this error to ensure it does
|
/* $query['link']['DoubleEntry']['fields'] = array(); */
|
||||||
// not get used.
|
|
||||||
$this->INTERNAL_ERROR('This function should not be used');
|
if (isset($id))
|
||||||
|
$query['conditions'][] = array('Entry.id' => $id);
|
||||||
|
|
||||||
|
if (isset($set))
|
||||||
|
$set = strtoupper($set);
|
||||||
|
|
||||||
|
//pr(array('stats()', compact('id', 'query', 'set')));
|
||||||
|
|
||||||
|
$rtypes = array('charge', 'payment',
|
||||||
|
// 'debit', 'credit',
|
||||||
|
);
|
||||||
|
|
||||||
|
$stats = array();
|
||||||
|
foreach($rtypes AS $rtype) {
|
||||||
|
$Rtype = ucfirst($rtype);
|
||||||
|
|
||||||
|
if (($rtype == 'charge' && (!isset($set) || $set == 'PAYMENT')) ||
|
||||||
|
($rtype == 'payment' && (!isset($set) || $set == 'CHARGE'))
|
||||||
|
/* ($rtype == 'debit' && (!isset($set) || $set == 'CREDIT')) || */
|
||||||
|
/* ($rtype == 'credit' && (!isset($set) || $set == 'DEBIT')) */
|
||||||
|
) {
|
||||||
|
|
||||||
|
$rquery = $query;
|
||||||
|
$rquery['link'][$Rtype] =
|
||||||
|
array('fields' => array("SUM(COALESCE(Applied{$Rtype}.amount,0)) AS reconciled"));
|
||||||
|
|
||||||
|
$rquery['fields'] = array();
|
||||||
|
//$rquery['fields'][] = "SUM(DoubleEntry.amount) AS total";
|
||||||
|
$rquery['fields'][] = "SUM(DoubleEntry.amount) - SUM(COALESCE(Applied{$Rtype}.amount,0)) AS balance";
|
||||||
|
$rquery['conditions'][] = array("Applied{$Rtype}.id !=" => null);
|
||||||
|
|
||||||
|
$result = $this->find('first', $rquery);
|
||||||
|
//pr(compact('Rtype', 'rquery', 'result'));
|
||||||
|
|
||||||
|
$sumfld = $Rtype;
|
||||||
|
$stats[$sumfld] = $result[0];
|
||||||
|
/* if (!isset($stats[$sumfld]['applied'])) */
|
||||||
|
/* $stats[$sumfld]['applied'] = 0; */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
class MapsUnit extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'MapsUnit';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'map_id' => array('numeric'),
|
||||||
|
'unit_id' => array('numeric'),
|
||||||
|
'pt_top' => array('numeric'),
|
||||||
|
'pt_left' => array('numeric'),
|
||||||
|
'transpose' => array('boolean')
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
class Site extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Site';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'name' => array('notempty')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'SiteArea',
|
||||||
|
'SiteOption',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,605 @@
|
|||||||
|
<?php
|
||||||
|
class StatementEntry extends AppModel {
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'Transaction',
|
||||||
|
'Customer',
|
||||||
|
'Lease',
|
||||||
|
|
||||||
|
// The charge to which this payment applies (if it is one)
|
||||||
|
'ChargeEntry' => array(
|
||||||
|
'className' => 'StatementEntry',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
// The payments that apply to this charge (if it is one)
|
||||||
|
'PaymentEntry' => array(
|
||||||
|
'className' => 'StatementEntry',
|
||||||
|
'foreignKey' => 'charge_entry_id',
|
||||||
|
),
|
||||||
|
|
||||||
|
'StatementFraction',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasAndBelongsToMany = array(
|
||||||
|
'LedgerEntry' => array(
|
||||||
|
'joinTable' => 'statement_fractions',
|
||||||
|
//'fields' => 'StatementFraction.amount',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
//var $default_log_level = 30;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: chargePaymentFields
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
function chargePaymentFields($sum = false, $entry_name = 'StatementEntry') {
|
||||||
|
$fields = array
|
||||||
|
(
|
||||||
|
($sum ? 'SUM(' : '') .
|
||||||
|
"IF({$entry_name}.type = 'CHARGE'," .
|
||||||
|
" {$entry_name}.amount, NULL)" .
|
||||||
|
($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''),
|
||||||
|
|
||||||
|
($sum ? 'SUM(' : '') .
|
||||||
|
"IF({$entry_name}.type = 'PAYMENT' OR {$entry_name}.type = 'SURPLUS'," .
|
||||||
|
" {$entry_name}.amount, NULL)" .
|
||||||
|
($sum ? ')' : '') . ' AS payment' . ($sum ? 's' : ''),
|
||||||
|
|
||||||
|
($sum ? 'SUM(' : '') .
|
||||||
|
"IF({$entry_name}.type = 'CHARGE', 1," .
|
||||||
|
" IF({$entry_name}.type = 'PAYMENT' OR {$entry_name}.type = 'SURPLUS', -1, 0))" .
|
||||||
|
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
|
||||||
|
($sum ? ')' : '') . ' AS balance',
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($sum)
|
||||||
|
$fields[] = "COUNT({$entry_name}.id) AS entries";
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: verifyStatementEntry
|
||||||
|
* - Verifies consistenty of new statement entry data
|
||||||
|
* (not in a pre-existing statement entry)
|
||||||
|
*/
|
||||||
|
function verifyStatementEntry($entry) {
|
||||||
|
$this->prFunctionLevel(30);
|
||||||
|
$this->prEnter(compact('entry'));
|
||||||
|
|
||||||
|
if (empty($entry['type']) ||
|
||||||
|
//empty($entry['effective_date']) ||
|
||||||
|
empty($entry['amount'])
|
||||||
|
) {
|
||||||
|
return $this->prReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addStatementEntry
|
||||||
|
* - Inserts new Statement Entry into the database
|
||||||
|
*/
|
||||||
|
function addStatementEntry($entry) {
|
||||||
|
$this->prEnter(compact('entry'));
|
||||||
|
|
||||||
|
$ret = array();
|
||||||
|
if (!$this->verifyStatementEntry($entry))
|
||||||
|
return array('error' => true, 'verify_data' => $entry) + $ret;
|
||||||
|
|
||||||
|
$this->pr(20, array('checkpoint' => 'Pre-Save')
|
||||||
|
+ compact('entry'));
|
||||||
|
|
||||||
|
$this->create();
|
||||||
|
if (!$this->save($entry))
|
||||||
|
return array('error' => true, 'save_data' => $entry) + $ret;
|
||||||
|
|
||||||
|
foreach ($entry['Fraction'] AS $fraction) {
|
||||||
|
$fraction['statement_entry_id'] = $this->id;
|
||||||
|
$this->StatementFraction->id = null;
|
||||||
|
$this->StatementFraction->save($fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret['statement_entry_id'] = $this->id;
|
||||||
|
return $this->prReturn($ret + array('error' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: reverse
|
||||||
|
* - Reverses the charges
|
||||||
|
*
|
||||||
|
* SAMPLE MOVE IN w/ PRE PAYMENT
|
||||||
|
* DEPOSIT RENT A/R RECEIPT CHECK PETTY BANK
|
||||||
|
* ------- ------- ------- ------- ------- ------- -------
|
||||||
|
* |25 | 25| | | | |
|
||||||
|
* | |20 20| | | | |
|
||||||
|
* | |20 20| | | | |
|
||||||
|
* | |20 20| | | | |
|
||||||
|
* | | |25 25| | | |
|
||||||
|
* | | |20 20| | | |
|
||||||
|
* | | |20 20| | | |
|
||||||
|
* | | |20 20| | | |
|
||||||
|
* | | | |85 85| | |
|
||||||
|
* | | | | |85 | 85|
|
||||||
|
|
||||||
|
* MOVE OUT and REFUND FINAL MONTH
|
||||||
|
* DEPOSIT RENT C/P RECEIPT CHECK PETTY BANK
|
||||||
|
* ------- ------- ------- ------- ------- ------- -------
|
||||||
|
* 25| | |25 | | | | t20 e20a
|
||||||
|
* | 20| |20 | | | | t20 e20b
|
||||||
|
|
||||||
|
* -ONE REFUND CHECK-
|
||||||
|
* | | 25| |25 | | | t30 e30a
|
||||||
|
* | | 20| |20 | | | t30 e30b
|
||||||
|
* | | | 45| | | |45 t40 e40
|
||||||
|
* -OR MULTIPLE-
|
||||||
|
* | | 15| |15 | | | t50a e50a
|
||||||
|
* | | | 15| | |15 | t60a e60a
|
||||||
|
* | | 30| |30 | | | t50b e50b
|
||||||
|
* | | | 30| | | |30 t60b e60b
|
||||||
|
* | | | | | | |
|
||||||
|
|
||||||
|
|
||||||
|
OPTION 1
|
||||||
|
* |-25 | -25| | | | |
|
||||||
|
* | |-20 -20| | | | |
|
||||||
|
* | | |-25 -25| | | |
|
||||||
|
* | | |-20 -20| | | |
|
||||||
|
|
||||||
|
OPTION 2
|
||||||
|
* |-25 | | -25| | | |
|
||||||
|
* | |-20 | -20| | | |
|
||||||
|
* | | | |-15 | -15| |
|
||||||
|
* | | | |-30 | | -30|
|
||||||
|
* | | | | | | |
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function reverse($ledger_entries, $stamp = null) {
|
||||||
|
$this->prEnter(compact('ledger_entries', 'stamp'));
|
||||||
|
|
||||||
|
// If the user only wants to reverse one ID, we'll allow it
|
||||||
|
if (!is_array($ledger_entries))
|
||||||
|
$ledger_entries = $this->find
|
||||||
|
('all', array
|
||||||
|
('contain' => false,
|
||||||
|
'conditions' => array('Entry.id' => $ledger_entries)));
|
||||||
|
|
||||||
|
$A = new Account();
|
||||||
|
|
||||||
|
$ar_account_id = $A->accountReceivableAccountID();
|
||||||
|
$receipt_account_id = $A->receiptAccountID();
|
||||||
|
|
||||||
|
$transaction_id = null;
|
||||||
|
foreach ($ledger_entries AS $entry) {
|
||||||
|
$entry = $entry['Entry'];
|
||||||
|
$amount = -1*$entry['amount'];
|
||||||
|
|
||||||
|
if (isset($entry['credit_account_id']))
|
||||||
|
$refund_account_id = $entry['credit_account_id'];
|
||||||
|
elseif (isset($entry['CreditLedger']['Account']['id']))
|
||||||
|
$refund_account_id = $entry['CreditLedger']['Account']['id'];
|
||||||
|
elseif (isset($entry['credit_ledger_id']))
|
||||||
|
$refund_account_id = $this->Ledger->accountID($entry['credit_ledger_id']);
|
||||||
|
else
|
||||||
|
return $this->prReturn(null);
|
||||||
|
|
||||||
|
// post new refund in the income account
|
||||||
|
$ids = $A->postEntry
|
||||||
|
(array('transaction_id' => $transaction_id),
|
||||||
|
null,
|
||||||
|
array('debit_ledger_id' => $A->currentLedgerID($ar_account_id),
|
||||||
|
'credit_ledger_id' => $A->currentLedgerID($refund_account_id),
|
||||||
|
'effective_date' => $entry['effective_date'],
|
||||||
|
'through_date' => $entry['through_date'],
|
||||||
|
'amount' => $amount,
|
||||||
|
'lease_id' => $entry['lease_id'],
|
||||||
|
'customer_id' => $entry['customer_id'],
|
||||||
|
'comment' => "Refund; Entry #{$entry['id']}",
|
||||||
|
),
|
||||||
|
array('debit' => array
|
||||||
|
(array('Entry' =>
|
||||||
|
array('id' => $entry['id'],
|
||||||
|
'amount' => $amount))),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($ids['error'])
|
||||||
|
return $this->prReturn(null);
|
||||||
|
$transaction_id = $ids['transaction_id'];
|
||||||
|
|
||||||
|
$this->pr(15, compact('ids', 'amount', 'refund_account_id', 'ar_account_id'),
|
||||||
|
'Posted Refund Ledger Entry');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: reconciledSet
|
||||||
|
* - Returns the set of entries satisfying the given conditions,
|
||||||
|
* along with any entries that they reconcile
|
||||||
|
*/
|
||||||
|
function reconciledSetQuery($set, $query) {
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
if ($set == 'CHARGE' || $set == 'PAYMENT')
|
||||||
|
$query['conditions'][] = array('StatementEntry.type' => $set);
|
||||||
|
else
|
||||||
|
die("INVALID RECONCILE SET");
|
||||||
|
|
||||||
|
if ($set == 'CHARGE')
|
||||||
|
$query['link']['PaymentEntry'] = array('fields' => array("SUM(PaymentEntry.amount) AS reconciled"));
|
||||||
|
if ($set == 'PAYMENT')
|
||||||
|
$query['link']['ChargeEntry'] = array('fields' => array("SUM(ChargeEntry.amount) AS reconciled"));
|
||||||
|
|
||||||
|
$query['group'] = 'StatementEntry.id';
|
||||||
|
|
||||||
|
// REVISIT: TESTING
|
||||||
|
//$query['link']['PaymentEntry'] = array('fields' => array("(`PaymentEntry.amount`+0) AS reconciled"));
|
||||||
|
//$query['group'] = null;
|
||||||
|
// END REVISIT
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reconciledSet($set, $query = null, $unrec = false, $if_rec_include_partial = false) {
|
||||||
|
//$this->prFunctionLevel(16);
|
||||||
|
$this->prEnter(compact('set', 'query', 'unrec', 'if_rec_include_partial'));
|
||||||
|
$lquery = $this->reconciledSetQuery($set, $query);
|
||||||
|
$result = $this->find('all', $lquery);
|
||||||
|
|
||||||
|
$this->pr(20, compact('lquery', 'result'));
|
||||||
|
|
||||||
|
$resultset = array();
|
||||||
|
foreach ($result AS $i => $entry) {
|
||||||
|
$this->pr(25, compact('entry'));
|
||||||
|
if (!empty($entry[0]))
|
||||||
|
$entry['StatementEntry'] = $entry[0] + $entry['StatementEntry'];
|
||||||
|
unset($entry[0]);
|
||||||
|
|
||||||
|
$entry['StatementEntry']['balance'] =
|
||||||
|
$entry['StatementEntry']['amount'] - $entry['StatementEntry']['reconciled'];
|
||||||
|
|
||||||
|
// Since HAVING isn't a builtin feature of CakePHP,
|
||||||
|
// we'll have to post-process to get the desired entries
|
||||||
|
|
||||||
|
if ($entry['StatementEntry']['balance'] == 0)
|
||||||
|
$reconciled = true;
|
||||||
|
elseif ($entry['StatementEntry']['reconciled'] == 0)
|
||||||
|
$reconciled = false;
|
||||||
|
else // Partial payment; depends on unrec
|
||||||
|
$reconciled = (!$unrec && $if_rec_include_partial);
|
||||||
|
|
||||||
|
// Add to the set, if it's been requested
|
||||||
|
if ($reconciled == !$unrec)
|
||||||
|
$resultset[] = $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn(array('entries' => $resultset,
|
||||||
|
'summary' => $this->stats(null, $query)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: reconciledEntries
|
||||||
|
* - Returns a list of entries that reconcile against the given entry.
|
||||||
|
* (such as payments towards a charge).
|
||||||
|
*/
|
||||||
|
function reconciledEntriesQuery($id, $query = null) {
|
||||||
|
$this->queryInit($query, false);
|
||||||
|
|
||||||
|
$this->id = $id;
|
||||||
|
$this->recursive = -1;
|
||||||
|
$this->read();
|
||||||
|
|
||||||
|
$query['conditions'][] = array('StatementEntry.id' => $id);
|
||||||
|
|
||||||
|
if ($this->data['StatementEntry']['type'] == 'CHARGE')
|
||||||
|
$query['link']['PaymentEntry'] = array();
|
||||||
|
if ($this->data['StatementEntry']['type'] == 'PAYMENT')
|
||||||
|
$query['link']['ChargeEntry'] = array();
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reconciledEntries($id, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
$lquery = $this->reconciledEntriesQuery($id, $query);
|
||||||
|
|
||||||
|
$result = $this->find('all', $lquery);
|
||||||
|
foreach (array_keys($result) AS $i)
|
||||||
|
unset($result[$i]['StatementEntry']);
|
||||||
|
|
||||||
|
return $this->prReturn(array('entries' => $result));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: assignCredits
|
||||||
|
* - Assigns all credits to existing charges
|
||||||
|
*
|
||||||
|
* REVISIT <AP>: 20090726
|
||||||
|
* This algorithm shouldn't be hardcoded. We need to allow
|
||||||
|
* the user to specify how payments should be applied.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function assignCredits($query = null, $receipt_id = null) {
|
||||||
|
$this->prFunctionLevel(25);
|
||||||
|
$this->prEnter( compact('query', 'receipt_id'));
|
||||||
|
$this->queryInit($query);
|
||||||
|
|
||||||
|
$ret = array();
|
||||||
|
|
||||||
|
// First, find all known credits
|
||||||
|
$lquery = $query;
|
||||||
|
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
|
||||||
|
$lquery['order'][] = 'StatementEntry.effective_date ASC';
|
||||||
|
$credits = $this->find('all', $lquery);
|
||||||
|
$this->pr(18, compact('credits'),
|
||||||
|
"Credits Established");
|
||||||
|
|
||||||
|
// Next, establish credit from the newly added receipt
|
||||||
|
$receipt_credit = null;
|
||||||
|
if (!empty($receipt_id)) {
|
||||||
|
$lquery = array
|
||||||
|
('contain' => array
|
||||||
|
('LedgerEntry' =>
|
||||||
|
array('conditions' =>
|
||||||
|
//array(LedgerEntry.'crdr'=>'DEBIT'),
|
||||||
|
array('LedgerEntry.account_id !=' =>
|
||||||
|
$this->LedgerEntry->Account->accountReceivableAccountID()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->Transaction->id = $receipt_id;
|
||||||
|
$receipt_credit = $this->Transaction->find('first', $lquery);
|
||||||
|
if (!$receipt_credit)
|
||||||
|
die("INTERNAL ERROR: UNABLE TO LOCATE RECEIPT");
|
||||||
|
|
||||||
|
$receipt_credit['balance'] = $receipt_credit['Transaction']['amount'];
|
||||||
|
|
||||||
|
$this->pr(18, compact('receipt_credit'),
|
||||||
|
"Receipt Credit Added");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now find all unpaid charges
|
||||||
|
$lquery = $query;
|
||||||
|
$lquery['order'] = 'StatementEntry.effective_date ASC';
|
||||||
|
$charges = $this->reconciledSet('CHARGE', $lquery, true);
|
||||||
|
$this->pr(18, compact('charges'),
|
||||||
|
"Outstanding Charges Determined");
|
||||||
|
|
||||||
|
// Initialize our list of used credits
|
||||||
|
$used_credits = array();
|
||||||
|
|
||||||
|
// Work through all unpaid charges, applying payments as we go
|
||||||
|
foreach ($charges['entries'] AS $charge) {
|
||||||
|
|
||||||
|
$this->pr(20, compact('charge'),
|
||||||
|
'Process Charge');
|
||||||
|
|
||||||
|
// Check that we have available credits.
|
||||||
|
// Technically, this isn't necessary, since the loop
|
||||||
|
// will handle everything just fine. However, this
|
||||||
|
// just saves extra processing if/when there is no
|
||||||
|
// means to resolve a charge anyway.
|
||||||
|
if (count($credits) == 0 && empty($receipt_credit['balance'])) {
|
||||||
|
$this->pr(15, 'No more available credits');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$charge['balance'] = $charge['StatementEntry']['balance'];
|
||||||
|
while ($charge['balance'] > 0 &&
|
||||||
|
(count($credits) || !empty($receipt_credit['balance']))) {
|
||||||
|
|
||||||
|
$this->pr(20, compact('charge'),
|
||||||
|
'Attempt Charge Reconciliation');
|
||||||
|
|
||||||
|
// Use explicit credits before using implicit credits
|
||||||
|
// (Not sure it matters though).
|
||||||
|
if (count($credits)) {
|
||||||
|
// Peel off the first credit available
|
||||||
|
$credit =& $credits[0];
|
||||||
|
$payment_date = $credit['StatementEntry']['effective_date'];
|
||||||
|
$payment_transaction_id = $credit['StatementEntry']['transaction_id'];
|
||||||
|
$payment_account_id = $credit['StatementEntry']['account_id'];
|
||||||
|
|
||||||
|
if (!isset($credit['balance']))
|
||||||
|
$credit['balance'] = $credit['StatementEntry']['amount'];
|
||||||
|
}
|
||||||
|
elseif (!empty($receipt_credit['balance'])) {
|
||||||
|
// Use our only receipt credit
|
||||||
|
$credit =& $receipt_credit;
|
||||||
|
$payment_date = $credit['Transaction']['stamp'];
|
||||||
|
$payment_transaction_id = $credit['Transaction']['id'];
|
||||||
|
$payment_account_id = $credit['LedgerEntry']['account_id'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
die("HOW DID WE GET HERE WITH NO SURPLUS?");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the payment amount to the maximum amount
|
||||||
|
// possible without exceeding the charge or credit balance
|
||||||
|
$payment_amount = min($charge['balance'], $credit['balance']);
|
||||||
|
if (!isset($credit['applied']))
|
||||||
|
$credit['applied'] = 0;
|
||||||
|
|
||||||
|
$credit['applied'] += $payment_amount;
|
||||||
|
$credit['balance'] -= $payment_amount;
|
||||||
|
|
||||||
|
$this->pr(20, compact('credit'),
|
||||||
|
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
|
||||||
|
(count($credits) ? ' Credit' : ' Receipt'));
|
||||||
|
|
||||||
|
if ($credit['balance'] < 0)
|
||||||
|
die("HOW DID WE END UP WITH NEGATIVE SURPLUS BALANCE?");
|
||||||
|
|
||||||
|
// If we've exhausted the credit, get it out of the
|
||||||
|
// available credit pool (but keep track of it for later).
|
||||||
|
if ($credit['balance'] <= 0 && count($credits))
|
||||||
|
$used_credits[] = array_shift($credits);
|
||||||
|
|
||||||
|
// Add a payment that uses the available credit to pay the charge
|
||||||
|
$payment = array('type' => 'PAYMENT',
|
||||||
|
'account_id' => $payment_account_id,
|
||||||
|
'amount' => $payment_amount,
|
||||||
|
'effective_date' => $payment_date,
|
||||||
|
'transaction_id' => $payment_transaction_id,
|
||||||
|
'customer_id' => $charge['StatementEntry']['customer_id'],
|
||||||
|
'lease_id' => $charge['StatementEntry']['lease_id'],
|
||||||
|
'charge_entry_id' => $charge['StatementEntry']['id'],
|
||||||
|
'comment' => null,
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->pr(20, compact('payment'),
|
||||||
|
'New Payment Entry');
|
||||||
|
|
||||||
|
$result = $this->addStatementEntry($payment);
|
||||||
|
$ret['Payment'][] = $result;
|
||||||
|
if ($result['error'])
|
||||||
|
$ret['error'] = true;
|
||||||
|
|
||||||
|
// Adjust the charge balance to reflect the new payment
|
||||||
|
$charge['balance'] -= $payment_amount;
|
||||||
|
if ($charge['balance'] < 0)
|
||||||
|
die("HOW DID WE GET A NEGATIVE CHARGE AMOUNT?");
|
||||||
|
|
||||||
|
if ($charge['balance'] <= 0)
|
||||||
|
$this->pr(20, 'Fully Paid Charge');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partially used credits must be added to the used list
|
||||||
|
if (isset($credits[0]['applied']))
|
||||||
|
$used_credits[] = array_shift($credits);
|
||||||
|
|
||||||
|
$this->pr(18, compact('credits', 'used_credits', 'receipt_credit'),
|
||||||
|
'Payments added');
|
||||||
|
|
||||||
|
// Clean up any explicit credits that have been used
|
||||||
|
foreach ($used_credits AS $credit) {
|
||||||
|
if ($credit['balance'] > 0) {
|
||||||
|
$this->pr(20, compact('credit'),
|
||||||
|
'Update Credit Entry');
|
||||||
|
|
||||||
|
$this->id = $credit['StatementEntry']['id'];
|
||||||
|
$this->saveField('amount', $credit['balance']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->pr(20, compact('credit'),
|
||||||
|
'Delete Exhausted Credit Entry');
|
||||||
|
|
||||||
|
$this->del($credit['StatementEntry']['id'], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert non-exhausted receipt credit to an explicit one
|
||||||
|
if (!empty($receipt_credit['balance'])) {
|
||||||
|
$credit =& $receipt_credit;
|
||||||
|
|
||||||
|
$this->pr(18, compact('credit'),
|
||||||
|
'Create Explicit Credit');
|
||||||
|
|
||||||
|
$result = $this->addStatementEntry
|
||||||
|
(array('type' => 'SURPLUS',
|
||||||
|
'account_id' => $credit['LedgerEntry']['account_id'],
|
||||||
|
'amount' => $credit['balance'],
|
||||||
|
'effective_date' => $credit['Transaction']['stamp'],
|
||||||
|
'transaction_id' => $credit['Transaction']['id'],
|
||||||
|
'customer_id' => $credit['Customer']['id'],
|
||||||
|
));
|
||||||
|
$ret['Credit'] = $result;
|
||||||
|
if ($result['error'])
|
||||||
|
$ret['error'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn($ret + array('error' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested statement entry
|
||||||
|
*/
|
||||||
|
function stats($id = null, $query = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
|
||||||
|
$this->queryInit($query);
|
||||||
|
unset($query['group']);
|
||||||
|
|
||||||
|
$stats = array();
|
||||||
|
if (isset($id))
|
||||||
|
$query['conditions'][] = array('StatementEntry.id' => $id);
|
||||||
|
|
||||||
|
$rquery = $query;
|
||||||
|
unset($rquery['link']['ChargeEntry']);
|
||||||
|
$rquery['link']['PaymentEntry'] = array('fields' => array());
|
||||||
|
|
||||||
|
$rquery['fields'] = array();
|
||||||
|
$rquery['fields'][] = "StatementEntry.amount";
|
||||||
|
$rquery['fields'][] = "SUM(PaymentEntry.amount) AS reconciled";
|
||||||
|
|
||||||
|
$rquery['conditions'][] = array('StatementEntry.type' => 'CHARGE');
|
||||||
|
$rquery['group'] = 'StatementEntry.id';
|
||||||
|
|
||||||
|
$result = $this->find('all', $rquery);
|
||||||
|
$stats['Charge'] = array('total' => 0, 'reconciled' => 0);
|
||||||
|
foreach($result AS $charge) {
|
||||||
|
$stats['Charge']['total'] += $charge['StatementEntry']['amount'];
|
||||||
|
$stats['Charge']['reconciled'] += $charge[0]['reconciled'];
|
||||||
|
}
|
||||||
|
$stats['Charge']['balance'] =
|
||||||
|
$stats['Charge']['total'] - $stats['Charge']['reconciled'];
|
||||||
|
|
||||||
|
$this->pr(17, compact('query', 'result'),
|
||||||
|
'Charges');
|
||||||
|
|
||||||
|
$rquery = $query;
|
||||||
|
unset($rquery['link']['PaymentEntry']);
|
||||||
|
$rquery['link']['ChargeEntry'] = array('fields' => array());
|
||||||
|
|
||||||
|
$rquery['fields'] = array();
|
||||||
|
$rquery['fields'][] = "SUM(StatementEntry.amount) AS total";
|
||||||
|
$rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, 0, StatementEntry.amount)) AS reconciled";
|
||||||
|
$rquery['fields'][] = "SUM(IF(ChargeEntry.id IS NULL, StatementEntry.amount, 0)) AS balance";
|
||||||
|
|
||||||
|
$rquery['conditions'][] = array('StatementEntry.type' => 'PAYMENT');
|
||||||
|
$result = $this->find('first', $rquery);
|
||||||
|
if (!isset($result[0]['balance']))
|
||||||
|
$result[0]['balance'] = 0;
|
||||||
|
$stats['Payment'] = $result[0];
|
||||||
|
|
||||||
|
$this->pr(17, compact('rquery', 'result'),
|
||||||
|
'Payments');
|
||||||
|
|
||||||
|
return $this->prReturn($stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
class StatementFraction extends AppModel {
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'StatementEntry',
|
||||||
|
'LedgerEntry',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<?php
|
||||||
|
class Tender extends AppModel {
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'TenderType',
|
||||||
|
'Customer',
|
||||||
|
'LedgerEntry',
|
||||||
|
'DepositTransaction' => array(
|
||||||
|
'className' => 'Transaction',
|
||||||
|
),
|
||||||
|
'NsfTransaction' => array(
|
||||||
|
'className' => 'Transaction',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: verifyTender
|
||||||
|
* - Verifies consistenty of new tender data
|
||||||
|
* (not in a pre-existing tender)
|
||||||
|
*/
|
||||||
|
function verifyTender($tender) {
|
||||||
|
$this->prFunctionLevel(10);
|
||||||
|
$this->prEnter(compact('tender'));
|
||||||
|
|
||||||
|
if (empty($tender['tender_type_id'])) {
|
||||||
|
return $this->prReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addTender
|
||||||
|
* - Inserts new Tender into the database
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addTender($tender) {
|
||||||
|
$this->prEnter(compact('tender'));
|
||||||
|
|
||||||
|
$ret = array();
|
||||||
|
if (!$this->verifyTender($tender))
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
// Come up with a (not necessarily unique) name for the tender.
|
||||||
|
// For checks & money orders, this will be based on the check
|
||||||
|
// number. For other types of tender, we'll just use the
|
||||||
|
// generic name of the monetary account.
|
||||||
|
// REVISIT <AP>: 20090723
|
||||||
|
// I would like to have cash named "Cash #1234", where
|
||||||
|
// the number would correspond to either the Tender ID
|
||||||
|
// or the LedgerEntry ID.
|
||||||
|
if (empty($tender['name']) && !empty($tender['account_id'])) {
|
||||||
|
$tender['name'] = $this->LedgerEntry->Account->name($tender['account_id']);
|
||||||
|
if ($tender['account_id'] == $this->LedgerEntry->Account->checkAccountID() ||
|
||||||
|
$tender['account_id'] == $this->LedgerEntry->Account->moneyOrderAccountID()) {
|
||||||
|
$tender['name'] .= ' #' . $tender['data1'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->pr(20, array('Tender' => $tender),
|
||||||
|
'Pre-Save');
|
||||||
|
|
||||||
|
$this->create();
|
||||||
|
if (!$this->save($tender))
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
$ret['tender_id'] = $this->id;
|
||||||
|
return $this->prReturn($ret + array('error' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: nsf
|
||||||
|
* - Flags the ledger entry as having insufficient funds
|
||||||
|
*
|
||||||
|
* Steps:
|
||||||
|
* - Get information from Check (C1); for amount $A
|
||||||
|
* - Find Bank Deposit matching to Tender
|
||||||
|
* - New Transaction (T1)
|
||||||
|
* - New Bank Deposit (D1)
|
||||||
|
* - New Tender (N1); NSF; D1,
|
||||||
|
* - Add new LedgerEntry (L1a); T1; debit:bank; -$A
|
||||||
|
* - Add new LedgerEntry (L1b); T1; credit:NSF; -$A
|
||||||
|
* - Add new LedgerEntry (L2a); T1; debit:NSF; -$A; N1
|
||||||
|
* - Add new LedgerEntry (L2b); T1; credit:A/R; -$A
|
||||||
|
* - For Tx associated with LE associated with C1:
|
||||||
|
* - For each Payment SE of Tx:
|
||||||
|
* - Add new StatementEntry (S1n); T1; PAYMENT; -1*S1n.amount
|
||||||
|
* - New Transaction (T2) (?????)
|
||||||
|
* - Add new StatementEntry (S2); T2; CHARGE; NSF; $35
|
||||||
|
* - Add new LedgerEntry (L3a); T2; credit:NSF-Fee; $35
|
||||||
|
* - Add new LedgerEntry (L3b); T2; debit:A/R; $35
|
||||||
|
* - Set C1.nsf_tx = T1
|
||||||
|
* - Re-Reconcile (customer may have running credit)
|
||||||
|
*/
|
||||||
|
|
||||||
|
function nsf($id, $stamp = null) {
|
||||||
|
$this->prFunctionLevel(30);
|
||||||
|
$this->prEnter(compact('id'));
|
||||||
|
|
||||||
|
// Get information about this NSF item.
|
||||||
|
$this->id = $id;
|
||||||
|
$tender = $this->find
|
||||||
|
('first', array
|
||||||
|
('contain' =>
|
||||||
|
array('LedgerEntry',
|
||||||
|
'DepositTransaction',
|
||||||
|
'NsfTransaction'),
|
||||||
|
));
|
||||||
|
$this->pr(20, compact('tender'));
|
||||||
|
|
||||||
|
if (!empty($tender['NsfTransaction']['id']))
|
||||||
|
die("Item has already been set as NSF");
|
||||||
|
|
||||||
|
if (empty($tender['DepositTransaction']['id']))
|
||||||
|
die("Item has not been deposited yet");
|
||||||
|
|
||||||
|
$tender['Transaction'] = $tender['DepositTransaction'];
|
||||||
|
unset($tender['DepositTransaction']);
|
||||||
|
unset($tender['NsfTransaction']);
|
||||||
|
|
||||||
|
$T = new Transaction();
|
||||||
|
$result = $T->addNsf($tender, $stamp);
|
||||||
|
if ($result['error'])
|
||||||
|
return $this->prReturn(false);
|
||||||
|
|
||||||
|
// Flag the tender as NSF, using the items created from addNsf
|
||||||
|
$this->id = $id;
|
||||||
|
$this->saveField('nsf_transaction_id', $result['nsf_transaction_id']);
|
||||||
|
$this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']);
|
||||||
|
|
||||||
|
return $this->prReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -112,4 +112,4 @@ class TenderType extends AppModel {
|
|||||||
return $stats[0];
|
return $stats[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,726 @@
|
|||||||
|
<?php
|
||||||
|
class Transaction extends AppModel {
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'Account',
|
||||||
|
'Ledger',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'LedgerEntry',
|
||||||
|
'StatementEntry',
|
||||||
|
'DepositTender' => array(
|
||||||
|
'className' => 'Tender',
|
||||||
|
'foreignKey' => 'deposit_transaction_id',
|
||||||
|
),
|
||||||
|
|
||||||
|
'Charge' => array(
|
||||||
|
'className' => 'StatementEntry',
|
||||||
|
'conditions' => array('Charge.type' => 'CHARGE')
|
||||||
|
),
|
||||||
|
|
||||||
|
'Payment' => array(
|
||||||
|
'className' => 'StatementEntry',
|
||||||
|
'conditions' => array('Payment.type' => 'PAYMENT')
|
||||||
|
),
|
||||||
|
|
||||||
|
'Debit' => array(
|
||||||
|
'className' => 'LedgerEntry',
|
||||||
|
'conditions' => array('Debit.crdr' => 'DEBIT')
|
||||||
|
),
|
||||||
|
|
||||||
|
'Credit' => array(
|
||||||
|
'className' => 'LedgerEntry',
|
||||||
|
'conditions' => array('Credit.crdr' => 'CREDIT')
|
||||||
|
),
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
var $default_log_level = 30;
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addInvoice
|
||||||
|
* - Adds a new invoice invoice
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addInvoice($data, $customer_id, $lease_id = null) {
|
||||||
|
$this->prEnter(compact('data', 'customer_id', 'lease_id'));
|
||||||
|
|
||||||
|
// Establish the transaction as an invoice
|
||||||
|
$invoice =& $data['Transaction'];
|
||||||
|
$invoice['type'] = 'INVOICE';
|
||||||
|
$invoice['crdr'] = 'DEBIT';
|
||||||
|
$invoice['account_id'] = $this->Account->accountReceivableAccountID();
|
||||||
|
$invoice['customer_id'] = $customer_id;
|
||||||
|
$invoice['lease_id'] = $lease_id;
|
||||||
|
|
||||||
|
// Go through the statement entries and flag as charges
|
||||||
|
foreach ($data['Entry'] AS &$entry) {
|
||||||
|
$entry['type'] = 'CHARGE';
|
||||||
|
$entry['crdr'] = 'CREDIT';
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = $this->addTransaction($data['Transaction'], $data['Entry']);
|
||||||
|
if (isset($ids['transaction_id']))
|
||||||
|
$ids['invoice_id'] = $ids['transaction_id'];
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addReceipt
|
||||||
|
* - Adds a new receipt
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addReceipt($data, $customer_id, $lease_id = null) {
|
||||||
|
$this->prEnter(compact('data', 'customer_id', 'lease_id'));
|
||||||
|
|
||||||
|
// Establish the transaction as a receipt
|
||||||
|
$receipt =& $data['Transaction'];
|
||||||
|
$receipt['type'] = 'RECEIPT';
|
||||||
|
$receipt['crdr'] = 'CREDIT';
|
||||||
|
$receipt['account_id'] = $this->Account->accountReceivableAccountID();
|
||||||
|
$receipt['customer_id'] = $customer_id;
|
||||||
|
$receipt['lease_id'] = $lease_id;
|
||||||
|
|
||||||
|
// Go through the statement entries and flag as payments
|
||||||
|
foreach ($data['Entry'] AS &$entry) {
|
||||||
|
$entry['crdr'] = 'DEBIT';
|
||||||
|
if (empty($entry['account_id']) && isset($entry['Tender']['tender_type_id'])) {
|
||||||
|
$entry['account_id'] = $this->LedgerEntry->Tender->TenderType->
|
||||||
|
accountID($entry['Tender']['tender_type_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = $this->addTransaction($data['Transaction'], $data['Entry']);
|
||||||
|
if (isset($ids['transaction_id']))
|
||||||
|
$ids['receipt_id'] = $ids['transaction_id'];
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addWaiver
|
||||||
|
* - Adds a new waiver
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addWaiver($data, $customer_id, $lease_id = null) {
|
||||||
|
$this->prEnter(compact('data', 'customer_id', 'lease_id'));
|
||||||
|
// REVISIT <AP>: 20090802
|
||||||
|
// Completely un-implemented. Just copied from addReceipt
|
||||||
|
// and search-replace receipt with waiver.
|
||||||
|
return array('error' => true);
|
||||||
|
|
||||||
|
// Establish the transaction as a waiver
|
||||||
|
$waiver =& $data['Transaction'];
|
||||||
|
$waiver['type'] = 'RECEIPT';
|
||||||
|
$waiver['crdr'] = 'CREDIT';
|
||||||
|
$waiver['account_id'] = $this->Account->accountReceivableAccountID();
|
||||||
|
$waiver['customer_id'] = $customer_id;
|
||||||
|
$waiver['lease_id'] = $lease_id;
|
||||||
|
|
||||||
|
// Go through the statement entries and flag as payments
|
||||||
|
foreach ($data['Entry'] AS &$entry) {
|
||||||
|
$entry['type'] = 'WAIVE';
|
||||||
|
$entry['crdr'] = 'DEBIT';
|
||||||
|
if (empty($entry['account_id']) && isset($entry['Tender']['tender_type_id'])) {
|
||||||
|
$entry['account_id'] = $this->LedgerEntry->Tender->TenderType->
|
||||||
|
accountID($entry['Tender']['tender_type_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = $this->addTransaction($data['Transaction'], $data['Entry']);
|
||||||
|
if (isset($ids['transaction_id']))
|
||||||
|
$ids['waiver_id'] = $ids['transaction_id'];
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addDeposit
|
||||||
|
* - Adds a new bank deposit
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addDeposit($data, $account_id) {
|
||||||
|
$this->prEnter(compact('data', 'account_id'));
|
||||||
|
|
||||||
|
// Establish the transaction as a deposit
|
||||||
|
$deposit =& $data['Transaction'];
|
||||||
|
$deposit['type'] = 'DEPOSIT';
|
||||||
|
$deposit['crdr'] = 'DEBIT';
|
||||||
|
$deposit['account_id'] = $account_id;
|
||||||
|
$deposit['customer_id'] = null;
|
||||||
|
$deposit['lease_id'] = null;
|
||||||
|
|
||||||
|
// Save the list of IDs, so that we can mark their
|
||||||
|
// deposit transaction after it has been created.
|
||||||
|
$tender_ids = array_map(create_function('$item', 'return $item["tender_id"];'),
|
||||||
|
$data['Entry']);
|
||||||
|
|
||||||
|
// Go through the statement entries and re-group by account id
|
||||||
|
$group = array();
|
||||||
|
foreach ($data['Entry'] AS &$entry) {
|
||||||
|
if (!isset($group[$entry['account_id']]))
|
||||||
|
$group[$entry['account_id']] =
|
||||||
|
array('account_id' => $entry['account_id'],
|
||||||
|
'crdr' => 'CREDIT',
|
||||||
|
'amount' => 0);
|
||||||
|
$group[$entry['account_id']]['amount'] += $entry['amount'];
|
||||||
|
}
|
||||||
|
$data['Entry'] = $group;
|
||||||
|
|
||||||
|
$ids = $this->addTransaction($data['Transaction'], $data['Entry']);
|
||||||
|
if (isset($ids['transaction_id']))
|
||||||
|
$ids['deposit_id'] = $ids['transaction_id'];
|
||||||
|
|
||||||
|
if (!empty($ids['deposit_id'])) {
|
||||||
|
$this->LedgerEntry->Tender->updateAll
|
||||||
|
(array('Tender.deposit_transaction_id' => $ids['deposit_id']),
|
||||||
|
array('Tender.id' => $tender_ids)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addClose
|
||||||
|
* - Adds a new transaction for closing ledgers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addClose($data) {
|
||||||
|
$this->prEnter(compact('data'));
|
||||||
|
|
||||||
|
// Establish the transaction as a close
|
||||||
|
$close =& $data['Transaction'];
|
||||||
|
$close['type'] = 'CLOSE';
|
||||||
|
$close['account_id'] = null;
|
||||||
|
$close['customer_id'] = null;
|
||||||
|
$close['lease_id'] = null;
|
||||||
|
|
||||||
|
$ledger_ids = array();
|
||||||
|
$data['Entry'] = array();
|
||||||
|
foreach ($data['Ledger'] AS $ledger) {
|
||||||
|
$ledger_id = $ledger['old_ledger_id'];
|
||||||
|
$new_ledger_id = $ledger['new_ledger_id'];
|
||||||
|
$amount = $ledger['amount'];
|
||||||
|
$account_id = $this->Account->Ledger->accountID($ledger_id);
|
||||||
|
$crdr = strtoupper($this->Account->fundamentalOpposite($account_id));
|
||||||
|
$comment = "Ledger Carry Forward (c/f)";
|
||||||
|
|
||||||
|
// Save the ledger ID for later, to mark it as closed
|
||||||
|
$ledger_ids[] = $ledger_id;
|
||||||
|
|
||||||
|
// No need to generate ledger entries if there is no balance
|
||||||
|
if (empty($ledger['amount']) || $ledger['amount'] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add an entry to carry the ledger balance forward
|
||||||
|
$data['Entry'][] = compact('account_id', 'ledger_id', 'new_ledger_id',
|
||||||
|
'crdr', 'amount', 'comment');
|
||||||
|
}
|
||||||
|
unset($data['Ledger']);
|
||||||
|
|
||||||
|
// Add the transaction and carry forward balances
|
||||||
|
$ids = $this->addTransaction($data['Transaction'], $data['Entry']);
|
||||||
|
if (isset($ids['transaction_id']))
|
||||||
|
$ids['close_id'] = $ids['transaction_id'];
|
||||||
|
|
||||||
|
// Mark the older ledgers as closed
|
||||||
|
if (!empty($ids['close_id'])) {
|
||||||
|
$this->LedgerEntry->Ledger->updateAll
|
||||||
|
(array('Ledger.close_transaction_id' => $ids['close_id']),
|
||||||
|
array('Ledger.id' => $ledger_ids)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: verifyTransaction
|
||||||
|
* - Verifies consistenty of new transaction data
|
||||||
|
* (not in a pre-existing transaction)
|
||||||
|
*/
|
||||||
|
function verifyTransaction($transaction, $entries) {
|
||||||
|
//$this->prFunctionLevel(10);
|
||||||
|
$this->prEnter(compact('transaction', 'entries'));
|
||||||
|
|
||||||
|
// Verify required Transaction data is present
|
||||||
|
if (empty($transaction['type']) ||
|
||||||
|
($transaction['type'] != 'CLOSE'
|
||||||
|
&& (empty($transaction['account_id']) ||
|
||||||
|
empty($transaction['crdr']))) ||
|
||||||
|
(in_array($transaction['type'], array('INVOICE', 'RECEIPT'))
|
||||||
|
&& empty($transaction['customer_id']))
|
||||||
|
) {
|
||||||
|
return $this->prReturn(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all entries
|
||||||
|
foreach ($entries AS $entry) {
|
||||||
|
// Ensure these items are null'ed out so we don't
|
||||||
|
// accidentally pick up stale data.
|
||||||
|
$le1 = $le1_tender = $le2 = $se = null;
|
||||||
|
extract($entry);
|
||||||
|
if (!empty($le1) && !empty($le2) &&
|
||||||
|
!$this->LedgerEntry->DoubleEntry->verifyDoubleEntry($le1, $le2, $le1_tender)) {
|
||||||
|
return $this->prReturn(false);
|
||||||
|
}
|
||||||
|
if (!empty($se) &&
|
||||||
|
!$this->StatementEntry->verifyStatementEntry($se)) {
|
||||||
|
return $this->prReturn(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addTransaction
|
||||||
|
* - Adds a new transaction, and the appropriate ledger and statement
|
||||||
|
* entries, as layed out in the $data['Entry'] array. The array is
|
||||||
|
* overloaded, since it is used to create both ledger _and_ statement
|
||||||
|
* entries.
|
||||||
|
*
|
||||||
|
* $data
|
||||||
|
* - Transaction
|
||||||
|
* - [MANDATORY]
|
||||||
|
* - type (INVOICE, RECEIPT)
|
||||||
|
* - account_id
|
||||||
|
* - crdr
|
||||||
|
* - [OPTIONAL]
|
||||||
|
* - stamp
|
||||||
|
* (default: NOW)
|
||||||
|
* - comment
|
||||||
|
* - [AUTOMATICALLY SET] (if set, these items will be overwritten)
|
||||||
|
* - id
|
||||||
|
* - amount
|
||||||
|
* - customer_id
|
||||||
|
* - ledger_id
|
||||||
|
*
|
||||||
|
* - Entry (array)
|
||||||
|
* - [MANDATORY]
|
||||||
|
* - type (CHARGE, PAYMENT)
|
||||||
|
* - account_id
|
||||||
|
* - crdr
|
||||||
|
* - amount
|
||||||
|
* - [OPTIONAL]
|
||||||
|
* - effective_date
|
||||||
|
* - through_date
|
||||||
|
* - due_date
|
||||||
|
* - comment (used for statement or ledger entry, based on context)
|
||||||
|
* - ledger_entry_comment
|
||||||
|
* - statement_entry_comment
|
||||||
|
* - Tender
|
||||||
|
* - [MANDATORY]
|
||||||
|
* - tender_type_id
|
||||||
|
* - [OPTIONAL]
|
||||||
|
* - name
|
||||||
|
* (default: Entry Account Name & data1)
|
||||||
|
* - data1, data2, data3, data4
|
||||||
|
* - comment
|
||||||
|
* - [AUTOMATICALLY SET] (if set, these items will be overwritten)
|
||||||
|
* - id
|
||||||
|
* - ledger_entry_id
|
||||||
|
* - deposit_transaction_id
|
||||||
|
* - nsf_transaction_id
|
||||||
|
* - [AUTOMATICALLY SET] (if set, these items will be overwritten)
|
||||||
|
* - id
|
||||||
|
* - transaction_id
|
||||||
|
* - ledger_id
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addTransaction($transaction, $entries, $subtype = null) {
|
||||||
|
$this->prEnter(compact('transaction', 'entries', 'subtype'));
|
||||||
|
|
||||||
|
// Verify that we have a transaction and entries
|
||||||
|
if (empty($transaction) ||
|
||||||
|
($transaction['type'] !== 'CLOSE' && empty($entries)))
|
||||||
|
return $this->prReturn(array('error' => true));
|
||||||
|
|
||||||
|
// set ledger ID as the current ledger of the specified account
|
||||||
|
if (empty($transaction['ledger_id']))
|
||||||
|
$transaction['ledger_id'] =
|
||||||
|
$this->Account->currentLedgerID($transaction['account_id']);
|
||||||
|
|
||||||
|
// Automatically figure out the customer if we have the lease
|
||||||
|
if (!empty($transaction['lease_id']) && empty($transaction['customer_id'])) {
|
||||||
|
$L = new Lease();
|
||||||
|
$L->recursive = -1;
|
||||||
|
$lease = $L->read(null, $transaction['lease_id']);
|
||||||
|
$transaction['customer_id'] = $lease['Lease']['customer_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break each entry out of the combined statement/ledger entry
|
||||||
|
// and into individual entries appropriate for saving. While
|
||||||
|
// we're at it, calculate the transaction total as well.
|
||||||
|
$transaction['amount'] = 0;
|
||||||
|
foreach ($entries AS &$entry) {
|
||||||
|
// Ensure these items are null'ed out so we don't
|
||||||
|
// accidentally pick up stale data.
|
||||||
|
$le1 = $le1_tender = $le2 = $se = null;
|
||||||
|
|
||||||
|
// Add entry amount into the transaction total
|
||||||
|
$transaction['amount'] += $entry['amount'];
|
||||||
|
|
||||||
|
// Set up our comments, possibly using the default 'comment' field
|
||||||
|
if (empty($entry['ledger_entry_comment'])) {
|
||||||
|
if ($transaction['type'] != 'INVOICE' && !empty($entry['comment']))
|
||||||
|
$entry['ledger_entry_comment'] = $entry['comment'];
|
||||||
|
else
|
||||||
|
$entry['ledger_entry_comment'] = null;
|
||||||
|
}
|
||||||
|
if (empty($entry['statement_entry_comment'])) {
|
||||||
|
if ($transaction['type'] == 'INVOICE' && !empty($entry['comment']))
|
||||||
|
$entry['statement_entry_comment'] = $entry['comment'];
|
||||||
|
else
|
||||||
|
$entry['statement_entry_comment'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create one half of the Double Ledger Entry (and the Tender)
|
||||||
|
$le1 =
|
||||||
|
array_intersect_key($entry,
|
||||||
|
array_flip(array('ledger_id', 'account_id', 'crdr', 'amount')));
|
||||||
|
$le1['comment'] = $entry['ledger_entry_comment'];
|
||||||
|
$le1_tender = isset($entry['Tender']) ? $entry['Tender'] : null;
|
||||||
|
|
||||||
|
// Create the second half of the Double Ledger Entry
|
||||||
|
if ($transaction['type'] == 'CLOSE') {
|
||||||
|
$le2 =
|
||||||
|
array_intersect_key($entry,
|
||||||
|
array_flip(array('account_id', 'amount')));
|
||||||
|
$le2['ledger_id'] = $entry['new_ledger_id'];
|
||||||
|
$le2['crdr'] = strtoupper($this->Account->fundamentalOpposite($le1['crdr']));
|
||||||
|
$le2['comment'] = "Ledger Balance Forward (b/f)";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$le2 =
|
||||||
|
array_intersect_key($entry,
|
||||||
|
array_flip(array('amount'))) +
|
||||||
|
array_intersect_key($transaction,
|
||||||
|
array_flip(array('ledger_id', 'account_id', 'crdr')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the statement entry
|
||||||
|
$se =
|
||||||
|
array_intersect_key($entry,
|
||||||
|
array_flip(array('type', 'amount',
|
||||||
|
'effective_date', 'through_date', 'due_date',
|
||||||
|
'customer_id', 'lease_id',
|
||||||
|
'charge_entry_id'))) +
|
||||||
|
array_intersect_key($transaction,
|
||||||
|
array_flip(array('customer_id', 'lease_id')));
|
||||||
|
$se['comment'] = $entry['statement_entry_comment'];
|
||||||
|
|
||||||
|
// (PAYMENTS will have statement entries created below, when
|
||||||
|
// assigning credits, and DEPOSITS don't have statement entries)
|
||||||
|
if ($transaction['type'] != 'INVOICE' && $subtype !== 'NSF')
|
||||||
|
$se = null;
|
||||||
|
|
||||||
|
// NSF transactions don't use LedgerEntries
|
||||||
|
// REVISIT <AP>: 20090731
|
||||||
|
// Doesn't seem right... probably doing this because of the
|
||||||
|
// single A/R entry we add below for NSF
|
||||||
|
if ($subtype === 'NSF')
|
||||||
|
$le1 = $le1_tender = $le2 = null;
|
||||||
|
|
||||||
|
// Replace combined entry with our new individual entries
|
||||||
|
$entry = compact('le1', 'le1_tender', 'le2', 'se');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($subtype === 'NSF') {
|
||||||
|
// REVISIT <AP>: 20090731
|
||||||
|
// Should we be doing this, or just doing individual ledger entries
|
||||||
|
// that were created above before we nulled them out
|
||||||
|
array_unshift($entries,
|
||||||
|
array('le1' => array('account_id' => $transaction['account_id'],
|
||||||
|
'crdr' => 'DEBIT',
|
||||||
|
'amount' => $transaction['amount']),
|
||||||
|
'le2' => array('account_id' => $this->Account->accountReceivableAccountID(),
|
||||||
|
'crdr' => 'CREDIT',
|
||||||
|
'amount' => $transaction['amount'])
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->pr(20, compact('transaction', 'entries'));
|
||||||
|
|
||||||
|
// Move forward, verifying and saving everything.
|
||||||
|
$ret = array();
|
||||||
|
if (!$this->verifyTransaction($transaction, $entries))
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
// Save transaction to the database
|
||||||
|
$this->create();
|
||||||
|
if (!$this->save($transaction))
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
// Set up our return ids array
|
||||||
|
$ret['transaction_id'] = $this->id;
|
||||||
|
$ret['entries'] = array();
|
||||||
|
$ret['error'] = false;
|
||||||
|
|
||||||
|
// Go through the entries
|
||||||
|
foreach ($entries AS $e_index => &$entry) {
|
||||||
|
// Ensure these items are null'ed out so we don't
|
||||||
|
// accidentally pick up stale data.
|
||||||
|
$le1 = $le1_tender = $le2 = $se = null;
|
||||||
|
extract($entry);
|
||||||
|
|
||||||
|
if (!empty($le1) && !empty($le2)) {
|
||||||
|
$le1['transaction_id'] = $le2['transaction_id'] = $ret['transaction_id'];
|
||||||
|
if (isset($le1_tender))
|
||||||
|
$le1_tender['customer_id'] = $transaction['customer_id'];
|
||||||
|
$result = $this->LedgerEntry->DoubleEntry->addDoubleEntry($le1, $le2, $le1_tender);
|
||||||
|
$ret['entries'][$e_index]['DoubleEntry'] = $result;
|
||||||
|
if ($result['error']) {
|
||||||
|
$ret['error'] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($se)) {
|
||||||
|
//pr($ret['entries'][$e_index]['DoubleEntry']); die;
|
||||||
|
$le_id = $ret['entries'][0]['DoubleEntry']['Entry1']['ledger_entry_id'];
|
||||||
|
$se['transaction_id'] = $ret['transaction_id'];
|
||||||
|
$se['Fraction'] = array(array('ledger_entry_id' => $le_id,
|
||||||
|
'amount' => $se['amount']));
|
||||||
|
$result = $this->StatementEntry->addStatementEntry($se);
|
||||||
|
$ret['entries'][$e_index]['StatementEntry'] = $result;
|
||||||
|
if ($result['error']) {
|
||||||
|
$ret['error'] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($transaction['type'] == 'INVOICE' ||
|
||||||
|
$transaction['type'] == 'RECEIPT') &&
|
||||||
|
$subtype !== 'NSF' && !$ret['error']) {
|
||||||
|
$result = $this->StatementEntry->assignCredits
|
||||||
|
(array('link' => array('Customer'),
|
||||||
|
'conditions' => array('Customer.id' => $transaction['customer_id'])),
|
||||||
|
($transaction['type'] == 'RECEIPT'
|
||||||
|
? $ret['transaction_id']
|
||||||
|
: null));
|
||||||
|
|
||||||
|
$ret['assigned'] = $result;
|
||||||
|
if ($result['error'])
|
||||||
|
$ret['error'] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn($ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: addNsf
|
||||||
|
* - Adds NSF transaction
|
||||||
|
*/
|
||||||
|
|
||||||
|
function addNsf($tender, $stamp) {
|
||||||
|
$this->prEnter(compact('tender', 'stamp'));
|
||||||
|
|
||||||
|
$ret = array();
|
||||||
|
|
||||||
|
// Enter the NSF
|
||||||
|
// This is the transaction pulling money from the bank account
|
||||||
|
// and recording it in the NSF account. It has nothing to do
|
||||||
|
// with the customer statement (charges, payments, credits, etc).
|
||||||
|
$bounce_result = $this->addDeposit
|
||||||
|
(array('Transaction' => array(),
|
||||||
|
'Entry' => array(array('tender_id' => null,
|
||||||
|
'account_id' => $this->Account->nsfAccountID(),
|
||||||
|
'amount' => -1 * $tender['LedgerEntry']['amount'],
|
||||||
|
))),
|
||||||
|
$tender['Transaction']['account_id']);
|
||||||
|
|
||||||
|
$this->pr(20, compact('bounce_result'));
|
||||||
|
$ret['bounce'] = $bounce_result;
|
||||||
|
if ($bounce_result['error'])
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
// Since we may have saved the nsf transaction with a null
|
||||||
|
// timestamp, query it back out of the database to find out
|
||||||
|
// what timestamp was _really_ specified, for later use.
|
||||||
|
$bounce = $this->find
|
||||||
|
('first', array('contain' => false, 'id' => $bounce_result['transaction_id']));
|
||||||
|
$this->pr(20, compact('bounce'));
|
||||||
|
$stamp = $bounce['Transaction']['stamp'];
|
||||||
|
|
||||||
|
// OK, now move into customer realm, finding all statement
|
||||||
|
// entries that were affected by the bad payment (tender).
|
||||||
|
$nsf_ledger_entry = $this->LedgerEntry->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array('Transaction' =>
|
||||||
|
array(//'fields' => array(),
|
||||||
|
'StatementEntry' =>
|
||||||
|
array(//'fields' => array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'conditions' => array('LedgerEntry.id' => $tender['LedgerEntry']['id']),
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->pr(20, compact('nsf_ledger_entry'));
|
||||||
|
if (!$nsf_ledger_entry)
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
// Build a transaction to adjust all of the statement entries
|
||||||
|
$rollback = array('Transaction' => array(), 'Entry' => array());
|
||||||
|
|
||||||
|
$rollback['Transaction']['stamp'] = $stamp;
|
||||||
|
$rollback['Transaction']['type'] = 'RECEIPT';
|
||||||
|
$rollback['Transaction']['crdr'] = 'DEBIT'; // Unused... keeps verifyTx happy
|
||||||
|
$rollback['Transaction']['account_id'] = $this->Account->nsfAccountID();
|
||||||
|
$rollback['Transaction']['customer_id'] = $tender['Tender']['customer_id'];
|
||||||
|
$rollback['Transaction']['amount'] = -1 * $tender['LedgerEntry']['amount'];
|
||||||
|
|
||||||
|
foreach ($nsf_ledger_entry['Transaction']['StatementEntry'] AS $payment) {
|
||||||
|
if ($payment['type'] === 'SURPLUS') {
|
||||||
|
$payment['type'] = 'VOID';
|
||||||
|
$this->StatementEntry->id = $payment['id'];
|
||||||
|
$this->StatementEntry->saveField('type', $payment['type']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$rollback['Entry'][] =
|
||||||
|
array('type' => $payment['type'],
|
||||||
|
'amount' => -1 * $payment['amount'],
|
||||||
|
'account_id' => $this->Account->nsfAccountID(),
|
||||||
|
'customer_id' => $payment['customer_id'],
|
||||||
|
'lease_id' => $payment['lease_id'],
|
||||||
|
'charge_entry_id' => $payment['charge_entry_id'],
|
||||||
|
'effective_date' => $stamp,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the transaction, which will un-pay previously paid
|
||||||
|
// charges, void any credits, and other similar work.
|
||||||
|
$rollback_result = $this->addTransaction($rollback['Transaction'], $rollback['Entry'], 'NSF');
|
||||||
|
$this->pr(20, compact('rollback', 'rollback_result'));
|
||||||
|
$ret['rollback'] = $rollback_result;
|
||||||
|
if ($rollback_result['error'])
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
// Add NSF Charge
|
||||||
|
$charge_result = $this->addInvoice
|
||||||
|
(array('Transaction' => compact('stamp'),
|
||||||
|
|
||||||
|
'Entry' =>
|
||||||
|
array
|
||||||
|
(array('account_id' => $this->Account->nsfChargeAccountID(),
|
||||||
|
'effective_date' => $stamp,
|
||||||
|
// REVISIT <AP>: 20090730
|
||||||
|
// BAD, BAD, BAD... who would actually
|
||||||
|
// hardcode a value like this???? ;-)
|
||||||
|
'amount' => 35,
|
||||||
|
'comment' => "NSF: " . $tender['Tender']['name'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
$tender['Tender']['customer_id']);
|
||||||
|
|
||||||
|
$this->pr(20, compact('charge_result'));
|
||||||
|
$ret['charge'] = $charge_result;
|
||||||
|
if ($charge_result['error'])
|
||||||
|
return $this->prReturn(array('error' => true) + $ret);
|
||||||
|
|
||||||
|
$ret['nsf_transaction_id'] = $ret['bounce']['transaction_id'];
|
||||||
|
$ret['nsf_ledger_entry_id'] = $ret['rollback']['entries'][0]['DoubleEntry']['Entry1']['ledger_entry_id'];
|
||||||
|
return $this->prReturn($ret + array('error' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested transaction
|
||||||
|
*/
|
||||||
|
function stats($id = null, $query = null, $balance_account_id = null) {
|
||||||
|
$this->prEnter(compact('id', 'query'));
|
||||||
|
|
||||||
|
$this->queryInit($query);
|
||||||
|
unset($query['group']);
|
||||||
|
|
||||||
|
if (isset($id)) {
|
||||||
|
$query['conditions'][] = array('Transaction.id' => $id);
|
||||||
|
$query['group'] = 'Transaction.id';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// CakePHP seems to automagically add in our ID as a part
|
||||||
|
// of the query conditions, but only on a 'first' query,
|
||||||
|
// not an 'all'. I suppose this is helpful :-/
|
||||||
|
unset($this->id);
|
||||||
|
|
||||||
|
if (empty($query['fields']))
|
||||||
|
$query['fields'] = array();
|
||||||
|
|
||||||
|
$stats = array();
|
||||||
|
foreach ($this->hasMany AS $table => $association) {
|
||||||
|
// Only calculate stats for *Entry types
|
||||||
|
if (!preg_match("/Entry$/", $table) &&
|
||||||
|
!preg_match("/Entry$/", $association['className']))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
$squery = $query;
|
||||||
|
$squery['link'][$table] = array('fields' => array());
|
||||||
|
|
||||||
|
if ($table == 'LedgerEntry') {
|
||||||
|
if (isset($balance_account_id)) {
|
||||||
|
$squery['link']['LedgerEntry']['Account'] = array('fields' => array());
|
||||||
|
$squery['conditions'][] = array("Account.id" => $balance_account_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$squery['fields'] = array_merge($squery['fields'],
|
||||||
|
$this->LedgerEntry->debitCreditFields(true, $balance_account_id != null));
|
||||||
|
}
|
||||||
|
elseif ($table == 'StatementEntry') {
|
||||||
|
$squery['fields'] = array_merge($squery['fields'],
|
||||||
|
$this->StatementEntry->chargePaymentFields(true));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$squery['fields'][] = "SUM({$table}.amount) AS total";
|
||||||
|
$squery['fields'][] = "COUNT({$table}.id) AS entries";
|
||||||
|
}
|
||||||
|
$stats[$table] = $this->find('first', $squery);
|
||||||
|
// REVISIT <AP>: 20090724
|
||||||
|
// [0][0] is for when we do an 'all' query. This can
|
||||||
|
// be removed at some point, but I'm keeping it while
|
||||||
|
// toggling between 'all' and 'first' (testing).
|
||||||
|
if (isset($stats[$table][0][0]))
|
||||||
|
$stats[$table] += $stats[$table][0][0];
|
||||||
|
else
|
||||||
|
$stats[$table] += $stats[$table][0];
|
||||||
|
unset($stats[$table][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->prReturn($stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
class Unit extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Unit';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'unit_size_id' => array('numeric'),
|
||||||
|
'name' => array('notempty'),
|
||||||
|
'sort_order' => array('numeric'),
|
||||||
|
'walk_order' => array('numeric'),
|
||||||
|
'deposit' => array('money'),
|
||||||
|
'amount' => array('money')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'UnitSize',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasOne = array(
|
||||||
|
'CurrentLease' => array(
|
||||||
|
'className' => 'Lease',
|
||||||
|
'conditions' => 'CurrentLease.moveout_date IS NULL',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'Lease',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* helpers: status enumerations
|
||||||
|
*/
|
||||||
|
|
||||||
|
function statusEnums() {
|
||||||
|
static $status_enums;
|
||||||
|
if (!isset($status_enums))
|
||||||
|
$status_enums = $this->getEnumValues('status');
|
||||||
|
return $status_enums;
|
||||||
|
}
|
||||||
|
|
||||||
|
function activeStatusEnums() {
|
||||||
|
return array_diff_key($this->statusEnums(), array(''=>1, 'DELETED'=>1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function statusValue($enum) {
|
||||||
|
$enums = $this->statusEnums();
|
||||||
|
return $enums[$enum];
|
||||||
|
}
|
||||||
|
|
||||||
|
function occupiedEnumValue() {
|
||||||
|
return statusValue('OCCUPIED');
|
||||||
|
}
|
||||||
|
|
||||||
|
function conditionOccupied() {
|
||||||
|
return ('Unit.status >= ' . $this->statusValue('OCCUPIED'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function conditionVacant() {
|
||||||
|
return ('Unit.status BETWEEN ' .
|
||||||
|
($this->statusValue('UNAVAILABLE')+1) .
|
||||||
|
' AND ' .
|
||||||
|
($this->statusValue('OCCUPIED')-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function conditionUnavailable() {
|
||||||
|
return ('Unit.status <= ' . $this->statusValue('UNAVAILABLE'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: updateStatus
|
||||||
|
* - Update the given unit to the given status
|
||||||
|
*/
|
||||||
|
function updateStatus($id, $status) {
|
||||||
|
$this->id = $id;
|
||||||
|
//pr(compact('id', 'status'));
|
||||||
|
$this->saveField('status', $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested customer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function stats($id = null) {
|
||||||
|
if (!$id)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Get the basic information necessary
|
||||||
|
$unit = $this->find('first',
|
||||||
|
array('contain' => array
|
||||||
|
('Lease' => array
|
||||||
|
('fields' => array('Lease.id')),
|
||||||
|
|
||||||
|
'CurrentLease' => array
|
||||||
|
('fields' => array('CurrentLease.id'))),
|
||||||
|
|
||||||
|
'conditions' => array
|
||||||
|
(array('Unit.id' => $id)),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Get the stats for the current lease
|
||||||
|
$stats['CurrentLease'] = $this->Lease->stats($unit['CurrentLease']['id']);
|
||||||
|
|
||||||
|
// Sum the stats for all leases together
|
||||||
|
foreach ($unit['Lease'] AS $lease) {
|
||||||
|
$this->statsMerge($stats['Lease'], $this->Lease->stats($lease['id']));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the collection
|
||||||
|
return $stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
class UnitSize extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'UnitSize';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'unit_type_id' => array('numeric'),
|
||||||
|
'code' => array('notempty'),
|
||||||
|
'name' => array('notempty'),
|
||||||
|
'width' => array('numeric'),
|
||||||
|
'depth' => array('numeric'),
|
||||||
|
'deposit' => array('money'),
|
||||||
|
'amount' => array('money')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'UnitType',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'Unit',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
class UnitType extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'UnitType';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'code' => array('notempty'),
|
||||||
|
'name' => array('notempty')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'UnitSize',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user