Compare commits
158 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9fea9c79f3 | |||
| 10f71a1fe3 | |||
| 73eacdbcf2 | |||
| 009ea6b44d | |||
| 7ea002850a | |||
| eee3d45c5d | |||
| de93c7545b | |||
| e00e10bbb5 | |||
| 3953e1dbf3 | |||
| 788cbde710 | |||
| 4a064df594 | |||
| c048d44972 | |||
| f6d6659d2a | |||
| 19cee7290f | |||
| 3c067f6586 | |||
| f7bcfef665 | |||
| d06f34de9a | |||
| d5388e7767 | |||
| 5a88f29600 | |||
| 8dd64f60bc | |||
| de2319e93d | |||
| 1fbc452581 | |||
| 65acd0e181 | |||
| f5bb9bac83 | |||
| 45ae013e99 | |||
| 16126b7b6e | |||
| fdd3fe2641 | |||
| c340c25eee | |||
| b8de98917a | |||
| d6c7fbb735 | |||
| 5dd3efa12f | |||
| cb02b9e1e0 | |||
| 212c982851 | |||
| 0aa94b8fe5 | |||
| 76e9b7590f | |||
| af405a44d5 | |||
| 1f9772e926 | |||
| b1a0437117 | |||
| 8db9b90157 | |||
| 33b7d3d67d | |||
| 57c73eafdb | |||
| 30b3185473 | |||
| e9dd1366bc | |||
| 7ee461d993 | |||
| 365b2295af | |||
| dfb0d90246 | |||
| af32d88605 | |||
| c9c06a9fb4 | |||
| c3139220ee | |||
| 68273302cb | |||
| abd45244e1 | |||
| e3b838d62a | |||
| 5fd7483ac1 | |||
| 274ed13644 | |||
| 4537174873 | |||
| 3c5a31aaff | |||
| fd155aaaeb | |||
| 284765e06a | |||
| 352e3487cc | |||
| b02695631e | |||
| b6317d3ee9 | |||
| 2cbd5da8ee | |||
| 960ac108b8 | |||
| 0133c85c01 | |||
| 92d8387e8c | |||
| 67d640b1a0 | |||
| ddf4d5cb29 | |||
| 2143960ce9 | |||
| 06a4a25be8 | |||
| 25677ffa5e | |||
| f06d831329 | |||
| eefc0d7bce | |||
| 046ffba340 | |||
| cf0da7d3c2 | |||
| 95181f4718 | |||
| 447c6a8376 | |||
| 54291b4467 | |||
| 94c78ccb2a | |||
| 323c88a669 | |||
| 3fb680e20f | |||
| cbdd198be5 | |||
| 8cdf061fca | |||
| 5e321888d5 | |||
| d45481b770 | |||
| ff5c7260f8 | |||
| e2f623b7ee | |||
| b47bb9d46e | |||
| 9cf245d030 | |||
| 8bce19d8c4 | |||
| ab766c2dc5 | |||
| 4a53ebd70b | |||
| ce735cad3f | |||
| ef3b5f3022 | |||
| 73ea4fa86c | |||
| 806f732de6 | |||
| b78834f7d6 | |||
| a0274b4d89 | |||
| 970b2ad202 | |||
| e0d9edc4a8 | |||
| ffd1b64580 | |||
| 3dcd83229b | |||
| ebc4a42ae9 | |||
| f08884f326 | |||
| e740cc859b | |||
| f12a95f3b9 | |||
| 677458e942 | |||
| ce24abc812 | |||
| 1ead830ad6 | |||
| 0848ab5055 | |||
| 52c72b08b2 | |||
| fc71c058fb | |||
| dd5402d2f1 | |||
| f473a91870 | |||
| cdd274adf7 | |||
| 8ea0822ed1 | |||
| 492e70b2f6 | |||
| abff728a37 | |||
| b8c4257f95 | |||
| 5f715cc076 | |||
| f40dc205f9 | |||
| feaabd29d9 | |||
| f48e7d8907 | |||
| 991b5a3317 | |||
| 68585a0b30 | |||
| a9a570d666 | |||
| 15c4b96a2a | |||
| ce252f2e70 | |||
| 4b857ff11f | |||
| 6661d26c76 | |||
| b409bf09d1 | |||
| b488054106 | |||
| 59398cb3f0 | |||
| 1145d293b2 | |||
| 2feb7f60a4 | |||
| bd6cc37d4a | |||
| 8dae1ccf84 | |||
| 50449205b4 | |||
| 77c038e880 | |||
| 44bdb384f5 | |||
| 2b135b0e66 | |||
| 23ec1b6b20 | |||
| 8f4f3c054e | |||
| 1249854514 | |||
| 7805e4d229 | |||
| 54c7287ee4 | |||
| bcec2a9891 | |||
| e772ff8755 | |||
| 3288969b0d | |||
| d268b6fe7e | |||
| e9b31d964c | |||
| 47d362750e | |||
| 47af64aefe | |||
| 1ca704157b | |||
| 8a3be97d41 | |||
| 05a4ee38f0 | |||
| 0e68fea04b | |||
| a9f47d73ba | |||
| 5b5e478bd0 |
@@ -0,0 +1,5 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine on
|
||||||
|
RewriteRule ^$ webroot/ [L]
|
||||||
|
RewriteRule (.*) webroot/$1 [L]
|
||||||
|
</IfModule>
|
||||||
@@ -0,0 +1,394 @@
|
|||||||
|
<?php
|
||||||
|
/* SVN FILE: $Id: app_controller.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||||
|
/**
|
||||||
|
* Short description for file.
|
||||||
|
*
|
||||||
|
* This file is application-wide controller file. You can put all
|
||||||
|
* application-wide controller-related methods here.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Short description for class.
|
||||||
|
*
|
||||||
|
* Add your application-wide methods in the class below, your controllers
|
||||||
|
* will inherit them.
|
||||||
|
*
|
||||||
|
* @package cake
|
||||||
|
* @subpackage cake.app
|
||||||
|
*/
|
||||||
|
class AppController extends Controller {
|
||||||
|
var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time');
|
||||||
|
var $components = array('DebugKit.Toolbar');
|
||||||
|
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array(
|
||||||
|
array('name' => 'Common', 'header' => true),
|
||||||
|
array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)),
|
||||||
|
array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')),
|
||||||
|
array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index')),
|
||||||
|
array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')),
|
||||||
|
array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index')),
|
||||||
|
array('name' => 'Accounts', 'url' => array('controller' => 'accounts', 'action' => 'index')),
|
||||||
|
array('name' => 'Ledgers', 'url' => array('controller' => 'ledgers', 'action' => 'index')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeRender() {
|
||||||
|
$this->set('sidemenu', $this->sideMenuLinks());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* helper: jqGridView
|
||||||
|
* - called by function to create an index listing
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridView($title, $action = null) {
|
||||||
|
$this->set('title', $title);
|
||||||
|
// The resulting page will contain a jqGrid, which will
|
||||||
|
// use ajax to obtain the actual data for this action
|
||||||
|
$this->set('action', $action ? $action : $this->params['action']);
|
||||||
|
$this->render('/elements/' . $this->params['controller']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: jqGridData
|
||||||
|
* - Fetches the actual data requested by jqGrid as XML
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridData() {
|
||||||
|
// Grab a copy of the parameters that control this request
|
||||||
|
$params = array();
|
||||||
|
if (isset($this->params['url']) && is_array($this->params['url']))
|
||||||
|
$params = $this->params['url'];
|
||||||
|
|
||||||
|
// Do any preliminary setup necessary
|
||||||
|
$this->jqGridDataSetup($params);
|
||||||
|
|
||||||
|
// Get the top level model for this grid
|
||||||
|
$model = $this->jqGridDataModel($params);
|
||||||
|
|
||||||
|
// Establish the basic query and conditions
|
||||||
|
$query = array_intersect_key($this->jqGridDataCountTables($params, $model),
|
||||||
|
array('link'=>1, 'contain'=>1));
|
||||||
|
$query['conditions'] = $this->jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
// Get the number of records prior to pagination
|
||||||
|
$count = $this->jqGridDataRecordCount($params, $model, $query);
|
||||||
|
|
||||||
|
// Start the query over, this time getting the actual set
|
||||||
|
// of tables needed, not just those needed for counting.
|
||||||
|
$query = array_intersect_key($this->jqGridDataTables($params, $model),
|
||||||
|
array('link'=>1, 'contain'=>1));
|
||||||
|
$query['conditions'] = $this->jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
// Verify a few parameters and determine our starting row
|
||||||
|
$limit = $params['rows'];
|
||||||
|
$total = ($count < 0) ? 0 : ceil($count/$limit);
|
||||||
|
$page = ($params['page'] <= 1) ? 1 : (($params['page'] > $total) ? $total : $params['page']);
|
||||||
|
$start = $limit*$page - $limit;
|
||||||
|
|
||||||
|
// Grab the actual records taking pagination into account
|
||||||
|
$query['group'] = $this->jqGridDataGroup($params, $model);
|
||||||
|
$query['order'] = $this->jqGridDataOrder($params, $model,
|
||||||
|
isset($params['sidx']) ? $params['sidx'] : null,
|
||||||
|
isset($params['sord']) ? $params['sord'] : null);
|
||||||
|
$query['limit'] = $this->jqGridDataLimit($params, $model, $start, $limit);
|
||||||
|
$query['fields'] = $this->jqGridDataFields($params, $model);
|
||||||
|
$results = $this->jqGridDataRecords($params, $model, $query);
|
||||||
|
|
||||||
|
// Post process the records
|
||||||
|
$this->jqGridRecordsPostProcess($params, $model, $results);
|
||||||
|
|
||||||
|
// Add in any needed hyperlinks
|
||||||
|
$this->jqGridRecordLinks($params, $model, $results, array());
|
||||||
|
|
||||||
|
// DEBUG PURPOSES ONLY!
|
||||||
|
$params['query'] = $query;
|
||||||
|
|
||||||
|
// Finally, dump out the data
|
||||||
|
$this->jqGridDataOutputHeader($params, $model);
|
||||||
|
echo "<?xml version='1.0' encoding='utf-8'?>\n";
|
||||||
|
echo "<rows>\n";
|
||||||
|
$this->jqGridDataOutputSummary($params, $model, $page, $total, $count);
|
||||||
|
$this->jqGridDataOutputRecords($params, $model, $results);
|
||||||
|
echo "</rows>\n";
|
||||||
|
|
||||||
|
// Call out to finalize everything
|
||||||
|
$this->jqGridDataFinalize($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtual: jqGridData* functions
|
||||||
|
* - These set up the context for the jqGrid data, and will
|
||||||
|
* need to be overridden in the derived class for anything
|
||||||
|
* other than the most basic of grids.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataSetup(&$params) {
|
||||||
|
// Assume we're debugging.
|
||||||
|
// The actual jqGrid request will set this to false
|
||||||
|
$debug = true;
|
||||||
|
|
||||||
|
if (isset($this->passedArgs['debug']))
|
||||||
|
$debug = $this->passedArgs['debug'];
|
||||||
|
|
||||||
|
$params['debug'] = $debug;
|
||||||
|
|
||||||
|
if (!$debug) {
|
||||||
|
$this->layout = null;
|
||||||
|
$this->autoLayout = false;
|
||||||
|
$this->autoRender = false;
|
||||||
|
Configure::write('debug', '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Establish some defaults (except for serialized items)
|
||||||
|
$params = array_merge(array('page' => 1,
|
||||||
|
'rows' => 20),
|
||||||
|
$params);
|
||||||
|
|
||||||
|
// Unserialize our complex structure of fields
|
||||||
|
// This SHOULD always be set, except when debugging
|
||||||
|
if (isset($params['fields']))
|
||||||
|
$params['fields'] = unserialize($params['fields']);
|
||||||
|
else
|
||||||
|
$params['fields'] = array($this->{$this->modelClass}->alias
|
||||||
|
.'.'.
|
||||||
|
$this->{$this->modelClass}->primarKey);
|
||||||
|
|
||||||
|
// Unserialize the list of ids, if present.
|
||||||
|
if (isset($params['custom']))
|
||||||
|
$params['custom'] = unserialize($params['custom']);
|
||||||
|
else
|
||||||
|
$params['custom'] = null;
|
||||||
|
|
||||||
|
// Unserialize the list of ids, if present.
|
||||||
|
if (isset($params['idlist']))
|
||||||
|
$params['idlist'] = unserialize($params['idlist']);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataModel(&$params) {
|
||||||
|
return $this->{$this->modelClass};
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataCountTables(&$params, &$model) {
|
||||||
|
// If not overridden, we use the same tables to
|
||||||
|
// perform our count as we do to for the actual query
|
||||||
|
return $this->jqGridDataTables($params, $model);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
return array('contain' => false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataConditions(&$params, &$model) {
|
||||||
|
$searches = array();
|
||||||
|
|
||||||
|
if (isset($params['_search']) && $params['_search'] === 'true') {
|
||||||
|
if (isset($params['searchOper'])) {
|
||||||
|
$searches[] = array('op' => $params['searchOper'],
|
||||||
|
'field' => $params['searchField'],
|
||||||
|
'value' => $params['searchString']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// DOH! Crappy mechanism puts toolbar search terms
|
||||||
|
// directly into params as name/value pairs. No
|
||||||
|
// way to know which elements of params are search
|
||||||
|
// terms, so skipping this at the moment.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (isset($params['filt']) && $params['filt']) {
|
||||||
|
$searches[] = array('op' => 'bw',
|
||||||
|
'field' => $params['filtField'],
|
||||||
|
'value' => $params['filtValue']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ops = array('eq' => array('op' => null, 'pre' => '', 'post' => ''),
|
||||||
|
'ne' => array('op' => '<>', 'pre' => '', 'post' => ''),
|
||||||
|
'lt' => array('op' => '<', 'pre' => '', 'post' => ''),
|
||||||
|
'le' => array('op' => '<=', 'pre' => '', 'post' => ''),
|
||||||
|
'gt' => array('op' => '>', 'pre' => '', 'post' => ''),
|
||||||
|
'ge' => array('op' => '>=', 'pre' => '', 'post' => ''),
|
||||||
|
'bw' => array('op' => 'LIKE', 'pre' => '', 'post' => '%'),
|
||||||
|
'ew' => array('op' => 'LIKE', 'pre' => '%', 'post' => ''),
|
||||||
|
'cn' => array('op' => 'LIKE', 'pre' => '%', 'post' => '%'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$conditions = array();
|
||||||
|
foreach ($searches AS $search) {
|
||||||
|
$op = $ops[$search['op']];
|
||||||
|
$field = $search['field'] . ($op['op'] ? ' '.$op['op'] : '');
|
||||||
|
$value = $op['pre'] . $search['value']. $op['post'];
|
||||||
|
$conditions[] = array($field => $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['action']) && $params['action'] === 'idlist') {
|
||||||
|
if (count($params['idlist']))
|
||||||
|
$conditions[] = array($model->alias.'.'.$model->primaryKey => $params['idlist']);
|
||||||
|
else
|
||||||
|
$conditions[] = '0=1';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataFields(&$params, &$model) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataGroup(&$params, &$model) {
|
||||||
|
return $model->alias.'.'.$model->primaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
return $index ? array($index .' '. $direction) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataLimit(&$params, &$model, $start, $limit) {
|
||||||
|
return $start . ', ' . $limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataRecordCount(&$params, &$model, $query) {
|
||||||
|
return $model->find('count', $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataRecords(&$params, &$model, $query) {
|
||||||
|
return $model->find('all', $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordsPostProcess(&$params, &$model, &$records) {
|
||||||
|
$model_alias = $model->alias;
|
||||||
|
$id = $model->primaryKey;
|
||||||
|
|
||||||
|
foreach ($records AS &$record) {
|
||||||
|
$record['jqGrid_id'] = $record[$model_alias][$id];
|
||||||
|
// Add the calculated fields (if any), to the model fields
|
||||||
|
if (isset($record[0])) {
|
||||||
|
$record[$model_alias] += $record[0];
|
||||||
|
unset($record[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG PURPOSES ONLY!
|
||||||
|
//$params['records'] = $records;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
foreach ($links AS $table => $fields) {
|
||||||
|
$special = array('controller', 'id');
|
||||||
|
$controller = Inflector::pluralize(Inflector::underscore($table));
|
||||||
|
$id = 'id';
|
||||||
|
extract(array_intersect_key($fields, array_flip($special)));
|
||||||
|
foreach ($records AS &$record) {
|
||||||
|
if (!isset($record[$table]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (array_diff_key($fields, array_flip($special)) AS $field) {
|
||||||
|
if (!isset($record[$table][$id]) || !isset($record[$table][$field]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// DEBUG PURPOSES ONLY!
|
||||||
|
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
|
||||||
|
$record[$table][$field] =
|
||||||
|
'<A HREF="' .
|
||||||
|
Router::url(array('controller' => $controller,
|
||||||
|
'action' => 'view',
|
||||||
|
$record[$table][$id])) .
|
||||||
|
'">' .
|
||||||
|
$record[$table][$field] .
|
||||||
|
'</A>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOutputHeader(&$params, &$model) {
|
||||||
|
if ($params['debug']) {
|
||||||
|
ob_start();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
header("Content-type: text/xml;charset=utf-8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOutputSummary(&$params, &$model, $page, $total, $records) {
|
||||||
|
echo " <params><![CDATA[\n" . print_r($params, true) . "\n]]></params>\n";
|
||||||
|
echo " <page>$page</page>\n";
|
||||||
|
echo " <total>$total</total>\n";
|
||||||
|
echo " <records>$records</records>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOutputRecords(&$params, &$model, &$records) {
|
||||||
|
$id_field = 'jqGrid_id';
|
||||||
|
foreach ($records AS $record) {
|
||||||
|
$this->jqGridDataOutputRecord($params, $model, $record,
|
||||||
|
$record[$id_field], $params['fields']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOutputRecord(&$params, &$model, &$record, $id, $fields) {
|
||||||
|
echo " <row id='$id'>\n";
|
||||||
|
foreach ($fields AS $field) {
|
||||||
|
$this->jqGridDataOutputRecordField($params, $model, $record, $field);
|
||||||
|
}
|
||||||
|
echo " </row>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOutputRecordField(&$params, &$model, &$record, $field) {
|
||||||
|
if (preg_match("/\./", $field)) {
|
||||||
|
list($tbl, $col) = explode(".", $field);
|
||||||
|
$data = $record[$tbl][$col];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$data = $record[$model->alias][$field];
|
||||||
|
}
|
||||||
|
$this->jqGridDataOutputRecordCell($params, $model, $record, $field, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
|
||||||
|
// be sure to put text data in CDATA
|
||||||
|
if (preg_match("/^\d*$/", $data))
|
||||||
|
echo " <cell>$data</cell>\n";
|
||||||
|
else
|
||||||
|
echo " <cell><![CDATA[$data]]></cell>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataFinalize(&$params) {
|
||||||
|
if ($params['debug']) {
|
||||||
|
$xml = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
$xml = preg_replace("/&/", "&", $xml);
|
||||||
|
$xml = preg_replace("/</", "<", $xml);
|
||||||
|
$xml = preg_replace("/>/", ">", $xml);
|
||||||
|
|
||||||
|
echo ("\n<PRE>\n$xml\n</PRE>\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
/* SVN FILE: $Id: app_model.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application model for Cake.
|
||||||
|
*
|
||||||
|
* This file is application-wide model file. You can put all
|
||||||
|
* application-wide model-related methods here.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application model for Cake.
|
||||||
|
*
|
||||||
|
* Add your application-wide methods in the class below, your models
|
||||||
|
* will inherit them.
|
||||||
|
*
|
||||||
|
* @package cake
|
||||||
|
* @subpackage cake.app
|
||||||
|
*/
|
||||||
|
class AppModel extends Model {
|
||||||
|
|
||||||
|
var $actsAs = array('Containable', 'Linkable');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Enum Values
|
||||||
|
* Snippet v0.1.3
|
||||||
|
* http://cakeforge.org/snippet/detail.php?type=snippet&id=112
|
||||||
|
*
|
||||||
|
* Gets the enum values for MySQL 4 and 5 to use in selectTag()
|
||||||
|
*/
|
||||||
|
function getEnumValues($columnName=null, $respectDefault=false)
|
||||||
|
{
|
||||||
|
if ($columnName==null) { return array(); } //no field specified
|
||||||
|
|
||||||
|
//Get the name of the table
|
||||||
|
$db =& ConnectionManager::getDataSource($this->useDbConfig);
|
||||||
|
$tableName = $db->fullTableName($this, false);
|
||||||
|
|
||||||
|
//Get the values for the specified column (database and version specific, needs testing)
|
||||||
|
$result = $this->query("SHOW COLUMNS FROM {$tableName} LIKE '{$columnName}'");
|
||||||
|
|
||||||
|
//figure out where in the result our Types are (this varies between mysql versions)
|
||||||
|
$types = null;
|
||||||
|
if ( isset( $result[0]['COLUMNS']['Type'] ) ) { //MySQL 5
|
||||||
|
$types = $result[0]['COLUMNS']['Type']; $default = $result[0]['COLUMNS']['Default'];
|
||||||
|
}
|
||||||
|
elseif ( isset( $result[0][0]['Type'] ) ) { //MySQL 4
|
||||||
|
$types = $result[0][0]['Type']; $default = $result[0][0]['Default'];
|
||||||
|
}
|
||||||
|
else { //types return not accounted for
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the values
|
||||||
|
return array_flip(array_merge(array(''), // MySQL sets 0 to be the empty string
|
||||||
|
explode("','", preg_replace("/(enum)\('(.+?)'\)/","\\2", $types))
|
||||||
|
));
|
||||||
|
} //end getEnumValues
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: statMerge
|
||||||
|
* - Merges summary data from $b into $a
|
||||||
|
*/
|
||||||
|
|
||||||
|
function statsMerge (&$a, $b) {
|
||||||
|
if (!isset($b))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!isset($a)) {
|
||||||
|
$a = $b;
|
||||||
|
}
|
||||||
|
elseif (!is_array($a) && !is_array($b)) {
|
||||||
|
$a += $b;
|
||||||
|
}
|
||||||
|
elseif (is_array($a) && is_array($b)) {
|
||||||
|
foreach (array_intersect_key($a, $b) AS $k => $v)
|
||||||
|
{
|
||||||
|
if (preg_match("/^sp\./", $k))
|
||||||
|
$a[$k] .= '; ' . $b[$k];
|
||||||
|
else
|
||||||
|
$this->statsMerge($a[$k], $b[$k]);
|
||||||
|
}
|
||||||
|
$a = array_merge($a, array_diff_key($b, $a));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
die ("Can't yet merge array and non-array stats");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: dateFormatBeforeSave
|
||||||
|
* - convert dates to database format
|
||||||
|
*/
|
||||||
|
|
||||||
|
function dateFormatBeforeSave($dateString) {
|
||||||
|
return date('Y-m-d', strtotime($dateString));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
Book Keeping Challenges / Issues
|
|
||||||
- Chart of Accounts is not sufficient
|
|
||||||
- One payment can go towards more than one charge
|
|
||||||
- One charge can be paid for by more than one payment
|
|
||||||
- Need to know: how much money does customer owe?
|
|
||||||
- Need to know: how much money has customer been charged for "Rent"?
|
|
||||||
- Need to know: how much money has customer paid towards "Rent" (nothing else)?
|
|
||||||
|
|
||||||
|
|
||||||
- Reverse a charge
|
|
||||||
To make charge reversal work, I'm presently issuing a credit note
|
|
||||||
(transaction) that has 3 ledger entries:
|
|
||||||
Debit charged account - Credit A/R
|
|
||||||
Debit A/R - Credit "Credit" account
|
|
||||||
Debit "Credit" account - Credit A/R
|
|
||||||
And 3 statement entries:
|
|
||||||
Reversal on charged account
|
|
||||||
Negative Disbursement on "Credit" account
|
|
||||||
Positive Disbursement on "Credit" account
|
|
||||||
|
|
||||||
Obviously, the two "Credit" account ledger entries cancel each other
|
|
||||||
out. However, the monies need to be reversed in the A/R account, and a
|
|
||||||
previous transaction will have already performed an A/R credit and so
|
|
||||||
the two A/R credits will create an imbalance in A/R unless we move
|
|
||||||
those funds to our "Credit" account. The "Credit" account statement
|
|
||||||
entries are needed to undo any previous disbursement to the charge
|
|
||||||
being reversed, and then to re-disburse those funds to a different
|
|
||||||
charge (or possibly just a Surplus entry if no other charges exist.)
|
|
||||||
|
|
||||||
|
|
||||||
Question
|
|
||||||
- What should be recorded with this charge reversal?
|
|
||||||
Charge of $5 for "Parking"
|
|
||||||
Charge of $6 for "Rent"
|
|
||||||
Payment of $6
|
|
||||||
Reverse the $5 "Parking" charge
|
|
||||||
|
|
||||||
- What should be recorded with this charge reversal?
|
|
||||||
Charge of $5 for "Parking"
|
|
||||||
Charge of $6 for "Rent"
|
|
||||||
Charge of $7 for "Pets"
|
|
||||||
Payment of $13
|
|
||||||
Reverse the $5 "Parking" charge
|
|
||||||
|
|
||||||
- What should be recorded with this charge reversal?
|
|
||||||
Charge of $5 for "Parking"
|
|
||||||
Charge of $6 for "Rent"
|
|
||||||
Charge of $7 for "Pets"
|
|
||||||
Payment of $18
|
|
||||||
Reverse the $5 "Parking" charge
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
@echo off
|
|
||||||
mysql --user=pmgr --password=pmgruser < %~dp0\db\property_manager.sql
|
|
||||||
echo Done!
|
|
||||||
@@ -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';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
*
|
*
|
||||||
* $uninflectedPlural = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox');
|
* $uninflectedPlural = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox');
|
||||||
*/
|
*/
|
||||||
$uninflectedPlural = array('.*cash');
|
$uninflectedPlural = array();
|
||||||
/**
|
/**
|
||||||
* This is a key => value array of plural irregular words.
|
* This is a key => value array of plural irregular words.
|
||||||
* If key matches then the value is returned.
|
* If key matches then the value is returned.
|
||||||
@@ -26,30 +26,14 @@
|
|||||||
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
* @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
|
* @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.
|
* Here, we are connecting '/' (base path) to controller called 'Pages',
|
||||||
* It's hardcoded to map #1, but at some point we'll implement
|
* its action called 'display', and we pass a param to select the view file
|
||||||
* a login mechanism and the default path will be to log on instead.
|
* to use (in this case, /app/views/pages/home.ctp)...
|
||||||
*/
|
*/
|
||||||
Router::connect('/', $default_path);
|
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
|
||||||
|
/**
|
||||||
/*
|
* ...and connect the rest of 'Pages' controller's urls.
|
||||||
* Route for sandbox functionality
|
|
||||||
*/
|
*/
|
||||||
Router::connect('/sand',
|
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
|
||||||
array('sand_route' => true) + $default_path);
|
|
||||||
Router::connect('/sand/:controller/:action/*',
|
|
||||||
array('sand_route' => true, 'action' => 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));
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class AccountsController extends AppController {
|
||||||
|
|
||||||
|
var $uses = array('Account', 'LedgerEntry');
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Accounts', 'header' => true),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'accounts', 'action' => 'all')),
|
||||||
|
array('name' => 'Asset', 'url' => array('controller' => 'accounts', 'action' => 'asset')),
|
||||||
|
array('name' => 'Liability', 'url' => array('controller' => 'accounts', 'action' => 'liability')),
|
||||||
|
array('name' => 'Equity', 'url' => array('controller' => 'accounts', 'action' => 'equity')),
|
||||||
|
array('name' => 'Income', 'url' => array('controller' => 'accounts', 'action' => 'income')),
|
||||||
|
array('name' => 'Expense', 'url' => array('controller' => 'accounts', 'action' => 'expense')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: index / asset / liability / equity / income / expense / all
|
||||||
|
* - Generate a chart of accounts
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->all(); }
|
||||||
|
function asset() { $this->jqGridView('Asset Accounts'); }
|
||||||
|
function liability() { $this->jqGridView('Liability Accounts'); }
|
||||||
|
function equity() { $this->jqGridView('Equity Accounts'); }
|
||||||
|
function income() { $this->jqGridView('Income Accounts'); }
|
||||||
|
function expense() { $this->jqGridView('Expense Accounts'); }
|
||||||
|
function all() { $this->jqGridView('All Accounts', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataSetup(&$params) {
|
||||||
|
parent::jqGridDataSetup($params);
|
||||||
|
if (!isset($params['action']))
|
||||||
|
$params['action'] = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataCountTables(&$params, &$model) {
|
||||||
|
return parent::jqGridDataTables($params, $model);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('link' =>
|
||||||
|
array(// Models
|
||||||
|
'CurrentLedger' => array
|
||||||
|
(// Models
|
||||||
|
'LedgerEntry'
|
||||||
|
/* REVISIT <AP> 20090615:
|
||||||
|
* I'll remove this 'conditions' section on a future checkin,
|
||||||
|
* after I've proven out the %{MODEL_ALIAS} feature will be
|
||||||
|
* sticking around.
|
||||||
|
|
||||||
|
=> array
|
||||||
|
('conditions' =>
|
||||||
|
array('OR' =>
|
||||||
|
array('LedgerEntry.debit_ledger_id = CurrentLedger.id',
|
||||||
|
'LedgerEntry.credit_ledger_id = CurrentLedger.id'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
* END REVISIT
|
||||||
|
*/
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataFields(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('Account.*',
|
||||||
|
'SUM(IF(LedgerEntry.debit_ledger_id = CurrentLedger.id,
|
||||||
|
LedgerEntry.amount, NULL)) AS debits',
|
||||||
|
'SUM(IF(LedgerEntry.credit_ledger_id = CurrentLedger.id,
|
||||||
|
LedgerEntry.amount, NULL)) AS credits',
|
||||||
|
"SUM(IF(Account.type IN ('ASSET', 'EXPENSE'),
|
||||||
|
IF(LedgerEntry.debit_ledger_id = CurrentLedger.id, 1, -1),
|
||||||
|
IF(LedgerEntry.credit_ledger_id = CurrentLedger.id, 1, -1)
|
||||||
|
) * IF(LedgerEntry.amount, LedgerEntry.amount, 0)
|
||||||
|
) AS balance",
|
||||||
|
'COUNT(LedgerEntry.id) AS entries');
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if (in_array($params['action'], array('asset', 'liability', 'equity', 'income', 'expense'))) {
|
||||||
|
$conditions[] = array('Account.type' => strtoupper($params['action']));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Account'] = array('name');
|
||||||
|
return parent::jqGridRecordLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific account
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get details about the account and its ledgers (no ledger entries yet)
|
||||||
|
$account = $this->Account->find
|
||||||
|
('first',
|
||||||
|
array('contain' =>
|
||||||
|
array(// Models
|
||||||
|
'CurrentLedger' =>
|
||||||
|
array('fields' => array('id', 'sequence')),
|
||||||
|
|
||||||
|
'Ledger' =>
|
||||||
|
array('order' => array('Ledger.open_stamp' => 'DESC')),
|
||||||
|
),
|
||||||
|
'conditions' => array(array('Account.id' => $id)),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get all ledger entries of the CURRENT ledger
|
||||||
|
$entries = $this->Account->findLedgerEntries($id);
|
||||||
|
$account['CurrentLedger']['LedgerEntry'] = $entries['Entries'];
|
||||||
|
|
||||||
|
// Summarize each ledger
|
||||||
|
foreach($account['Ledger'] AS &$ledger)
|
||||||
|
$ledger = array_merge($ledger,
|
||||||
|
$this->Account->Ledger->stats($ledger['id']));
|
||||||
|
|
||||||
|
// Obtain stats across ALL ledgers for the summary infobox
|
||||||
|
$stats = $this->Account->stats($id, true);
|
||||||
|
$stats = $stats['Ledger'];
|
||||||
|
|
||||||
|
// Prepare to render
|
||||||
|
$title = 'Account: ' . $account['Account']['name'];
|
||||||
|
$this->set(compact('account', 'title', 'stats'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: index / all
|
||||||
|
* - Generate a listing of contacts
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->all(); }
|
||||||
|
function all() { $this->jqGridView('All Contacts', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
$order = parent::jqGridDataOrder($params, $model, $index, $direction);
|
||||||
|
if ($index === 'Contact.last_name') {
|
||||||
|
$order[] = 'Contact.first_name ' . $direction;
|
||||||
|
}
|
||||||
|
if ($index === 'Contact.first_name') {
|
||||||
|
$order[] = 'Contact.last_name ' . $direction;
|
||||||
|
}
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific contact
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$contact = $this->Contact->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'ContactPhone',
|
||||||
|
'ContactEmail',
|
||||||
|
'ContactAddress',
|
||||||
|
'Customer'),
|
||||||
|
|
||||||
|
'conditions' => array('Contact.id' => $id),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = $contact['Contact']['display_name'];
|
||||||
|
$this->set(compact('contact', 'title'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,250 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class CustomersController extends AppController {
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Tenants', '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')),
|
||||||
|
);
|
||||||
|
|
||||||
|
//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 tenants
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->current(); }
|
||||||
|
function current() { $this->jqGridView('Current Tenants'); }
|
||||||
|
function past() { $this->jqGridView('Past Tenants'); }
|
||||||
|
function all() { $this->jqGridView('All Tenants', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataSetup(&$params) {
|
||||||
|
parent::jqGridDataSetup($params);
|
||||||
|
if (!isset($params['action']))
|
||||||
|
$params['action'] = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('link' =>
|
||||||
|
array(// Models
|
||||||
|
'PrimaryContact',
|
||||||
|
'CurrentLease' => array('fields' => array()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataFields(&$params, &$model) {
|
||||||
|
return array('Customer.*',
|
||||||
|
'COUNT(CurrentLease.id) AS lease_count');
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if ($params['action'] === 'current') {
|
||||||
|
$conditions[] = 'CurrentLease.id IS NOT NULL';
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'past') {
|
||||||
|
$conditions[] = 'CurrentLease.id IS NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
$order = parent::jqGridDataOrder($params, $model, $index, $direction);
|
||||||
|
if ($index === 'PrimaryContact.last_name') {
|
||||||
|
$order[] = 'PrimaryContact.first_name ' . $direction;
|
||||||
|
}
|
||||||
|
if ($index === 'PrimaryContact.first_name') {
|
||||||
|
$order[] = 'PrimaryContact.last_name ' . $direction;
|
||||||
|
}
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataRecordCount(&$params, &$model, $query) {
|
||||||
|
|
||||||
|
// 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, which will destroy the count,
|
||||||
|
// whether we omit the group by or leave it in.
|
||||||
|
// So, build a fresh query for counting.
|
||||||
|
|
||||||
|
$query['conditions'] = parent::jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
$count = $model->find('count',
|
||||||
|
array_merge(array('link' => array_diff_key($query['link'],
|
||||||
|
array('CurrentLease'=>1))),
|
||||||
|
array_diff_key($query, array('link'=>1))));
|
||||||
|
|
||||||
|
if ($params['action'] === 'all')
|
||||||
|
return $count;
|
||||||
|
|
||||||
|
$query['conditions'][] = 'CurrentLease.id IS NULL';
|
||||||
|
$count_past = $model->find('count', $query);
|
||||||
|
|
||||||
|
// Since we can't easily count 'current' directly, we
|
||||||
|
// can quickly derive it since 'current' customers
|
||||||
|
// are mutually exclusive to 'past' customers.
|
||||||
|
if ($params['action'] == 'current')
|
||||||
|
$count = $count - $count_past;
|
||||||
|
elseif ($params['action'] == 'past') {
|
||||||
|
$count = $count_past;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataRecords(&$params, &$model, $query) {
|
||||||
|
$customers = parent::jqGridDataRecords($params, $model, $query);
|
||||||
|
|
||||||
|
// Get the balance on each customer.
|
||||||
|
foreach ($customers AS &$customer) {
|
||||||
|
$stats = $this->Customer->stats($customer['Customer']['id']);
|
||||||
|
$customer['Customer']['balance'] = $stats['balance'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $customers;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Customer'] = array('name');
|
||||||
|
return parent::jqGridRecordLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* 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'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$customer = $this->Customer->details($id);
|
||||||
|
|
||||||
|
$outstanding_balance = $customer['stats']['balance'];
|
||||||
|
$outstanding_deposit = $customer['deposits']['summary']['balance'];
|
||||||
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Payment', 'url' => array('action' => 'payment', $id));
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Move-Out', 'url' => array('controller' => 'units', 'action' => 'move-out'));
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = $customer['Customer']['name'];
|
||||||
|
$this->set(compact('customer', 'title',
|
||||||
|
'outstanding_balance',
|
||||||
|
'outstanding_deposit'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: payment
|
||||||
|
* - Sets up the payment entry page for the given customer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function payment($id = null) {
|
||||||
|
/* if (!$id) { */
|
||||||
|
/* $this->Session->setFlash(__('Invalid Item.', true)); */
|
||||||
|
/* $this->redirect(array('action'=>'index')); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* if ($this->RequestHandler->isPost()) { */
|
||||||
|
/* pr($this->data); */
|
||||||
|
/* //$this->redirect(array('action'=>'index')); */
|
||||||
|
/* $customer = $this->data; */
|
||||||
|
/* } */
|
||||||
|
if (isset($id)) {
|
||||||
|
$this->Customer->recursive = -1;
|
||||||
|
$customer = $this->Customer->read(null, $id);
|
||||||
|
$customer = $customer['Customer'];
|
||||||
|
$unreconciled = $this->Customer->findUnreconciledLedgerEntries($id);
|
||||||
|
$charges = $unreconciled['debit'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$customer = null;
|
||||||
|
$charges = array('balance' => 0, 'entry' => array());
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = 'Payment Entry';
|
||||||
|
$this->set(compact('customer', 'charges', 'title'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: unreconciledEntries
|
||||||
|
* - 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->findUnreconciledLedgerEntries($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->reconcileNewLedgerEntry($cust_id, 'credit', $amount);
|
||||||
|
|
||||||
|
$opts = array();
|
||||||
|
//$opts['format'] = 'tags';
|
||||||
|
echo $xml->header();
|
||||||
|
echo $xml->serialize($unreconciled, $opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
<?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->jqGridView('Active Leases'); }
|
||||||
|
function closed() { $this->jqGridView('Closed Leases'); }
|
||||||
|
function all() { $this->jqGridView('All Leases', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataSetup(&$params) {
|
||||||
|
parent::jqGridDataSetup($params);
|
||||||
|
if (!isset($params['action']))
|
||||||
|
$params['action'] = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('link' => array('Unit' => array('fields' => array('Unit.id', 'Unit.name')),
|
||||||
|
'Customer' => array('fields' => array('Customer.id', 'Customer.name'))));
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if ($params['action'] === 'active') {
|
||||||
|
$conditions[] = 'Lease.close_date IS NULL';
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'closed') {
|
||||||
|
$conditions[] = 'Lease.close_date IS NOT NULL';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Lease'] = array('number');
|
||||||
|
$links['Unit'] = array('name');
|
||||||
|
$links['Customer'] = array('name');
|
||||||
|
return parent::jqGridRecordLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataRecords(&$params, &$model, $query) {
|
||||||
|
$leases = parent::jqGridDataRecords($params, $model, $query);
|
||||||
|
|
||||||
|
// Get the balance on each lease.
|
||||||
|
foreach ($leases AS &$lease) {
|
||||||
|
$stats = $this->Lease->stats($lease['Lease']['id']);
|
||||||
|
$lease['Lease']['balance'] = $stats['balance'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $leases;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* 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)),
|
||||||
|
'limit' => 2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
$deposits = $this->Lease->findSecurityDeposits($lease['Lease']['id']);
|
||||||
|
$outstanding_deposit = $deposits['summary']['balance'];
|
||||||
|
|
||||||
|
// Prepare to render
|
||||||
|
$title = 'Lease: #' . $lease['Lease']['id'];
|
||||||
|
$this->set(compact('lease', 'title',
|
||||||
|
'outstanding_deposit',
|
||||||
|
'outstanding_balance'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,344 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class LedgerEntriesController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataSetup(&$params) {
|
||||||
|
parent::jqGridDataSetup($params);
|
||||||
|
if (isset($params['custom']['ar_account'])) {
|
||||||
|
$params['custom']['account_id'] =
|
||||||
|
$this->LedgerEntry->DebitLedger->Account->accountReceivableAccountID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
$link =
|
||||||
|
array(// Models
|
||||||
|
'Transaction' =>
|
||||||
|
array('fields' => array('id', 'stamp'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'MonetarySource' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Customer' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Lease' =>
|
||||||
|
array('fields' => array('id', 'number'),
|
||||||
|
'Unit' =>
|
||||||
|
array('fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($params['custom']['account_ftype'])) {
|
||||||
|
$ftype = $params['custom']['account_ftype'];
|
||||||
|
$ftype = ucfirst($ftype);
|
||||||
|
//$ftype = $this->LedgerEntry->DebitLedger->Account->fundamentalOpposite($ftype);
|
||||||
|
$link[$ftype . 'Ledger'] =
|
||||||
|
array('fields' => array('id', 'sequence'),
|
||||||
|
'Account' => array('class' => 'Account',
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
elseif (isset($params['custom']['ledger_id'])) {
|
||||||
|
$ledger_id = $params['custom']['ledger_id'];
|
||||||
|
$link['Ledger'] =
|
||||||
|
array('fields' => array('id', 'sequence'),
|
||||||
|
'conditions' => ("Ledger.id = IF(LedgerEntry.debit_ledger_id = $ledger_id," .
|
||||||
|
" LedgerEntry.credit_ledger_id," .
|
||||||
|
" LedgerEntry.debit_ledger_id)"),
|
||||||
|
'Account' => array(
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$link['DebitLedger'] =
|
||||||
|
array('fields' => array('id', 'sequence'),
|
||||||
|
'DebitAccount' => array('class' => 'Account',
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$link['CreditLedger'] =
|
||||||
|
array('fields' => array('id', 'sequence'),
|
||||||
|
'CreditAccount' => array('class' => 'Account',
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['custom']['account_id'])) {
|
||||||
|
$account_id = $params['custom']['account_id'];
|
||||||
|
$link['Ledger'] =
|
||||||
|
array('fields' => array('id', 'sequence'),
|
||||||
|
'conditions' => ("Ledger.id = IF(DebitLedger.account_id = $account_id," .
|
||||||
|
" LedgerEntry.credit_ledger_id," .
|
||||||
|
" LedgerEntry.debit_ledger_id)"),
|
||||||
|
'Account' => array(
|
||||||
|
'fields' => array('id', 'name'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['custom']['reconcile_id'])) {
|
||||||
|
$ftype = $params['custom']['account_ftype'];
|
||||||
|
$ftype = $this->LedgerEntry->DebitLedger->Account->fundamentalOpposite($ftype);
|
||||||
|
$ftype = ucfirst($ftype);
|
||||||
|
$link[$ftype.'ReconciliationLedgerEntry'] =
|
||||||
|
array('fields' => array('Reconciliation.amount'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('link' => $link);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataFields(&$params, &$model) {
|
||||||
|
$ledger_id = (isset($params['custom']['ledger_id'])
|
||||||
|
? $params['custom']['ledger_id']
|
||||||
|
: null);
|
||||||
|
$account_id = (isset($params['custom']['account_id'])
|
||||||
|
? $params['custom']['account_id']
|
||||||
|
: null);
|
||||||
|
$account_type = (isset($params['custom']['account_type'])
|
||||||
|
? $params['custom']['account_type']
|
||||||
|
: null);
|
||||||
|
|
||||||
|
return $model->ledgerContextFields2($ledger_id, $account_id, $account_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataConditions(&$params, &$model) {
|
||||||
|
$ledger_id = (isset($params['custom']['ledger_id'])
|
||||||
|
? $params['custom']['ledger_id']
|
||||||
|
: null);
|
||||||
|
$account_type = (isset($params['custom']['account_type'])
|
||||||
|
? $params['custom']['account_type']
|
||||||
|
: null);
|
||||||
|
|
||||||
|
$conditions = parent::jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if ($params['action'] === 'ledger') {
|
||||||
|
$conditions[] = $model->ledgerContextConditions($ledger_id, $account_type);
|
||||||
|
}
|
||||||
|
if (isset($params['custom']['reconcile_id'])) {
|
||||||
|
$ftype = $params['custom']['account_ftype'];
|
||||||
|
//$ftype = $this->LedgerEntry->DebitLedger->Account->fundamentalOpposite($ftype);
|
||||||
|
$conditions[] = array('Reconciliation.'.$ftype.'_ledger_entry_id' => $params['custom']['reconcile_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['custom']['account_id'])) {
|
||||||
|
$conditions[] =
|
||||||
|
array('OR' =>
|
||||||
|
array(array('CreditAccount.id' => $params['custom']['account_id']),
|
||||||
|
array('DebitAccount.id' => $params['custom']['account_id'])));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['custom']['customer_id'])) {
|
||||||
|
$conditions[] =
|
||||||
|
array('Customer.id' => $params['custom']['customer_id']);
|
||||||
|
|
||||||
|
/* $Account = new Account(); */
|
||||||
|
/* if (isset($params['custom']['account_ftype']) || */
|
||||||
|
/* isset($params['custom']['ledger_id'])) { */
|
||||||
|
/* $conditions[] = */
|
||||||
|
/* array('OR' => array('Account.id' => $Account->invoiceAccountID(), */
|
||||||
|
/* 'Account.id' => $Account->receiptAccountID())); */
|
||||||
|
/* } else { */
|
||||||
|
/* $conditions[] = */
|
||||||
|
/* array('OR' => array('DebitAccount.id' => $Account->invoiceAccountID(), */
|
||||||
|
/* //'CreditAccount.id' => $Account->invoiceAccountID(), */
|
||||||
|
/* //'DebitAccount.id' => $Account->receiptAccountID(), */
|
||||||
|
/* 'CreditAccount.id' => $Account->receiptAccountID(), */
|
||||||
|
/* )); */
|
||||||
|
/* } */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['custom']['lease_id'])) {
|
||||||
|
$conditions[] =
|
||||||
|
array('Lease.id' => $params['custom']['lease_id']);
|
||||||
|
|
||||||
|
/* $Account = new Account(); */
|
||||||
|
/* if (isset($params['custom']['account_ftype']) || */
|
||||||
|
/* isset($params['custom']['ledger_id'])) { */
|
||||||
|
/* $conditions[] = */
|
||||||
|
/* array('OR' => array('Account.id' => $Account->invoiceAccountID(), */
|
||||||
|
/* 'Account.id' => $Account->receiptAccountID())); */
|
||||||
|
/* } else { */
|
||||||
|
/* $conditions[] = */
|
||||||
|
/* array('OR' => array('DebitAccount.id' => $Account->invoiceAccountID(), */
|
||||||
|
/* //'CreditAccount.id' => $Account->invoiceAccountID(), */
|
||||||
|
/* //'DebitAccount.id' => $Account->receiptAccountID(), */
|
||||||
|
/* 'CreditAccount.id' => $Account->receiptAccountID(), */
|
||||||
|
/* )); */
|
||||||
|
/* } */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($params['custom']['transaction_id'])) {
|
||||||
|
$conditions[] =
|
||||||
|
array('Transaction.id' => $params['custom']['transaction_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Transaction'] = array('id');
|
||||||
|
$links['LedgerEntry'] = array('id');
|
||||||
|
$links['Account'] = array('controller' => 'accounts', 'name');
|
||||||
|
$links['DebitAccount'] = array('controller' => 'accounts', 'name');
|
||||||
|
$links['CreditAccount'] = array('controller' => 'accounts', 'name');
|
||||||
|
$links['MonetarySource'] = array('name');
|
||||||
|
$links['Customer'] = array('name');
|
||||||
|
$links['Lease'] = array('number');
|
||||||
|
$links['Unit'] = array('name');
|
||||||
|
return parent::jqGridRecordLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataGroup(&$params, &$model) {
|
||||||
|
if (isset($params['custom']['notxgroup']))
|
||||||
|
return parent::jqGridDataGroup($params, $model);
|
||||||
|
|
||||||
|
return $model->alias.'.transaction_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
/* if ($index === 'balance') */
|
||||||
|
/* return ($index .' '. $direction); */
|
||||||
|
$order = parent::jqGridDataOrder($params, $model, $index, $direction);
|
||||||
|
|
||||||
|
if ($index === 'Transaction.stamp') {
|
||||||
|
$order[] = 'LedgerEntry.id ' . $direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordsPostProcess(&$params, &$model, &$records) {
|
||||||
|
parent::jqGridRecordsPostProcess($params, $model, $records);
|
||||||
|
|
||||||
|
$subtotal = 0;
|
||||||
|
foreach ($records AS &$record) {
|
||||||
|
$amount = (isset($record['LedgerEntry']['balance'])
|
||||||
|
? $record['LedgerEntry']['balance']
|
||||||
|
: $record['LedgerEntry']['amount']);
|
||||||
|
$record['LedgerEntry']['subtotal'] = ($subtotal += $amount);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
// Experiment to minimize columns by putting the monetary source
|
||||||
|
// as the Account, when available
|
||||||
|
if ($record['MonetarySource']['name'])
|
||||||
|
$record['Account']['name'] = $record['MonetarySource']['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOutputRecordCell(&$params, &$model, &$record, $field, $data) {
|
||||||
|
/* if ($field === 'CreditAccount.name') { */
|
||||||
|
/* $data .= '-OK'; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
parent::jqGridDataOutputRecordCell($params, $model, $record, $field, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* 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 LedgerEntry and related fields
|
||||||
|
$entry = $this->LedgerEntry->find
|
||||||
|
('first',
|
||||||
|
array('contain' => array('MonetarySource.id',
|
||||||
|
'MonetarySource.name',
|
||||||
|
'MonetarySource.MonetaryType.id',
|
||||||
|
'Transaction.id',
|
||||||
|
'Transaction.stamp',
|
||||||
|
'DebitLedger.id',
|
||||||
|
'DebitLedger.sequence',
|
||||||
|
'DebitLedger.account_id',
|
||||||
|
'CreditLedger.id',
|
||||||
|
'CreditLedger.sequence',
|
||||||
|
'CreditLedger.account_id',
|
||||||
|
'Customer.id',
|
||||||
|
'Customer.name',
|
||||||
|
'Lease.id',
|
||||||
|
),
|
||||||
|
|
||||||
|
'fields' => array('LedgerEntry.id',
|
||||||
|
'LedgerEntry.amount',
|
||||||
|
'LedgerEntry.comment'),
|
||||||
|
|
||||||
|
'conditions' => array('LedgerEntry.id' => $id),
|
||||||
|
));
|
||||||
|
//pr($entry);
|
||||||
|
|
||||||
|
// Because 'DebitLedger' and 'CreditLedger' both relate to 'Account',
|
||||||
|
// CakePHP will not include them in the LedgerEntry->find (or so it
|
||||||
|
// seems). We'll have to break out each Account separately.
|
||||||
|
|
||||||
|
// Get the Account from DebitLedger
|
||||||
|
$entry['DebitLedger'] += $this->LedgerEntry->DebitLedger->Account->find
|
||||||
|
('first',
|
||||||
|
array('contain' => true,
|
||||||
|
'fields' => array('Account.id', 'Account.name', 'Account.type', 'Account.trackable'),
|
||||||
|
'conditions' => array('Account.id' => $entry['DebitLedger']['account_id']),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Get the Account from CreditLedger
|
||||||
|
$entry['CreditLedger'] += $this->LedgerEntry->CreditLedger->Account->find
|
||||||
|
('first',
|
||||||
|
array('contain' => true,
|
||||||
|
'fields' => array('Account.id', 'Account.name', 'Account.type', 'Account.trackable'),
|
||||||
|
'conditions' => array('Account.id' => $entry['CreditLedger']['account_id']),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Get the reconciliation balances for this ledger entry
|
||||||
|
$stats = $this->LedgerEntry->stats($id);
|
||||||
|
if ($entry['DebitLedger']['Account']['trackable'])
|
||||||
|
$stats['debit_amount_remaining'] = $entry['LedgerEntry']['amount'] - $stats['debit_amount_reconciled'];
|
||||||
|
if ($entry['CreditLedger']['Account']['trackable'])
|
||||||
|
$stats['credit_amount_remaining'] = $entry['LedgerEntry']['amount'] - $stats['credit_amount_reconciled'];
|
||||||
|
//pr($stats);
|
||||||
|
|
||||||
|
$reconciled = $this->LedgerEntry->findReconciledLedgerEntries($id);
|
||||||
|
//pr($reconciled);
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = "Ledger Entry #{$entry['LedgerEntry']['id']}";
|
||||||
|
$this->set(compact('entry', 'title', 'reconciled', 'stats'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class LedgersController extends AppController {
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Ledgers', 'header' => true),
|
||||||
|
array('name' => 'Current', 'url' => array('controller' => 'ledgers', 'action' => 'current')),
|
||||||
|
array('name' => 'Closed', 'url' => array('controller' => 'ledgers', 'action' => 'closed')),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'ledgers', 'action' => 'all')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: index / current / closed / all
|
||||||
|
* - Generate a list of ledgers
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->all(); }
|
||||||
|
function current() { $this->jqGridView('Current Ledgers'); }
|
||||||
|
function closed() { $this->jqGridView('Closed Ledgers'); }
|
||||||
|
function all() { $this->jqGridView('All Ledgers', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataSetup(&$params) {
|
||||||
|
parent::jqGridDataSetup($params);
|
||||||
|
if (!isset($params['action']))
|
||||||
|
$params['action'] = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataCountTables(&$params, &$model) {
|
||||||
|
return array('contain' => false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('link' =>
|
||||||
|
array(// Models
|
||||||
|
'Account',
|
||||||
|
'LedgerEntry',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataFields(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('Ledger.*',
|
||||||
|
'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence',
|
||||||
|
'SUM(IF(LedgerEntry.debit_ledger_id = Ledger.id,
|
||||||
|
LedgerEntry.amount, NULL)) AS debits',
|
||||||
|
'SUM(IF(LedgerEntry.credit_ledger_id = Ledger.id,
|
||||||
|
LedgerEntry.amount, NULL)) AS credits',
|
||||||
|
"SUM(IF(Account.type IN ('ASSET', 'EXPENSE'),
|
||||||
|
IF(LedgerEntry.debit_ledger_id = Ledger.id, 1, -1),
|
||||||
|
IF(LedgerEntry.credit_ledger_id = Ledger.id, 1, -1)
|
||||||
|
) * IF(LedgerEntry.amount, LedgerEntry.amount, 0)
|
||||||
|
) AS balance",
|
||||||
|
'COUNT(LedgerEntry.id) AS entries');
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::jqGridDataConditions($params, $model);
|
||||||
|
|
||||||
|
if ($params['action'] === 'current') {
|
||||||
|
$conditions[] = array('NOT' => array('Ledger.closed'));
|
||||||
|
}
|
||||||
|
elseif ($params['action'] === 'closed') {
|
||||||
|
$conditions[] = 'Ledger.closed';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
$id_sequence = false;
|
||||||
|
if ($index === 'id_sequence') {
|
||||||
|
$id_sequence = true;
|
||||||
|
$index = 'Ledger.account_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
$order = parent::jqGridDataOrder($params, $model, $index, $direction);
|
||||||
|
|
||||||
|
if ($id_sequence) {
|
||||||
|
$order[] = 'Ledger.sequence ' . $direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Ledger'] = array('id_sequence');
|
||||||
|
$links['Account'] = array('name');
|
||||||
|
return parent::jqGridRecordLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific ledger
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get details about the ledger itself (no entries yet)
|
||||||
|
$ledger = $this->Ledger->find
|
||||||
|
('first',
|
||||||
|
array('contain' =>
|
||||||
|
array(// Models
|
||||||
|
'Account',
|
||||||
|
),
|
||||||
|
'conditions' => array(array('Ledger.id' => $id)),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get ledger stats for our summary box
|
||||||
|
$stats = $this->Ledger->stats($id);
|
||||||
|
|
||||||
|
// OK, set our view variables and render!
|
||||||
|
$title = 'Ledger: #' . $ledger['Account']['id'] .'-'. $ledger['Ledger']['sequence'];
|
||||||
|
$this->set(compact('ledger', 'title', 'stats'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,28 +15,28 @@ class MapsController extends AppController {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
function index() { $this->all(); }
|
function index() { $this->all(); }
|
||||||
function all() { $this->gridView('All Maps', 'all'); }
|
function all() { $this->jqGridView('All Maps', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
* virtuals: gridData
|
* virtuals: jqGridData
|
||||||
* - With the application controller handling the gridData action,
|
* - With the application controller handling the jqGridData action,
|
||||||
* these virtual functions ensure that the correct data is passed
|
* these virtual functions ensure that the correct data is passed
|
||||||
* to jqGrid.
|
* to jqGrid.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function gridDataTables(&$params, &$model) {
|
function jqGridDataTables(&$params, &$model) {
|
||||||
return array
|
return array
|
||||||
('link' => array('SiteArea' => array('fields' => array('SiteArea.id', 'SiteArea.name')),
|
('link' => array('SiteArea' => array('fields' => array('SiteArea.id', 'SiteArea.name')),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
$links['Map'] = array('id');
|
$links['Map'] = array('id');
|
||||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
return parent::jqGridRecordLinks($params, $model, $records, $links);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -52,9 +52,7 @@ 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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -86,34 +84,10 @@ 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
|
||||||
@@ -138,7 +112,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 +131,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,18 +142,30 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporary function
|
||||||
|
function unitStatusList() {
|
||||||
|
return
|
||||||
|
array('DELETED' => array(),
|
||||||
|
'DAMAGED' => array(),
|
||||||
|
'COMPANY' => array(),
|
||||||
|
'UNAVAILABLE' => array(),
|
||||||
|
'RESERVED' => array(),
|
||||||
|
'DIRTY' => array(),
|
||||||
|
'VACANT' => array(),
|
||||||
|
'OCCUPIED' => array(),
|
||||||
|
'LATE' => array(),
|
||||||
|
'LOCKED' => array(),
|
||||||
|
'LIENED' => array(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
**************************************************************************
|
**************************************************************************
|
||||||
@@ -188,12 +175,9 @@ 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->unitStatusList();
|
||||||
$occupied_key = array_search('OCCUPIED', $status);
|
$cols = 6;
|
||||||
array_splice($status, $occupied_key+1, 0, array('LATE'));
|
$rows = (int)((count($status) + $cols - 1) / $cols);
|
||||||
|
|
||||||
$rows = 2;
|
|
||||||
$cols = (int)((count($status) + $rows - 1) / $rows);
|
|
||||||
|
|
||||||
$info = array('units' => array());
|
$info = array('units' => array());
|
||||||
|
|
||||||
@@ -221,7 +205,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 => $color) {
|
||||||
$info['units'][] = array('name' => $code,
|
$info['units'][] = array('name' => $code,
|
||||||
'status' => $code,
|
'status' => $code,
|
||||||
'width' => $item_width,
|
'width' => $item_width,
|
||||||
@@ -271,9 +255,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,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class MonetarySourcesController 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: index / all
|
||||||
|
* - Generate a listing of MonetarySources
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->all(); }
|
||||||
|
function all() { $this->jqGridView('All MonetarySources', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
return array
|
||||||
|
('link' => array('MonetaryType' => array('fields' => array('MonetaryType.id', 'MonetaryType.name')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['MonetarySource'] = array('id');
|
||||||
|
return parent::jqGridRecordLinks($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 MonetarySource and related fields
|
||||||
|
$monetary_source = $this->MonetarySource->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
('MonetaryType',
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = "Monetary Source #{$monetary_source['MonetarySource']['id']}";
|
||||||
|
$this->set(compact('monetary_source', 'title'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
<?php
|
||||||
|
/* SVN FILE: $Id: pages_controller.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||||
|
/**
|
||||||
|
* Static content controller.
|
||||||
|
*
|
||||||
|
* This file will render views from views/pages/
|
||||||
|
*
|
||||||
|
* 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.cake.libs.controller
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Static content controller
|
||||||
|
*
|
||||||
|
* Override this controller by placing a copy in controllers directory of an application
|
||||||
|
*
|
||||||
|
* @package cake
|
||||||
|
* @subpackage cake.cake.libs.controller
|
||||||
|
*/
|
||||||
|
class PagesController extends AppController {
|
||||||
|
/**
|
||||||
|
* Controller name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
var $name = 'Pages';
|
||||||
|
/**
|
||||||
|
* Default helper
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
var $helpers = array('Html');
|
||||||
|
/**
|
||||||
|
* This controller does not use a model
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
var $uses = array();
|
||||||
|
/**
|
||||||
|
* Displays a view
|
||||||
|
*
|
||||||
|
* @param mixed What page to display
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
function display() {
|
||||||
|
$path = func_get_args();
|
||||||
|
|
||||||
|
$count = count($path);
|
||||||
|
if (!$count) {
|
||||||
|
$this->redirect('/');
|
||||||
|
}
|
||||||
|
$page = $subpage = $title = null;
|
||||||
|
|
||||||
|
if (!empty($path[0])) {
|
||||||
|
$page = $path[0];
|
||||||
|
}
|
||||||
|
if (!empty($path[1])) {
|
||||||
|
$subpage = $path[1];
|
||||||
|
}
|
||||||
|
if (!empty($path[$count - 1])) {
|
||||||
|
$title = Inflector::humanize($path[$count - 1]);
|
||||||
|
}
|
||||||
|
$this->set(compact('page', 'subpage', 'title'));
|
||||||
|
$this->render(join('/', $path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class TransactionsController extends AppController {
|
||||||
|
|
||||||
|
var $components = array('RequestHandler');
|
||||||
|
|
||||||
|
var $sidemenu_links =
|
||||||
|
array(array('name' => 'Transactions', 'header' => true),
|
||||||
|
array('name' => 'All', 'url' => array('controller' => 'transactions', 'action' => 'all')),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* override: sideMenuLinks
|
||||||
|
* - Generates controller specific links for the side menu
|
||||||
|
*/
|
||||||
|
function sideMenuLinks() {
|
||||||
|
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: index / all
|
||||||
|
* - Generate a listing of transactions
|
||||||
|
*/
|
||||||
|
|
||||||
|
function index() { $this->all(); }
|
||||||
|
function all() { $this->jqGridView('All Transactions', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridRecordLinks(&$params, &$model, &$records, $links) {
|
||||||
|
$links['Transaction'] = array('id');
|
||||||
|
return parent::jqGridRecordLinks($params, $model, $records, $links);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: view
|
||||||
|
* - Displays information about a specific transaction
|
||||||
|
*/
|
||||||
|
|
||||||
|
function view($id = null) {
|
||||||
|
if (!$id) {
|
||||||
|
$this->Session->setFlash(__('Invalid Item.', true));
|
||||||
|
$this->redirect(array('action'=>'index'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$transaction = $this->Transaction->find
|
||||||
|
('first',
|
||||||
|
array('contain' =>
|
||||||
|
array(// Models
|
||||||
|
'LedgerEntry' => array('fields' => array('LedgerEntry.id',
|
||||||
|
'LedgerEntry.amount',
|
||||||
|
'LedgerEntry.comment'),
|
||||||
|
//Models
|
||||||
|
|
||||||
|
'DebitLedger' => array
|
||||||
|
('fields' => array('DebitLedger.id', 'DebitLedger.sequence'),
|
||||||
|
'Account' => array
|
||||||
|
('fields' => array('Account.id', 'Account.name')),
|
||||||
|
),
|
||||||
|
|
||||||
|
'CreditLedger' => array
|
||||||
|
('fields' => array('CreditLedger.id', 'CreditLedger.sequence'),
|
||||||
|
'Account' => array
|
||||||
|
('fields' => array('Account.id', 'Account.name')),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'conditions' => array('Transaction.id' => $id),
|
||||||
|
));
|
||||||
|
|
||||||
|
// Figure out the transaction total
|
||||||
|
$total = 0;
|
||||||
|
foreach($transaction['LedgerEntry'] AS $entry)
|
||||||
|
$total += $entry['amount'];
|
||||||
|
|
||||||
|
// OK, prepare to render.
|
||||||
|
$title = 'Transaction #' . $transaction['Transaction']['id'];
|
||||||
|
$this->set(compact('transaction', 'title', 'total'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* action: postReceipt
|
||||||
|
* - handles the creation of a payment receipt
|
||||||
|
*/
|
||||||
|
|
||||||
|
function postReceipt() {
|
||||||
|
$this->autoRender = false;
|
||||||
|
|
||||||
|
if (!$this->RequestHandler->isPost()) {
|
||||||
|
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//pr(array('thisdata' => $this->data));
|
||||||
|
|
||||||
|
if (isset($this->data['customer_id'])) {
|
||||||
|
$C = new Customer();
|
||||||
|
$C->recursive = -1;
|
||||||
|
$customer = $C->find
|
||||||
|
('first',
|
||||||
|
array('contain' => array('Account.CurrentLedger.id'),
|
||||||
|
'fields' => false,
|
||||||
|
'conditions' => array('Customer.id', $this->data['customer_id']),
|
||||||
|
));
|
||||||
|
$ledger_id = $customer['Account']['CurrentLedger']['id'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Payment by Unit, Lease, etc
|
||||||
|
$ledger_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = 0;
|
||||||
|
foreach ($this->data['LedgerEntry'] AS &$entry) {
|
||||||
|
$reconciled = $C->reconcileNewLedgerEntry($this->data['customer_id'],
|
||||||
|
'credit',
|
||||||
|
$entry['amount']);
|
||||||
|
pr(compact('entry', 'reconciled'));
|
||||||
|
|
||||||
|
foreach ($reconciled['debit']['entry'] AS $rec) {
|
||||||
|
$entry['DebitReconciliationLedgerEntry'] =
|
||||||
|
array('amount' => $rec['applied'],
|
||||||
|
//'debit_ledger_entry_id'
|
||||||
|
'credit_ledger_entry_id' => $rec['id']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount += isset($entry['amount']) ? $entry['amount'] : 0;
|
||||||
|
$entry['debit_ledger_id'] = 6; // Cash/Payments
|
||||||
|
$entry['credit_ledger_id'] = $ledger_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pr($this->data);
|
||||||
|
$T = new Transaction();
|
||||||
|
$T->create();
|
||||||
|
if ($T->saveAll($this->data,
|
||||||
|
array(
|
||||||
|
'validate' => false,
|
||||||
|
//'fieldList' => array(),
|
||||||
|
//'callbacks' => true,
|
||||||
|
))) {
|
||||||
|
$tid = $T->id;
|
||||||
|
$this->Session->setFlash(__("New Transaction Created ($tid)!", true));
|
||||||
|
//$this->redirect(array('action'=>'view', $mid));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->autoRender = false;
|
||||||
|
pr(array('checkpoint' => "saveAll failed"));
|
||||||
|
}
|
||||||
|
pr($T->data);
|
||||||
|
|
||||||
|
$C = new Customer();
|
||||||
|
$LE = new LedgerEntry();
|
||||||
|
/* $reconciled = $C->reconcileNewLedgerEntry($this->data['customer_id'], */
|
||||||
|
/* 'credit', */
|
||||||
|
/* $amount); */
|
||||||
|
/* pr(compact('amount', 'unreconciled', 'reconciled')); */
|
||||||
|
/* return; */
|
||||||
|
|
||||||
|
foreach ($this->data['LedgerEntry'] AS &$entry) {
|
||||||
|
$reconciled = $C->reconcileNewLedgerEntry($this->data['customer_id'],
|
||||||
|
'credit',
|
||||||
|
$entry['amount']);
|
||||||
|
pr(compact('entry', 'reconciled'));
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach ($reconciled['debit']['entry'] AS $rec) {
|
||||||
|
$data = array('LedgerEntry' =>
|
||||||
|
array('DebitReconciliationLedgerEntry' =>
|
||||||
|
array('amount' => $rec['applied'],
|
||||||
|
//'debit_ledger_entry_id'
|
||||||
|
'credit_ledger_entry_id' => $rec['id']
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
//'DebitReconciliationLedgerEntry' => array(
|
||||||
|
//pr(compact('amount', 'unreconciled', 'reconciled'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveTest() {
|
||||||
|
$data =
|
||||||
|
array(
|
||||||
|
/* 'Customer' => array */
|
||||||
|
/* ('id' => 7, */
|
||||||
|
/* ), */
|
||||||
|
|
||||||
|
'LedgerEntry' => array
|
||||||
|
(
|
||||||
|
'0' => array(
|
||||||
|
'amount' => 100,
|
||||||
|
'debit_ledger_id' => 1,
|
||||||
|
'credit_ledger_id' => 2,
|
||||||
|
'MonetarySource' => array('name' => 'testmoney', 'monetary_type_id' => 2),
|
||||||
|
),
|
||||||
|
'1' => array(
|
||||||
|
'amount' => 101,
|
||||||
|
'debit_ledger_id' => 1,
|
||||||
|
'credit_ledger_id' => 2,
|
||||||
|
'MonetarySource' => array('name' => 'testmoney2', 'monetary_type_id' => 2),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'Transaction' => array
|
||||||
|
(
|
||||||
|
'stamp' => '06/18/2009',
|
||||||
|
'comment' => 'no comment',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$data =
|
||||||
|
/* array( */
|
||||||
|
/* 'LedgerEntry' => array */
|
||||||
|
/* ( */
|
||||||
|
/* '0' => */
|
||||||
|
array(
|
||||||
|
'amount' => 100,
|
||||||
|
'debit_ledger_id' => 1,
|
||||||
|
'credit_ledger_id' => 2,
|
||||||
|
'transaction_id' => 66,
|
||||||
|
'DebitReconciliationLedgerEntry' =>
|
||||||
|
array('amount' => 44,
|
||||||
|
//'debit_ledger_entry_id'
|
||||||
|
'credit_ledger_entry_id' => 17,
|
||||||
|
),
|
||||||
|
/* ), */
|
||||||
|
/* ), */
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
//$M = new Transaction();
|
||||||
|
$M = new LedgerEntry();
|
||||||
|
$M->create();
|
||||||
|
$retval = $M->saveAll($data,
|
||||||
|
array(
|
||||||
|
'validate' => false,
|
||||||
|
'fieldList' => array(),
|
||||||
|
'callbacks' => true,
|
||||||
|
));
|
||||||
|
|
||||||
|
$mid = $M->id;
|
||||||
|
pr(compact('retval', 'mid'));
|
||||||
|
if ($mid) {
|
||||||
|
$this->Session->setFlash(__("New Transaction Created ($mid)!", true));
|
||||||
|
//$this->redirect(array('action'=>'view', $mid));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->autoRender = false;
|
||||||
|
pr(array('checkpoint' => "saveAll failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* $LE = new LedgerEntry(); */
|
||||||
|
/* $LE->create(); */
|
||||||
|
/* $ret = $LE->save($data, */
|
||||||
|
/* array( */
|
||||||
|
/* 'validate' => false, */
|
||||||
|
/* 'fieldList' => array(), */
|
||||||
|
/* 'callbacks' => true, */
|
||||||
|
/* )); */
|
||||||
|
/* $leid = $LE->id; */
|
||||||
|
/* pr(array('checkpoint' => "New Ledger Entry", */
|
||||||
|
/* compact('leid', 'ret'))); */
|
||||||
|
//pr($LE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
<?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->jqGridView('Unavailable Units'); }
|
||||||
|
function vacant() { $this->jqGridView('Vacant Units'); }
|
||||||
|
function occupied() { $this->jqGridView('Occupied Units'); }
|
||||||
|
function all() { $this->jqGridView('All Units', 'all'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* virtuals: jqGridData
|
||||||
|
* - With the application controller handling the jqGridData action,
|
||||||
|
* these virtual functions ensure that the correct data is passed
|
||||||
|
* to jqGrid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function jqGridDataSetup(&$params) {
|
||||||
|
parent::jqGridDataSetup($params);
|
||||||
|
if (!isset($params['action']))
|
||||||
|
$params['action'] = 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataTables(&$params, &$model) {
|
||||||
|
$link = array
|
||||||
|
('link' =>
|
||||||
|
array(// Models
|
||||||
|
'UnitSize' => array('fields' => array('name')),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($params['action'] === 'occupied')
|
||||||
|
$link['Lease'] = array('fields' => array(),
|
||||||
|
// Models
|
||||||
|
'Contact' => array('fields' => array('display_name'),
|
||||||
|
//'type' => 'LEFT',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return $link;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataConditions(&$params, &$model) {
|
||||||
|
$conditions = parent::jqGridDataConditions($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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $conditions;
|
||||||
|
}
|
||||||
|
|
||||||
|
function jqGridDataOrder(&$params, &$model, $index, $direction) {
|
||||||
|
if ($index === 'Unit.name') {
|
||||||
|
$index = 'Unit.sort_order';
|
||||||
|
}
|
||||||
|
return parent::jqGridDataOrder($params, $model, $index, $direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* 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->findSecurityDeposits($unit['CurrentLease']['id']);
|
||||||
|
$outstanding_deposit = $deposits['summary']['balance'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Operations', 'header' => true);
|
||||||
|
$this->sidemenu_links[] =
|
||||||
|
array('name' => 'Move-Out', 'url' => array('controller' => 'units', 'action' => 'move-out'));
|
||||||
|
|
||||||
|
// Prepare to render.
|
||||||
|
$title = 'Unit ' . $unit['Unit']['name'];
|
||||||
|
$this->set(compact('unit', 'title',
|
||||||
|
'outstanding_balance',
|
||||||
|
'outstanding_deposit'));
|
||||||
|
}
|
||||||
|
}
|
||||||
-1513
File diff suppressed because it is too large
Load Diff
-678
@@ -1,678 +0,0 @@
|
|||||||
-- Delete bad transaction(s)
|
|
||||||
DELETE M
|
|
||||||
FROM
|
|
||||||
pmgr_ledger_entries LE,
|
|
||||||
pmgr_tenders M
|
|
||||||
WHERE
|
|
||||||
M.ledger_entry_id = LE.id AND
|
|
||||||
LE.transaction_id
|
|
||||||
IN (467);
|
|
||||||
DELETE LE
|
|
||||||
FROM
|
|
||||||
pmgr_ledger_entries LE
|
|
||||||
WHERE
|
|
||||||
LE.transaction_id
|
|
||||||
IN (467);
|
|
||||||
DELETE SE
|
|
||||||
FROM
|
|
||||||
pmgr_statement_entries SE
|
|
||||||
WHERE
|
|
||||||
SE.transaction_id
|
|
||||||
IN (467);
|
|
||||||
DELETE T
|
|
||||||
FROM
|
|
||||||
pmgr_transactions T
|
|
||||||
WHERE
|
|
||||||
T.id
|
|
||||||
IN (467);
|
|
||||||
|
|
||||||
-- Delete bad transaction, one variable setting
|
|
||||||
SET @tid = 467;
|
|
||||||
DELETE M FROM pmgr_ledger_entries LE, pmgr_tenders M
|
|
||||||
WHERE M.ledger_entry_id = LE.id AND LE.transaction_id = @tid;
|
|
||||||
DELETE LE FROM pmgr_ledger_entries LE
|
|
||||||
WHERE LE.transaction_id = @tid;
|
|
||||||
DELETE SE FROM pmgr_statement_entries SE
|
|
||||||
WHERE SE.transaction_id = @tid;
|
|
||||||
DELETE T FROM pmgr_transactions T
|
|
||||||
WHERE T.id = @tid;
|
|
||||||
|
|
||||||
|
|
||||||
-- Delete all but one customer
|
|
||||||
SET @cid = 6;
|
|
||||||
-- DELETE T FROM pmgr_transactions T
|
|
||||||
-- LEFT JOIN pmgr_customers C ON C.id = T.customer_id
|
|
||||||
-- WHERE C.id IS NOT NULL AND C.id <> @cid;
|
|
||||||
DELETE C FROM pmgr_customers C
|
|
||||||
WHERE C.id <> @cid;
|
|
||||||
DELETE L FROM pmgr_leases L
|
|
||||||
LEFT JOIN pmgr_customers C ON C.id = L.customer_id
|
|
||||||
WHERE C.id IS NULL;
|
|
||||||
DELETE T FROM pmgr_transactions T
|
|
||||||
LEFT JOIN pmgr_customers C ON C.id = T.customer_id
|
|
||||||
WHERE C.id IS NULL;
|
|
||||||
DELETE SE FROM pmgr_statement_entries SE
|
|
||||||
LEFT JOIN pmgr_customers C ON C.id = SE.customer_id
|
|
||||||
WHERE C.id IS NULL;
|
|
||||||
DELETE LE FROM pmgr_ledger_entries LE
|
|
||||||
LEFT JOIN pmgr_transactions T ON T.id = LE.transaction_id
|
|
||||||
WHERE T.id IS NULL;
|
|
||||||
DELETE M FROM pmgr_tenders M
|
|
||||||
LEFT JOIN pmgr_ledger_entries LE ON M.ledger_entry_id = LE.id
|
|
||||||
WHERE LE.id IS NULL;
|
|
||||||
DELETE DE FROM pmgr_double_entries DE
|
|
||||||
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
|
|
||||||
WHERE LE.id IS NULL;
|
|
||||||
DELETE DE FROM pmgr_double_entries DE
|
|
||||||
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
|
|
||||||
WHERE LE.id IS NULL;
|
|
||||||
UPDATE pmgr_ledger_entries LE, pmgr_ledgers L, pmgr_accounts A
|
|
||||||
SET LE.ledger_id = L.id
|
|
||||||
WHERE A.id = LE.account_id AND L.account_id = A.id AND L.sequence = 1;
|
|
||||||
DELETE FROM pmgr_ledgers WHERE sequence > 1;
|
|
||||||
UPDATE pmgr_ledgers SET prior_ledger_id = NULL, close_transaction_id = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
-- Delete a ledger entry, associated double entry, and matching ledger_entry
|
|
||||||
SET @leid = 1365;
|
|
||||||
DELETE FROM pmgr_ledger_entries WHERE id = @leid;
|
|
||||||
DELETE DE FROM pmgr_double_entries DE
|
|
||||||
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
|
|
||||||
WHERE LE.id IS NULL;
|
|
||||||
DELETE DE FROM pmgr_double_entries DE
|
|
||||||
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
|
|
||||||
WHERE LE.id IS NULL;
|
|
||||||
DELETE LE FROM pmgr_ledger_entries LE
|
|
||||||
LEFT JOIN pmgr_double_entries DE
|
|
||||||
ON DE.credit_entry_id = LE.id OR DE.debit_entry_id = LE.id
|
|
||||||
WHERE DE.id IS NULL;
|
|
||||||
|
|
||||||
-- Add and update every Tender.ledger_entry_id (for rolling up old databases)
|
|
||||||
-- Takes a while to complete (~30s at time of writing)
|
|
||||||
ALTER TABLE `pmgr_tenders`
|
|
||||||
ADD `deposit_ledger_entry_id` INT UNSIGNED DEFAULT NULL
|
|
||||||
AFTER `nsf_ledger_entry_id`;
|
|
||||||
UPDATE
|
|
||||||
pmgr_tenders Tnd
|
|
||||||
JOIN pmgr_tender_types TndT ON TndT.id = Tnd.tender_type_id
|
|
||||||
JOIN pmgr_transactions T ON T.id = Tnd.deposit_transaction_id
|
|
||||||
JOIN pmgr_ledger_entries LE ON LE.transaction_id = T.id AND LE.account_id = TndT.account_id
|
|
||||||
JOIN pmgr_double_entries DE ON DE.debit_entry_id = LE.id OR DE.credit_entry_id = LE.id
|
|
||||||
JOIN pmgr_ledger_entries LEd ON (DE.debit_entry_id = LEd.id OR DE.credit_entry_id = LEd.id)
|
|
||||||
AND LEd.id <> LE.id
|
|
||||||
SET Tnd.deposit_ledger_entry_id = LEd.id;
|
|
||||||
|
|
||||||
|
|
||||||
-- Add auto_deposit and deposit_account_id to tenders
|
|
||||||
ALTER TABLE `pmgr_tender_types`
|
|
||||||
ADD `auto_deposit` TINYINT(1) UNSIGNED DEFAULT '0' NOT NULL
|
|
||||||
AFTER `tillable`;
|
|
||||||
ALTER TABLE `pmgr_tender_types`
|
|
||||||
ADD `deposit_account_id` INTEGER(10) UNSIGNED DEFAULT NULL
|
|
||||||
AFTER `account_id`;
|
|
||||||
|
|
||||||
|
|
||||||
-- Determine economic conditions
|
|
||||||
SELECT `status`, COUNT(id), SUM(rent) FROM pmgr_units
|
|
||||||
GROUP BY `status` WITH ROLLUP;
|
|
||||||
|
|
||||||
|
|
||||||
-- Check that transaction totals add up correctly
|
|
||||||
SELECT T.id, T.type, T.amount,
|
|
||||||
-- T.type, A.type, E.crdr,
|
|
||||||
SUM(IF(E.account_id = T.account_id,
|
|
||||||
IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1),0)
|
|
||||||
*E.amount) AS Tamt,
|
|
||||||
SUM(IF(E.account_id = T.account_id,
|
|
||||||
0,IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1))
|
|
||||||
*E.amount) AS Oamt,
|
|
||||||
COUNT(E.id) AS Ecnt
|
|
||||||
FROM pmgr_transactions T
|
|
||||||
-- LEFT JOIN pmgr_statement_entries E ON E.transaction_id = T.id
|
|
||||||
LEFT JOIN pmgr_ledger_entries E ON E.transaction_id = T.id
|
|
||||||
LEFT JOIN pmgr_accounts A ON A.id = T.account_id -- E.account_id
|
|
||||||
-- WHERE
|
|
||||||
-- E.account_id != T.account_id
|
|
||||||
GROUP BY T.id
|
|
||||||
HAVING
|
|
||||||
(T.amount <> IF(T.type IN ('INVOICE','TRANSFER','DEPOSIT','PAYMENT'), Tamt, Oamt))
|
|
||||||
OR
|
|
||||||
(Tamt * -1 <> Oamt)
|
|
||||||
|
|
||||||
|
|
||||||
-- Verify that statement entries all have the correct type
|
|
||||||
SELECT SE.id, SE.type, T.id, T.type
|
|
||||||
FROM pmgr_statement_entries SE
|
|
||||||
LEFT JOIN pmgr_transactions T ON T.id = SE.transaction_id
|
|
||||||
WHERE
|
|
||||||
((T.type = 'RECEIPT' OR T.type = 'CREDIT_NOTE') AND
|
|
||||||
SE.type NOT IN ('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS')
|
|
||||||
)
|
|
||||||
OR
|
|
||||||
((T.type = 'INVOICE' OR T.type = 'PAYMENT') AND
|
|
||||||
SE.type NOT IN ('CHARGE', 'PAYMENT', 'REFUND')
|
|
||||||
)
|
|
||||||
-- catch other types not considered in this query
|
|
||||||
OR T.type NOT IN ('RECEIPT', 'CREDIT_NOTE', 'INVOICE', 'PAYMENT')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- #################################################################
|
|
||||||
-- ## USER / GROUP
|
|
||||||
|
|
||||||
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
|
|
||||||
VALUES('Owner', 'Owner Group', 25);
|
|
||||||
SET @o_gid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
|
|
||||||
VALUES('Admin', 'Admin Group', 50);
|
|
||||||
SET @a_gid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
|
|
||||||
VALUES('Manager', 'Manager Group', 75);
|
|
||||||
SET @m_gid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_groups (`code`, `name`)
|
|
||||||
VALUES('Temp', 'Temporary Help');
|
|
||||||
SET @t_gid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
|
|
||||||
VALUES('AP', 'abijah', 0);
|
|
||||||
SET @a_uid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
|
|
||||||
VALUES('SK', 'shirley', 0);
|
|
||||||
SET @s_uid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
|
|
||||||
VALUES('DE', 'dan', 0);
|
|
||||||
SET @d_uid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
|
|
||||||
VALUES('KD', 'kevin', 0);
|
|
||||||
SET @k_uid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_sites (`code`, `name`)
|
|
||||||
VALUES('VSS', 'Valley Storage');
|
|
||||||
SET @v_sid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
INSERT INTO pmgr_sites (`code`, `name`)
|
|
||||||
VALUES('FAKE', 'Fake Site');
|
|
||||||
SET @f_sid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
-- Site Membership
|
|
||||||
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@v_sid, @a_uid, @o_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@v_sid, @a_uid, @a_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@v_sid, @a_uid, @m_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@v_sid, @s_uid, @m_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@v_sid, @d_uid, @t_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@f_sid, @s_uid, @a_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@f_sid, @s_uid, @m_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@f_sid, @k_uid, @o_gid);
|
|
||||||
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
|
|
||||||
VALUES(@f_sid, @d_uid, @t_gid);
|
|
||||||
|
|
||||||
|
|
||||||
-- Options
|
|
||||||
|
|
||||||
INSERT INTO pmgr_options (`name`) VALUES ('theme');
|
|
||||||
SET @t_oid = LAST_INSERT_ID();
|
|
||||||
INSERT INTO pmgr_options (`name`) VALUES ('menu');
|
|
||||||
SET @m_oid = LAST_INSERT_ID();
|
|
||||||
|
|
||||||
-- Default Option Values
|
|
||||||
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'blue');
|
|
||||||
INSERT INTO pmgr_default_options (`option_value_id`) VALUES(LAST_INSERT_ID());
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'basic');
|
|
||||||
INSERT INTO pmgr_default_options (`option_value_id`) VALUES(LAST_INSERT_ID());
|
|
||||||
|
|
||||||
-- Group options
|
|
||||||
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'gold');
|
|
||||||
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
|
|
||||||
VALUES(@o_gid, LAST_INSERT_ID());
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'silver');
|
|
||||||
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
|
|
||||||
VALUES(@a_gid, LAST_INSERT_ID());
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'red');
|
|
||||||
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
|
|
||||||
VALUES(@m_gid, LAST_INSERT_ID());
|
|
||||||
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'advanced');
|
|
||||||
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
|
|
||||||
VALUES(@o_gid, LAST_INSERT_ID());
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'advanced');
|
|
||||||
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
|
|
||||||
VALUES(@a_gid, LAST_INSERT_ID());
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'restricted');
|
|
||||||
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
|
|
||||||
VALUES(@t_gid, LAST_INSERT_ID());
|
|
||||||
|
|
||||||
-- User Options
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'special');
|
|
||||||
INSERT INTO pmgr_user_options (`user_id`, `option_value_id`)
|
|
||||||
VALUES(@s_uid, LAST_INSERT_ID());
|
|
||||||
|
|
||||||
-- Site Options
|
|
||||||
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'site-theme');
|
|
||||||
INSERT INTO pmgr_site_options (`site_id`, `option_value_id`)
|
|
||||||
VALUES(@f_sid, LAST_INSERT_ID());
|
|
||||||
|
|
||||||
|
|
||||||
-- SELECT U.id, P.name, MAX(P.access)
|
|
||||||
-- FROM pmgr_users U
|
|
||||||
-- LEFT JOIN pmgr_site_membership M ON M.user_id = U.id
|
|
||||||
-- LEFT JOIN pmgr_groups G ON G.id = M.group_id
|
|
||||||
-- LEFT JOIN pmgr_group_permissions P ON P.group_id = G.id
|
|
||||||
-- GROUP BY U.id, P.name
|
|
||||||
|
|
||||||
|
|
||||||
-- User access to site
|
|
||||||
SELECT U.id, U.login, COUNT(G.id) AS 'groups', MIN(G.rank) AS highest_rank
|
|
||||||
FROM pmgr_users U
|
|
||||||
JOIN pmgr_site_memberships M ON M.user_id = U.id
|
|
||||||
JOIN pmgr_sites S ON S.id = M.site_id
|
|
||||||
JOIN pmgr_groups G ON G.id = M.group_id
|
|
||||||
WHERE S.code = 'VSS'
|
|
||||||
GROUP BY U.id
|
|
||||||
|
|
||||||
|
|
||||||
-- User Options
|
|
||||||
SELECT O.id, O.name, O.default,
|
|
||||||
GROUP_CONCAT(Uopt.value) AS 'value', COUNT(U.id) AS 'count'
|
|
||||||
FROM pmgr_options O
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
|
|
||||||
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
|
|
||||||
WHERE U.id = 1
|
|
||||||
GROUP BY O.id
|
|
||||||
|
|
||||||
-- Group Options
|
|
||||||
SELECT O.id, O.name, O.default,
|
|
||||||
GROUP_CONCAT(Gopt.value) AS 'value', COUNT(G.id) AS 'count'
|
|
||||||
FROM pmgr_options O
|
|
||||||
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
|
|
||||||
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
|
|
||||||
WHERE G.id = 1
|
|
||||||
GROUP BY O.id
|
|
||||||
|
|
||||||
|
|
||||||
-- Site Options
|
|
||||||
SELECT O.id, O.name, O.default,
|
|
||||||
GROUP_CONCAT(Sopt.value) AS 'value', COUNT(S.id) AS 'count'
|
|
||||||
FROM pmgr_options O
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
|
|
||||||
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
|
|
||||||
WHERE S.id = 1
|
|
||||||
GROUP BY O.id
|
|
||||||
|
|
||||||
|
|
||||||
-- Option value for member & site
|
|
||||||
SELECT O.id, O.name, O.default,
|
|
||||||
S.id AS site_id, Sopt.value,
|
|
||||||
G.id AS group_id, Gopt.value,
|
|
||||||
U.id AS user_id, Uopt.value
|
|
||||||
FROM pmgr_options O
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
|
|
||||||
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
|
|
||||||
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
|
|
||||||
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
|
|
||||||
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
|
|
||||||
WHERE O.name = 'theme'
|
|
||||||
--GROUP BY O.id
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Option value for member & site
|
|
||||||
-- 1) User
|
|
||||||
SET @sid = 1;
|
|
||||||
SET @uid = 1;
|
|
||||||
SET @oid = 1;
|
|
||||||
SELECT O.name, U.id, Uopt.value
|
|
||||||
FROM pmgr_options O
|
|
||||||
JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
|
|
||||||
JOIN pmgr_users U ON U.id = Uopt.user_id
|
|
||||||
-- JOIN pmgr_site_memberships M ON M.user_id = U.id
|
|
||||||
-- JOIN pmgr_groups G ON G.id = M.group_id
|
|
||||||
-- JOIN pmgr_sites S ON S.id = M.site_id
|
|
||||||
WHERE -- S.id = @sid AND
|
|
||||||
U.id = @uid AND O.id = @oid
|
|
||||||
;
|
|
||||||
|
|
||||||
-- 2) Group
|
|
||||||
SELECT O.name, G.rank, G.id, Gopt.value
|
|
||||||
FROM pmgr_options O
|
|
||||||
JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
|
|
||||||
JOIN pmgr_groups G ON G.id = Gopt.group_id
|
|
||||||
JOIN pmgr_site_memberships M ON M.group_id = G.id
|
|
||||||
JOIN pmgr_users U ON U.id = M.user_id
|
|
||||||
JOIN pmgr_sites S ON S.id = M.site_id
|
|
||||||
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
|
|
||||||
ORDER BY G.rank
|
|
||||||
;
|
|
||||||
|
|
||||||
-- 3) Site
|
|
||||||
SELECT O.name, S.id, Sopt.value
|
|
||||||
FROM pmgr_options O
|
|
||||||
JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
|
|
||||||
JOIN pmgr_sites S ON S.id = Sopt.site_id
|
|
||||||
-- JOIN pmgr_site_memberships M ON M.site_id = S.id
|
|
||||||
-- JOIN pmgr_groups G ON G.id = M.group_id
|
|
||||||
-- JOIN pmgr_users U ON U.id = M.user_id
|
|
||||||
WHERE S.id = @sid
|
|
||||||
-- AND U.id = @uid
|
|
||||||
AND O.id = @oid
|
|
||||||
;
|
|
||||||
|
|
||||||
-- 3) Default
|
|
||||||
SELECT O.name, O.default AS 'value'
|
|
||||||
FROM pmgr_options O
|
|
||||||
WHERE O.id = @oid
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
-- User Permissions
|
|
||||||
|
|
||||||
|
|
||||||
-- Group Permissions
|
|
||||||
|
|
||||||
-- All option values, in order
|
|
||||||
SELECT O.name, V.value,
|
|
||||||
U.id AS uid, G.id AS gid, S.id as sid,
|
|
||||||
Dopt.id AS did, G.rank
|
|
||||||
FROM pmgr_option_values V
|
|
||||||
JOIN pmgr_options O ON O.id = V.option_id
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
|
|
||||||
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
|
|
||||||
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
|
|
||||||
WHERE O.id = @oid
|
|
||||||
ORDER BY IF(U.id IS NOT NULL, 1,
|
|
||||||
IF (G.id IS NOT NULL, 2,
|
|
||||||
IF (S.id IS NOT NULL, 3, 4))) ASC,
|
|
||||||
IF (G.id IS NOT NULL, G.rank, 0) ASC
|
|
||||||
|
|
||||||
|
|
||||||
-- Option values relevant to the user and site, in order
|
|
||||||
SELECT O.name, V.value,
|
|
||||||
U.id AS uid, G.id AS gid, S.id as sid,
|
|
||||||
Dopt.id AS did, G.rank
|
|
||||||
FROM pmgr_option_values V
|
|
||||||
JOIN pmgr_options O ON O.id = V.option_id
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
|
|
||||||
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
|
|
||||||
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
|
|
||||||
JOIN pmgr_site_memberships M ON M.user_id = U.id AND M.site_id = S.id
|
|
||||||
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
|
|
||||||
ORDER BY IF(U.id IS NOT NULL, 1,
|
|
||||||
IF (G.id IS NOT NULL, 2,
|
|
||||||
IF (S.id IS NOT NULL, 3, 4))) ASC,
|
|
||||||
IF (G.id IS NOT NULL, G.rank, 0) ASC
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SET @sid = 1;
|
|
||||||
SET @uid = 1;
|
|
||||||
SET @oid = 1;
|
|
||||||
SELECT O.name, V.value,
|
|
||||||
U.id AS uid,
|
|
||||||
-- G.id AS gid,
|
|
||||||
S.id as sid,
|
|
||||||
Dopt.id AS did
|
|
||||||
-- G.rank
|
|
||||||
FROM pmgr_option_values V
|
|
||||||
JOIN pmgr_options O ON O.id = V.option_id
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
|
|
||||||
-- LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
|
|
||||||
-- LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
|
|
||||||
-- LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
|
|
||||||
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
|
|
||||||
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
|
|
||||||
JOIN pmgr_site_memberships M ON M.user_id = U.id -- AND M.site_id = S.id
|
|
||||||
WHERE -- S.id = @sid AND U.id = @uid AND
|
|
||||||
O.id = @oid
|
|
||||||
ORDER BY IF(U.id IS NOT NULL, 1,
|
|
||||||
-- IF (G.id IS NOT NULL, 2,
|
|
||||||
IF (S.id IS NOT NULL, 3, 4)) -- ) ASC,
|
|
||||||
-- IF (G.id IS NOT NULL, G.rank, 0) ASC
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- ------------------------------------------------------------
|
|
||||||
-- ------------------------------------------------------------
|
|
||||||
-- ------------------------------------------------------------
|
|
||||||
-- Working version (without defaults)
|
|
||||||
SET @sid = 1;
|
|
||||||
SET @uid = 1;
|
|
||||||
SET @oid = 1;
|
|
||||||
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
|
|
||||||
U.id AS uid,
|
|
||||||
G.id AS gid,
|
|
||||||
S.id AS sid,
|
|
||||||
-- Dopt.id AS did
|
|
||||||
G.rank
|
|
||||||
FROM pmgr_users U
|
|
||||||
JOIN pmgr_site_memberships M ON M.user_id = U.id
|
|
||||||
JOIN pmgr_sites S ON S.id = M.site_id
|
|
||||||
LEFT JOIN pmgr_groups G ON G.id = M.group_id
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.user_id = U.id
|
|
||||||
LEFT JOIN pmgr_group_options Gopt ON Gopt.group_id = G.id
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.site_id = S.id
|
|
||||||
LEFT JOIN pmgr_option_values V ON (V.id = Uopt.option_value_id OR
|
|
||||||
V.id = Gopt.option_value_id OR
|
|
||||||
V.id = Sopt.option_value_id)
|
|
||||||
JOIN pmgr_options O ON O.id = V.option_id
|
|
||||||
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
|
|
||||||
ORDER BY IF(U.id IS NOT NULL, 1,
|
|
||||||
IF (G.id IS NOT NULL, 2,
|
|
||||||
IF (S.id IS NOT NULL, 3, 4))) ASC,
|
|
||||||
IF (G.id IS NOT NULL, G.rank, 0) ASC
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SET @sid = 1;
|
|
||||||
SET @uid = 1;
|
|
||||||
SET @oid = 1;
|
|
||||||
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
|
|
||||||
U.id AS uid,
|
|
||||||
G.id AS gid,
|
|
||||||
S.id AS sid,
|
|
||||||
-- Dopt.id AS did
|
|
||||||
G.rank
|
|
||||||
FROM pmgr_options O
|
|
||||||
LEFT JOIN pmgr_option_values V ON V.option_id = O.id
|
|
||||||
-- Now have the option and all possible values
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
|
|
||||||
-- Now have the user/group/site that each value applies to
|
|
||||||
LEFT JOIN pmgr_users U U ON Uopt.user_id = U.id OR Uopt.user_id IS NULL
|
|
||||||
-- Now restricted to our user
|
|
||||||
JOIN pmgr_site_memberships M ON M.user_id = U.id
|
|
||||||
JOIN pmgr_sites S ON S.id = M.site_id
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ON O.id = V.option_id
|
|
||||||
LEFT JOIN pmgr_groups G ON G.id = M.group_id
|
|
||||||
LEFT JOIN pmgr_option_values V ON (V.id = Uopt.option_value_id OR
|
|
||||||
V.id = Gopt.option_value_id OR
|
|
||||||
V.id = Sopt.option_value_id)
|
|
||||||
JOIN
|
|
||||||
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
|
|
||||||
ORDER BY IF(U.id IS NOT NULL, 1,
|
|
||||||
IF (G.id IS NOT NULL, 2,
|
|
||||||
IF (S.id IS NOT NULL, 3, 4))) ASC,
|
|
||||||
IF (G.id IS NOT NULL, G.rank, 0) ASC
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SET @sid = 1;
|
|
||||||
SET @uid = 1;
|
|
||||||
SET @oid = 1;
|
|
||||||
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
|
|
||||||
U.id AS uid,
|
|
||||||
G.id AS gid,
|
|
||||||
S.id AS sid,
|
|
||||||
-- Dopt.id AS did
|
|
||||||
G.rank
|
|
||||||
FROM pmgr_options O LEFT JOIN pmgr_option_values V ON V.option_id = O.id,
|
|
||||||
pmgr_users U
|
|
||||||
JOIN pmgr_site_memberships M ON M.user_id = U.id
|
|
||||||
JOIN pmgr_sites S ON S.id = M.site_id
|
|
||||||
LEFT JOIN pmgr_groups G ON G.id = M.group_id
|
|
||||||
LEFT JOIN pmgr_user_options Uopt ON Uopt.user_id = U.id
|
|
||||||
LEFT JOIN pmgr_group_options Gopt ON Gopt.group_id = G.id
|
|
||||||
LEFT JOIN pmgr_site_options Sopt ON Sopt.site_id = S.id,
|
|
||||||
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
|
|
||||||
AND (V.id = Uopt.option_value_id OR
|
|
||||||
V.id = Gopt.option_value_id OR
|
|
||||||
V.id = Sopt.option_value_id)
|
|
||||||
ORDER BY IF(U.id IS NOT NULL, 1,
|
|
||||||
IF (G.id IS NOT NULL, 2,
|
|
||||||
IF (S.id IS NOT NULL, 3, 4))) ASC,
|
|
||||||
IF (G.id IS NOT NULL, G.rank, 0) ASC
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------------------------------
|
|
||||||
-- Income by Month
|
|
||||||
SELECT MONTH(SE.effective_date) AS mon, YEAR(SE.effective_date) AS yr,
|
|
||||||
SE.account_id AS acct, ROUND(SUM(SE.amount)) AS amt
|
|
||||||
FROM pmgr_statement_entries SE
|
|
||||||
WHERE SE.type = 'CHARGE'
|
|
||||||
AND SE.effective_date >= '2009-04-01' AND SE.effective_date <= NOW()
|
|
||||||
GROUP BY yr, mon, acct WITH ROLLUP
|
|
||||||
|
|
||||||
-- ----------------------------------------------------
|
|
||||||
-- Rent Income by Month
|
|
||||||
SELECT MONTH(SE.effective_date) AS mon, YEAR(SE.effective_date) AS yr,
|
|
||||||
ROUND(SUM(SE.amount)) AS amt
|
|
||||||
FROM pmgr_statement_entries SE
|
|
||||||
WHERE SE.type = 'CHARGE'
|
|
||||||
AND SE.effective_date >= '2009-04-01' AND SE.effective_date <= NOW()
|
|
||||||
AND SE.account_id = 13
|
|
||||||
GROUP BY yr, mon WITH ROLLUP
|
|
||||||
|
|
||||||
-- ----------------------------------------------------
|
|
||||||
-- Occupancy during given month
|
|
||||||
SELECT COUNT(L.id) FROM pmgr_leases L
|
|
||||||
WHERE L.movein_date < '2009-10-01'
|
|
||||||
AND (L.moveout_date IS NULL OR L.moveout_date > '2009-09-01')
|
|
||||||
|
|
||||||
-- ----------------------------------------------------
|
|
||||||
-- Move-ins by month
|
|
||||||
SELECT MONTH(L.movein_date) AS mon, YEAR(L.movein_date) AS yr, COUNT(L.id)
|
|
||||||
FROM pmgr_leases L
|
|
||||||
WHERE L.movein_date >= '2009-04-01'
|
|
||||||
GROUP BY yr, mon
|
|
||||||
|
|
||||||
-- ----------------------------------------------------
|
|
||||||
-- Move-outs by month
|
|
||||||
SELECT MONTH(L.moveout_date) AS mon, YEAR(L.moveout_date) AS yr, COUNT(L.id)
|
|
||||||
FROM pmgr_leases L
|
|
||||||
WHERE L.moveout_date >= '2009-04-01'
|
|
||||||
GROUP BY yr, mon
|
|
||||||
|
|
||||||
-- ----------------------------------------------------
|
|
||||||
-- Move-ins/Move-outs by month
|
|
||||||
SELECT
|
|
||||||
MONTH(L.movein_date) AS mon, YEAR(L.movein_date) AS yr,
|
|
||||||
IF(L.movein_date AS mon, YEAR(L.movein_date) AS yr,
|
|
||||||
FROM pmgr_leases L
|
|
||||||
WHERE L.movein_date >= '2009-04-01'
|
|
||||||
GROUP BY yr, mon
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------------------------------
|
|
||||||
-- Rent charged
|
|
||||||
SELECT SUM(SE.amount)
|
|
||||||
FROM pmgr_statement_entries SE
|
|
||||||
LEFT JOIN pmgr_accounts A ON A.id = SE.account_id
|
|
||||||
WHERE A.name = 'Rent'
|
|
||||||
-- AND SE.effective_date >= '2009-04-01'
|
|
||||||
-- AND SE.effective_date < '2009-12-01'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- --------------------------------------------------------------
|
|
||||||
-- Merge two customers
|
|
||||||
SELECT * FROM pmgr_statement_entries WHERE customer_id = 65
|
|
||||||
;
|
|
||||||
UPDATE pmgr_leases SET customer_id=21 WHERE customer_id=65;
|
|
||||||
UPDATE pmgr_reservations SET customer_id=21 WHERE customer_id=65;
|
|
||||||
UPDATE pmgr_statement_entries SET customer_id=21 WHERE customer_id=65;
|
|
||||||
UPDATE pmgr_tenders SET customer_id=21 WHERE customer_id=65;
|
|
||||||
UPDATE pmgr_transactions SET customer_id=21 WHERE customer_id=65;
|
|
||||||
-- Make sure to update customer info afterwards
|
|
||||||
|
|
||||||
|
|
||||||
-- --------------------------------------------------------------
|
|
||||||
-- Determine income from a customer
|
|
||||||
SELECT NT.name AS 'type', SUM(LE.amount) AS 'total'
|
|
||||||
FROM pmgr_tenders N
|
|
||||||
LEFT JOIN pmgr_tender_types NT ON NT.id = N.tender_type_id
|
|
||||||
LEFT JOIN pmgr_ledger_entries LE ON LE.id = N.ledger_entry_id
|
|
||||||
LEFT JOIN pmgr_customers C ON C.id = N.customer_id
|
|
||||||
WHERE
|
|
||||||
N.customer_id = 49
|
|
||||||
AND N.nsf_ledger_entry_id IS NULL
|
|
||||||
AND (NT.tillable OR NT.auto_deposit)
|
|
||||||
GROUP BY NT.name WITH ROLLUP
|
|
||||||
|
|
||||||
|
|
||||||
-- --------------------------------------------------------------
|
|
||||||
-- Determine rent charges by month
|
|
||||||
SELECT MONTH(SE.effective_date) AS 'mon',
|
|
||||||
YEAR(SE.effective_date) AS 'yr',
|
|
||||||
DATE_FORMAT(SE.effective_date, "%m/1/%Y") AS 'date',
|
|
||||||
SUM(SE.amount) AS 'total'
|
|
||||||
FROM pmgr_accounts A
|
|
||||||
LEFT JOIN pmgr_statement_entries SE ON SE.account_id = A.id
|
|
||||||
WHERE
|
|
||||||
A.name = 'Rent'
|
|
||||||
AND SE.effective_date < NOW()
|
|
||||||
GROUP BY yr, mon -- WITH ROLLUP
|
|
||||||
|
|
||||||
@@ -0,0 +1,358 @@
|
|||||||
|
<?php
|
||||||
|
class Account extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Account';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'name' => array('notempty'),
|
||||||
|
'external_name' => array('notempty')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasOne = array(
|
||||||
|
'CurrentLedger' => array(
|
||||||
|
'className' => 'Ledger',
|
||||||
|
'conditions' => array('NOT' => array('CurrentLedger.closed'))
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'Ledger',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: type
|
||||||
|
* - Returns the type of this account
|
||||||
|
*/
|
||||||
|
function type($id) {
|
||||||
|
$this->cacheQueries = true;
|
||||||
|
$account = $this->find('first', array
|
||||||
|
('recursive' => -1,
|
||||||
|
'fields' => array('type'),
|
||||||
|
'conditions' => array(array('Account.id' => $id)),
|
||||||
|
));
|
||||||
|
$this->cacheQueries = false;
|
||||||
|
|
||||||
|
return $account['Account']['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: fundamentalType
|
||||||
|
* - Returns the fundmental type of the account, credit or debit
|
||||||
|
*/
|
||||||
|
function fundamentalType($id_or_type) {
|
||||||
|
if (is_numeric($id_or_type))
|
||||||
|
$type = $this->type($id_or_type);
|
||||||
|
else
|
||||||
|
$type = $id_or_type;
|
||||||
|
|
||||||
|
// Asset and Expense accounts are debit accounts
|
||||||
|
if (in_array(strtoupper($type), array('ASSET', 'EXPENSE')))
|
||||||
|
return 'debit';
|
||||||
|
|
||||||
|
// Otherwise, it's a credit account
|
||||||
|
return 'credit';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: fundamentalOpposite
|
||||||
|
* - Returns the opposite fundmental type of the account, credit or debit
|
||||||
|
*/
|
||||||
|
function fundamentalOpposite($id_or_type) {
|
||||||
|
if (in_array(strtolower($id_or_type), array('credit', 'debit')))
|
||||||
|
$fund = $id_or_type;
|
||||||
|
else
|
||||||
|
$fund = $this->fundamentalType($id_or_type);
|
||||||
|
|
||||||
|
if ($fund == 'debit')
|
||||||
|
return 'credit';
|
||||||
|
|
||||||
|
return 'debit';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: accountNameToID
|
||||||
|
* - Returns the ID of the named account
|
||||||
|
*/
|
||||||
|
function accountNameToID($name) {
|
||||||
|
$this->cacheQueries = true;
|
||||||
|
$account = $this->find('first', array
|
||||||
|
('recursive' => -1,
|
||||||
|
'conditions' => compact('name'),
|
||||||
|
));
|
||||||
|
$this->cacheQueries = false;
|
||||||
|
return $account['Account']['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
function securityDepositAccountID() { return $this->accountNameToID('Security Deposit'); }
|
||||||
|
function rentAccountID() { return $this->accountNameToID('Rent'); }
|
||||||
|
function accountReceivableAccountID() { return $this->accountNameToID('A/R'); }
|
||||||
|
function invoiceAccountID() { return $this->accountReceivableAccountID(); }
|
||||||
|
function receiptAccountID() { return $this->accountReceivableAccountID(); }
|
||||||
|
//function invoiceAccountID() { return $this->accountNameToID('Invoice'); }
|
||||||
|
//function receiptAccountID() { return $this->accountNameToID('Receipt'); }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: ledgers
|
||||||
|
* - Returns an array of ledger ids from the given account
|
||||||
|
*/
|
||||||
|
function ledgers($id, $all = false) {
|
||||||
|
if ($all) {
|
||||||
|
$contain = array('Ledger' => array('fields' => array('Ledger.id')));
|
||||||
|
} else {
|
||||||
|
$contain = array('CurrentLedger' => array('fields' => array('CurrentLedger.id')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cacheQueries = true;
|
||||||
|
$account = $this->find('first', array
|
||||||
|
('contain' => $contain,
|
||||||
|
'fields' => array(),
|
||||||
|
'conditions' => array(array('Account.id' => $id)),
|
||||||
|
));
|
||||||
|
$this->cacheQueries = false;
|
||||||
|
|
||||||
|
if ($all) {
|
||||||
|
$ledger_ids = array();
|
||||||
|
foreach ($account['Ledger'] AS $ledger)
|
||||||
|
array_push($ledger_ids, $ledger['id']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ledger_ids = array($account['CurrentLedger']['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pr(array('function' => 'Account::ledgers', */
|
||||||
|
/* 'args' => compact('id', 'all'), */
|
||||||
|
/* 'return' => $ledger_ids)); */
|
||||||
|
|
||||||
|
return $ledger_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findLedgerEntries
|
||||||
|
* - Returns an array of ledger entries that belong to the given
|
||||||
|
* account, either just from the current ledger, or from all ledgers.
|
||||||
|
*/
|
||||||
|
function findLedgerEntries($id, $all = false, $cond = null, $link = null) {
|
||||||
|
/* pr(array('function' => 'Account::findLedgerEntries', */
|
||||||
|
/* 'args' => compact('id', 'all', 'cond', 'link'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
$entries = array();
|
||||||
|
foreach ($this->ledgers($id, $all) AS $ledger_id) {
|
||||||
|
$ledger_entries = $this->Ledger->findLedgerEntries
|
||||||
|
($ledger_id, $this->type($id), $cond, $link);
|
||||||
|
$entries = array_merge($entries, $ledger_entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stats = $this->stats($id, $all, $cond);
|
||||||
|
$entries = array('Entries' => $entries,
|
||||||
|
'summary' => $stats['Ledger']);
|
||||||
|
|
||||||
|
/* pr(array('function' => 'Account::findLedgerEntries', */
|
||||||
|
/* 'args' => compact('id', 'all', 'cond', 'link'), */
|
||||||
|
/* 'vars' => compact('stats'), */
|
||||||
|
/* 'return' => compact('entries'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findLedgerEntriesRelatedToAccount
|
||||||
|
* - Returns an array of ledger entries that belong to the given
|
||||||
|
* account, and are related to a specific account, either just from
|
||||||
|
* the current ledger, or from all ledgers.
|
||||||
|
*/
|
||||||
|
function findLedgerEntriesRelatedToAccount($id, $rel_ids, $all = false, $cond = null, $link = null) {
|
||||||
|
/* pr(array('function' => 'Account::findLedgerEntriesRelatedToAccount', */
|
||||||
|
/* 'args' => compact('id', 'rel_ids', 'all', 'cond', 'link'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
if (!isset($cond))
|
||||||
|
$cond = array();
|
||||||
|
if (!is_array($rel_ids))
|
||||||
|
$rel_ids = array($rel_ids);
|
||||||
|
|
||||||
|
$ledger_ids = array();
|
||||||
|
foreach ($rel_ids AS $rel_id)
|
||||||
|
$ledger_ids = array_merge($ledger_ids, $this->ledgers($rel_id));
|
||||||
|
|
||||||
|
array_push($cond, $this->Ledger->LedgerEntry->conditionEntryAsCreditOrDebit($ledger_ids));
|
||||||
|
$entries = $this->findLedgerEntries($id, $all, $cond, $link);
|
||||||
|
|
||||||
|
/* pr(array('function' => 'Account::findLedgerEntriesRelatedToAccount', */
|
||||||
|
/* 'args' => compact('id', 'relid', 'all', 'cond', 'link'), */
|
||||||
|
/* 'vars' => compact('ledger_ids'), */
|
||||||
|
/* 'return' => compact('entries'), */
|
||||||
|
/* )); */
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findUnreconciledLedgerEntries
|
||||||
|
* - Returns ledger entries that are not yet reconciled
|
||||||
|
* (such as charges not paid).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null, $cond = null) {
|
||||||
|
if (!isset($cond))
|
||||||
|
$cond = array();
|
||||||
|
$cond[] = array('Account.id' => $id);
|
||||||
|
|
||||||
|
foreach (($fundamental_type
|
||||||
|
? array($fundamental_type)
|
||||||
|
: array('debit', 'credit')) AS $fund) {
|
||||||
|
$ucfund = ucfirst($fund);
|
||||||
|
$unreconciled[$fund]['entry'] = $this->find
|
||||||
|
('all', array
|
||||||
|
('link' => array
|
||||||
|
('Ledger' => array
|
||||||
|
('fields' => array(),
|
||||||
|
"LedgerEntry" => array
|
||||||
|
('class' => "{$ucfund}LedgerEntry",
|
||||||
|
'fields' => array('id', 'amount'),
|
||||||
|
"ReconciliationLedgerEntry" => array
|
||||||
|
('class' => "{$ucfund}ReconciliationLedgerEntry",
|
||||||
|
'fields' => array
|
||||||
|
("COALESCE(SUM(Reconciliation.amount),0) AS 'reconciled'",
|
||||||
|
"LedgerEntry.amount - COALESCE(SUM(Reconciliation.amount),0) AS 'balance'",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'group' => ("LedgerEntry.id" .
|
||||||
|
" HAVING LedgerEntry.amount" .
|
||||||
|
" <> COALESCE(SUM(Reconciliation.amount),0)"),
|
||||||
|
'conditions' => $cond,
|
||||||
|
'fields' => array(),
|
||||||
|
));
|
||||||
|
$balance = 0;
|
||||||
|
foreach ($unreconciled[$fund]['entry'] AS &$entry) {
|
||||||
|
$entry = array_merge(array_diff_key($entry["LedgerEntry"], array(0=>true)),
|
||||||
|
$entry[0]);
|
||||||
|
$balance += $entry['balance'];
|
||||||
|
}
|
||||||
|
$unreconciled[$fund]['balance'] = $balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $unreconciled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: reconcileNewLedgerEntry
|
||||||
|
* - Returns which ledger entries a new credit/debit would
|
||||||
|
* reconcile, and how much.
|
||||||
|
*
|
||||||
|
* - REVISIT <AP> 20090617
|
||||||
|
* This should be subject to different algorithms, such
|
||||||
|
* as apply to oldest charges first, newest first, to fees
|
||||||
|
* before rent, etc. Until we get there, I'll hardcode
|
||||||
|
* whatever algorithm is simplest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function reconcileNewLedgerEntry($id, $fundamental_type, $amount, $cond = null) {
|
||||||
|
$ofund = $this->fundamentalOpposite($fundamental_type);
|
||||||
|
$unreconciled = array($ofund => array('entry'=>array(), 'balance'=>0));
|
||||||
|
$applied = 0;
|
||||||
|
|
||||||
|
// if there is no money in the entry, it can reconcile nothing
|
||||||
|
// don't bother wasting time sifting ledger entries.
|
||||||
|
if ($amount > 0) {
|
||||||
|
$unreconciled = $this->findUnreconciledLedgerEntries($id, $ofund, $cond);
|
||||||
|
|
||||||
|
foreach ($unreconciled[$ofund]['entry'] AS $i => &$entry) {
|
||||||
|
// Determine if amount is sufficient to cover the entry
|
||||||
|
if ($amount > $entry['balance'])
|
||||||
|
$apply = $entry['balance'];
|
||||||
|
elseif ($amount > 0)
|
||||||
|
$apply = $amount;
|
||||||
|
else {
|
||||||
|
unset($unreconciled[$ofund]['entry'][$i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entry['applied'] = $apply;
|
||||||
|
$entry['reconciled'] += $apply;
|
||||||
|
$entry['balance'] -= $apply;
|
||||||
|
$applied += $apply;
|
||||||
|
$amount -= $apply;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$unreconciled[$ofund]['unapplied'] = $amount;
|
||||||
|
$unreconciled[$ofund]['applied'] = $applied;
|
||||||
|
$unreconciled[$ofund]['balance'] -= $applied;
|
||||||
|
return $unreconciled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested account.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function stats($id = null, $all = false, $cond = null) {
|
||||||
|
if (!$id)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// All old, closed ledgers MUST balance to 0.
|
||||||
|
// However, the user may want the ENTIRE running totals,
|
||||||
|
// (not just the balance), so we may have to query all
|
||||||
|
// ledgers, as dictated by the $all parameter.
|
||||||
|
|
||||||
|
$account = $this->find('first',
|
||||||
|
array('contain' =>
|
||||||
|
($all
|
||||||
|
? array('Ledger' => array
|
||||||
|
('fields' => array('id')))
|
||||||
|
: array('CurrentLedger' => array
|
||||||
|
('fields' => array('id')))
|
||||||
|
),
|
||||||
|
'conditions' => array
|
||||||
|
(array('Account.id' => $id))
|
||||||
|
));
|
||||||
|
|
||||||
|
$stats = array();
|
||||||
|
if ($all) {
|
||||||
|
foreach ($account['Ledger'] AS $ledger)
|
||||||
|
$this->statsMerge($stats['Ledger'],
|
||||||
|
$this->Ledger->stats($ledger['id'], $cond));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$stats['Ledger'] =
|
||||||
|
$this->Ledger->stats($account['CurrentLedger']['id'], $cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* LinkableBehavior
|
||||||
|
* Light-weight approach for data mining on deep relations between models.
|
||||||
|
* Join tables based on model relations to easily enable right to left find operations.
|
||||||
|
*
|
||||||
|
* Can be used as a alternative to the ContainableBehavior:
|
||||||
|
* - On data fetching only in right to left operations,
|
||||||
|
* wich means that in "one to many" relations (hasMany, hasAndBelongsToMany)
|
||||||
|
* should only be used from the "many to one" tables. i.e:
|
||||||
|
* To fetch all Users assigneds to a Project with ProjectAssignment,
|
||||||
|
* $Project->find('all', array('link' => 'User', 'conditions' => 'project_id = 1'))
|
||||||
|
* - Won't produce the desired result as data came from users table will be lost.
|
||||||
|
* $User->find('all', array('link' => 'Project', 'conditions' => 'project_id = 1'))
|
||||||
|
* - Will fetch all users related to the specified project in one query
|
||||||
|
*
|
||||||
|
* - On data mining as a much lighter approach - can reduce 300+ query find operations
|
||||||
|
* in one single query with joins; "or your money back!" ;-)
|
||||||
|
*
|
||||||
|
* - Has the 'fields' param enabled to make it easy to replace Containable usage,
|
||||||
|
* only change the 'contain' param to 'link'.
|
||||||
|
*
|
||||||
|
* Linkable Behavior. Taking it easy in your DB.
|
||||||
|
* RafaelBandeira <rafaelbandeira3(at)gmail(dot)com>
|
||||||
|
*
|
||||||
|
* Licensed under The MIT License
|
||||||
|
* Redistributions of files must retain the above copyright notice.
|
||||||
|
*
|
||||||
|
* @version 1.0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* NOTE TO <AP> 20090615:
|
||||||
|
* This structure should be linkable (it was my test case).
|
||||||
|
|
||||||
|
$entry = $this->LedgerEntry->find
|
||||||
|
('first',
|
||||||
|
array('link' => array('DebitLedger' =>
|
||||||
|
array(
|
||||||
|
'fields' => array('id'),
|
||||||
|
'alias' => 'MyDebitLedger',
|
||||||
|
'Account' =>
|
||||||
|
array(
|
||||||
|
'fields' => array('id'),
|
||||||
|
'alias' => 'MyDebitAccount'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'MyCreditLedger' =>
|
||||||
|
array(
|
||||||
|
'fields' => array('id'),
|
||||||
|
'class' => 'CreditLedger',
|
||||||
|
'MyCreditAccount' =>
|
||||||
|
array(
|
||||||
|
'fields' => array('id'),
|
||||||
|
'class' => 'Account'),
|
||||||
|
),
|
||||||
|
|
||||||
|
'MyOtherLedger' =>
|
||||||
|
array(
|
||||||
|
'fields' => array('id'),
|
||||||
|
'class' => 'Ledger',
|
||||||
|
'alias' => 'AliasToMyOtherLedger',
|
||||||
|
'Account' =>
|
||||||
|
array(
|
||||||
|
'fields' => array('id'),
|
||||||
|
'alias' => 'AliasToMyOtherAccount'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
'conditions' => array('LedgerEntry.id' => $id),
|
||||||
|
));
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
class LinkableBehavior extends ModelBehavior {
|
||||||
|
|
||||||
|
protected $_key = 'link';
|
||||||
|
|
||||||
|
protected $_options = array(
|
||||||
|
'type' => true, 'table' => true, 'alias' => true, 'joins' => true,
|
||||||
|
'conditions' => true, 'fields' => true, 'reference' => true,
|
||||||
|
'class' => true, 'defaults' => true, 'linkalias' => true,
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $_defaults = array('type' => 'LEFT');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a function for made recursive str_replaces in an array
|
||||||
|
* NOTE: The palacement of this function is terrible, but I don't
|
||||||
|
* know if I really want to go down this path or not.
|
||||||
|
*/
|
||||||
|
function recursive_array_replace($find, $replace, &$data) {
|
||||||
|
if (!isset($data))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is_array($data)) {
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if (is_array($value)) {
|
||||||
|
$this->recursive_array_replace($find, $replace, $data[$key]);
|
||||||
|
} else {
|
||||||
|
$data[$key] = str_replace($find, $replace, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data = str_replace($find, $replace, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function beforeFind(&$Model, $query) {
|
||||||
|
/* pr("Linkable::beforeFind() begin"); pr($query); */
|
||||||
|
if (isset($query[$this->_key])) {
|
||||||
|
$optionsDefaults = $this->_defaults + array('reference' =>
|
||||||
|
array('class' => $Model->alias,
|
||||||
|
'alias' => $Model->alias),
|
||||||
|
$this->_key => array());
|
||||||
|
$optionsKeys = $this->_options + array($this->_key => true);
|
||||||
|
if (!isset($query['fields']) || $query['fields'] === true) {
|
||||||
|
//$query['fields'] = array_keys($Model->_schema);
|
||||||
|
$query['fields'] = $Model->getDataSource()->fields($Model);
|
||||||
|
} elseif (!is_array($query['fields'])) {
|
||||||
|
$query['fields'] = array($query['fields']);
|
||||||
|
}
|
||||||
|
$query = am(array('joins' => array()), $query, array('recursive' => -1));
|
||||||
|
$iterators[] = $query[$this->_key];
|
||||||
|
$cont = 0;
|
||||||
|
do {
|
||||||
|
$iterator = $iterators[$cont];
|
||||||
|
$defaults = $optionsDefaults;
|
||||||
|
if (isset($iterator['defaults'])) {
|
||||||
|
$defaults = array_merge($defaults, $iterator['defaults']);
|
||||||
|
unset($iterator['defaults']);
|
||||||
|
}
|
||||||
|
$iterations = Set::normalize($iterator);
|
||||||
|
/* pr(array('checkpoint' => 'Iterations', compact('iterations'))); */
|
||||||
|
foreach ($iterations as $alias => $options) {
|
||||||
|
if (is_null($options)) {
|
||||||
|
$options = array();
|
||||||
|
}
|
||||||
|
$options = am($defaults, compact('alias'), $options);
|
||||||
|
if (empty($options['alias'])) {
|
||||||
|
throw new InvalidArgumentException(sprintf('%s::%s must receive aliased links', get_class($this), __FUNCTION__));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($options['class']))
|
||||||
|
$options['class'] = $alias;
|
||||||
|
|
||||||
|
/* pr(array('checkpoint' => 'Begin Model Work', compact('alias', 'options'))); */
|
||||||
|
|
||||||
|
$modelClass = $options['class'];
|
||||||
|
$modelAlias = $options['alias'];
|
||||||
|
$referenceClass = $options['reference']['class'];
|
||||||
|
$referenceAlias = $options['reference']['alias'];
|
||||||
|
|
||||||
|
$_Model =& ClassRegistry::init($modelClass); // the incoming model to be linked in query
|
||||||
|
$Reference =& ClassRegistry::init($referenceClass); // the already in query model that links to $_Model
|
||||||
|
/* pr(array('checkpoint' => 'Aliases Established', */
|
||||||
|
/* 'Model' => ($modelAlias .' : '. $modelClass . */
|
||||||
|
/* ' ('. $_Model->alias .' : '. $_Model->name .')'), */
|
||||||
|
/* 'Reference' => ($referenceAlias .' : '. $referenceClass . */
|
||||||
|
/* ' ('. $Reference->alias .' : '. $Reference->name .')'))); */
|
||||||
|
|
||||||
|
$db =& $_Model->getDataSource();
|
||||||
|
|
||||||
|
$associatedThroughReference = 0;
|
||||||
|
$association = null;
|
||||||
|
|
||||||
|
// Figure out how these two models are related, creating
|
||||||
|
// a relationship if one doesn't otherwise already exists.
|
||||||
|
if (($associations = $Reference->getAssociated()) &&
|
||||||
|
isset($associations[$_Model->alias])) {
|
||||||
|
/* pr("Reference defines association to _Model"); */
|
||||||
|
$associatedThroughReference = 1;
|
||||||
|
$type = $associations[$_Model->alias];
|
||||||
|
$association = $Reference->{$type}[$_Model->alias];
|
||||||
|
}
|
||||||
|
elseif (($associations = $_Model->getAssociated()) &&
|
||||||
|
isset($associations[$Reference->alias])) {
|
||||||
|
/* pr("_Model defines association to Reference"); */
|
||||||
|
$type = $associations[$Reference->alias];
|
||||||
|
$association = $_Model->{$type}[$Reference->alias];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// No relationship... make our best effort to create one.
|
||||||
|
/* pr("No assocation between _Model and Reference"); */
|
||||||
|
$type = 'belongsTo';
|
||||||
|
$_Model->bind($Reference->alias);
|
||||||
|
// Grab the association now, since we'll unbind in a moment.
|
||||||
|
$association = $_Model->{$type}[$Reference->alias];
|
||||||
|
$_Model->unbindModel(array('belongsTo' => array($Reference->alias)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine which model holds the foreign key
|
||||||
|
if (($type === 'hasMany' || $type === 'hasOne') ^ $associatedThroughReference) {
|
||||||
|
$primaryAlias = $referenceAlias;
|
||||||
|
$foreignAlias = $modelAlias;
|
||||||
|
$primaryModel = $Reference;
|
||||||
|
$foreignModel = $_Model;
|
||||||
|
} else {
|
||||||
|
$primaryAlias = $modelAlias;
|
||||||
|
$foreignAlias = $referenceAlias;
|
||||||
|
$primaryModel = $_Model;
|
||||||
|
$foreignModel = $Reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($associatedThroughReference)
|
||||||
|
$associationAlias = $referenceAlias;
|
||||||
|
else
|
||||||
|
$associationAlias = $modelAlias;
|
||||||
|
|
||||||
|
$this->recursive_array_replace("%{MODEL_ALIAS}",
|
||||||
|
$associationAlias,
|
||||||
|
$association['conditions']);
|
||||||
|
|
||||||
|
/* pr(array('checkpoint' => 'Models Established - Check Associations', */
|
||||||
|
/* 'primaryModel' => $primaryAlias .' : '. $primaryModel->name, */
|
||||||
|
/* 'foreignModel' => $foreignAlias .' : '. $foreignModel->name, */
|
||||||
|
/* compact('type', 'association'))); */
|
||||||
|
|
||||||
|
if (empty($options['conditions'])) {
|
||||||
|
if ($type === 'hasAndBelongsToMany') {
|
||||||
|
if (isset($association['with']))
|
||||||
|
$linkClass = $association['with'];
|
||||||
|
else
|
||||||
|
$linkClass = Inflector::classify($association['joinTable']);
|
||||||
|
|
||||||
|
$Link =& $_Model->{$linkClass};
|
||||||
|
|
||||||
|
if (isset($options['linkalias']))
|
||||||
|
$linkAlias = $options['linkalias'];
|
||||||
|
else
|
||||||
|
$linkAlias = $Link->alias;
|
||||||
|
|
||||||
|
// Get the foreign key fields (for the link table) directly from
|
||||||
|
// the defined model associations, if they exists. This is the
|
||||||
|
// users direct specification, and therefore definitive if present.
|
||||||
|
$modelLink = $Link->escapeField($association['foreignKey'], $linkAlias);
|
||||||
|
$referenceLink = $Link->escapeField($association['associationForeignKey'], $linkAlias);
|
||||||
|
|
||||||
|
// If we haven't figured out the foreign keys, see if there is a
|
||||||
|
// model for the link table, and if it has the appropriate
|
||||||
|
// associations with the two tables we're trying to join.
|
||||||
|
if (empty($modelLink) && isset($Link->belongsTo[$_Model->alias]))
|
||||||
|
$modelLink = $Link->escapeField($Link->belongsTo[$_Model->alias]['foreignKey'], $linkAlias);
|
||||||
|
if (empty($referenceLink) && isset($Link->belongsTo[$Reference->alias]))
|
||||||
|
$referenceLink = $Link->escapeField($Link->belongsTo[$Reference->alias]['foreignKey'], $linkAlias);
|
||||||
|
|
||||||
|
// We're running quite thin here. None of the models spell
|
||||||
|
// out the appropriate linkages. We'll have to SWAG it.
|
||||||
|
if (empty($modelLink))
|
||||||
|
$modelLink = $Link->escapeField(Inflector::underscore($_Model->alias) . '_id', $linkAlias);
|
||||||
|
if (empty($referenceLink))
|
||||||
|
$referenceLink = $Link->escapeField(Inflector::underscore($Reference->alias) . '_id', $linkAlias);
|
||||||
|
|
||||||
|
// Get the primary key from the tables we're joining.
|
||||||
|
$referenceKey = $Reference->escapeField(null, $referenceAlias);
|
||||||
|
$modelKey = $_Model->escapeField(null, $modelAlias);
|
||||||
|
|
||||||
|
// Join the linkage table to our model. We'll use an inner join,
|
||||||
|
// as the whole purpose of the linkage table is to make this
|
||||||
|
// connection. As we are embedding this join, the INNER will not
|
||||||
|
// cause any problem with the overall query, should the user not
|
||||||
|
// be concerned with whether or not the join has any results.
|
||||||
|
// They control that with the 'type' parameter which will be at
|
||||||
|
// the top level join.
|
||||||
|
$options['joins'][] = array('type' => 'INNER',
|
||||||
|
'alias' => $modelAlias,
|
||||||
|
'conditions' => "{$modelKey} = {$modelLink}",
|
||||||
|
'table' => $db->fullTableName($_Model, true));
|
||||||
|
|
||||||
|
// Now for the top level join. This will be added into the list
|
||||||
|
// of joins down below, outside of the HABTM specific code.
|
||||||
|
$options['class'] = $linkClass;
|
||||||
|
$options['alias'] = $linkAlias;
|
||||||
|
$options['table'] = $Link->getDataSource()->fullTableName($Link);
|
||||||
|
$options['conditions'][] = "{$referenceLink} = {$referenceKey}";
|
||||||
|
}
|
||||||
|
elseif (isset($association['foreignKey']) && $association['foreignKey']) {
|
||||||
|
$foreignKey = $primaryModel->escapeField($association['foreignKey'], $primaryAlias);
|
||||||
|
$primaryKey = $foreignModel->escapeField($foreignModel->primaryKey, $foreignAlias);
|
||||||
|
|
||||||
|
// Only differentiating to help show the logical flow.
|
||||||
|
// Either way works and this test can be tossed out
|
||||||
|
if (($type === 'hasMany' || $type === 'hasOne') ^ $associatedThroughReference)
|
||||||
|
$options['conditions'][] = "{$primaryKey} = {$foreignKey}";
|
||||||
|
else
|
||||||
|
$options['conditions'][] = "{$foreignKey} = {$primaryKey}";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// No Foreign Key... nothing we can do.
|
||||||
|
$options['conditions'] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The user may have specified conditions directly in the model
|
||||||
|
// for this join. Make sure to adhere to those conditions.
|
||||||
|
if (isset($association['conditions']) && is_array($association['conditions']))
|
||||||
|
$options['conditions'] = array_merge($options['conditions'], $association['conditions']);
|
||||||
|
elseif (!empty($association['conditions']))
|
||||||
|
$options['conditions'][] = $association['conditions'];
|
||||||
|
|
||||||
|
}
|
||||||
|
if (empty($options['table'])) {
|
||||||
|
$options['table'] = $db->fullTableName($_Model, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($options['fields']) || !is_array($options['fields']))
|
||||||
|
$options['fields'] = $db->fields($_Model, $modelAlias);
|
||||||
|
elseif (!empty($options['fields']))
|
||||||
|
$options['fields'] = $db->fields($_Model, $modelAlias, $options['fields']);
|
||||||
|
|
||||||
|
$query['fields'] = array_merge($query['fields'], $options['fields'],
|
||||||
|
(empty($association['fields'])
|
||||||
|
? array() : $db->fields($_Model, $modelAlias, $association['fields'])));
|
||||||
|
|
||||||
|
/* pr(array('checkpoint' => 'Model Work Complete', compact('options', 'modelClass', 'modelAlias'))); */
|
||||||
|
|
||||||
|
$options[$this->_key] = am($options[$this->_key], array_diff_key($options, $optionsKeys));
|
||||||
|
$options = array_intersect_key($options, $optionsKeys);
|
||||||
|
if (!empty($options[$this->_key])) {
|
||||||
|
$iterators[] = $options[$this->_key] +
|
||||||
|
array('defaults' =>
|
||||||
|
array_merge($defaults,
|
||||||
|
array('reference' =>
|
||||||
|
array('class' => $modelClass,
|
||||||
|
'alias' => $modelAlias))));
|
||||||
|
}
|
||||||
|
$query['joins'][] = array_intersect_key($options, array('type' => true, 'alias' => true, 'table' => true, 'joins' => true, 'conditions' => true));
|
||||||
|
}
|
||||||
|
++$cont;
|
||||||
|
$notDone = isset($iterators[$cont]);
|
||||||
|
} while ($notDone);
|
||||||
|
}
|
||||||
|
/* pr(array('checkpoint' => 'Linkable::beforeFind() end', */
|
||||||
|
/* compact('query'))); */
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
class Contact extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Contact';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'display_name' => array('notempty'),
|
||||||
|
'id_federal' => array('ssn'),
|
||||||
|
'id_exp' => array('date')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasAndBelongsToMany = array(
|
||||||
|
'Customer',
|
||||||
|
'ContactAddress' => array(
|
||||||
|
'joinTable' => 'contacts_methods',
|
||||||
|
'associationForeignKey' => 'method_id',
|
||||||
|
'unique' => true,
|
||||||
|
'conditions' => "method = 'POST'",
|
||||||
|
),
|
||||||
|
'ContactPhone' => array(
|
||||||
|
'joinTable' => 'contacts_methods',
|
||||||
|
'associationForeignKey' => 'method_id',
|
||||||
|
'unique' => true,
|
||||||
|
'conditions' => "method = 'PHONE'",
|
||||||
|
),
|
||||||
|
'ContactEmail' => array(
|
||||||
|
'joinTable' => 'contacts_methods',
|
||||||
|
'associationForeignKey' => 'method_id',
|
||||||
|
'unique' => true,
|
||||||
|
'conditions' => "method = 'EMAIL'",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
class ContactAddress extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'ContactAddress';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'postcode' => array('postal')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasAndBelongsToMany = array(
|
||||||
|
'Contact' => array(
|
||||||
|
'className' => 'Contact',
|
||||||
|
'joinTable' => 'contacts_methods',
|
||||||
|
'foreignKey' => 'method_id',
|
||||||
|
'associationForeignKey' => 'contact_id',
|
||||||
|
'unique' => true,
|
||||||
|
'conditions' => "method = 'POST'",
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
class ContactEmail extends AppModel {
|
class ContactEmail extends AppModel {
|
||||||
|
|
||||||
var $name = 'ContactEmail';
|
var $name = 'ContactEmail';
|
||||||
var $displayField = 'email';
|
|
||||||
var $validate = array(
|
var $validate = array(
|
||||||
'id' => array('numeric'),
|
'id' => array('numeric'),
|
||||||
'email' => array('email')
|
'email' => array('email')
|
||||||
@@ -19,9 +18,5 @@ class ContactEmail extends AppModel {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
function emailList() {
|
|
||||||
return $this->find('list');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
class ContactPhone extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'ContactPhone';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
//'type' => array('inlist'),
|
||||||
|
'phone' => array('phone'),
|
||||||
|
'ext' => array('numeric')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasAndBelongsToMany = array(
|
||||||
|
'Contact' => array(
|
||||||
|
'className' => 'Contact',
|
||||||
|
'joinTable' => 'contacts_methods',
|
||||||
|
'foreignKey' => 'method_id',
|
||||||
|
'associationForeignKey' => 'contact_id',
|
||||||
|
'unique' => true,
|
||||||
|
'conditions' => "method = 'PHONE'",
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
<?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',
|
||||||
|
'LedgerEntry',
|
||||||
|
|
||||||
|
// Cheat to get Account set as part of this class
|
||||||
|
'Account',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasAndBelongsToMany = array(
|
||||||
|
'Contact',
|
||||||
|
'Transaction' => array(
|
||||||
|
'joinTable' => 'ledger_entries',
|
||||||
|
'foreignKey' => 'customer_id',
|
||||||
|
'associationForeignKey' => 'transaction_id',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* 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: findSecurityDeposits
|
||||||
|
* - Returns an array of security deposit entries
|
||||||
|
*/
|
||||||
|
function findSecurityDeposits($id, $link = null) {
|
||||||
|
/* pr(array('function' => 'Customer::findSecurityDeposits', */
|
||||||
|
/* 'args' => compact('id', 'link'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
$entries = $this->Account->findLedgerEntriesRelatedToAccount
|
||||||
|
($this->Account->invoiceAccountID(),
|
||||||
|
$this->Account->securityDepositAccountID(),
|
||||||
|
true, array('LedgerEntry.customer_id' => $id), $link);
|
||||||
|
|
||||||
|
/* pr(array('function' => 'Customer::findSecurityDeposits', */
|
||||||
|
/* 'args' => compact('id', 'link'), */
|
||||||
|
/* 'vars' => compact('customer'), */
|
||||||
|
/* 'return' => compact('entries'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findUnreconciledLedgerEntries
|
||||||
|
* - Returns ledger entries that are not yet reconciled
|
||||||
|
* (such as charges not paid).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null) {
|
||||||
|
$unreconciled = $this->Account->findUnreconciledLedgerEntries
|
||||||
|
($this->Account->accountReceivableAccountID(),
|
||||||
|
$fundamental_type,
|
||||||
|
array('LedgerEntry.customer_id' => $id));
|
||||||
|
|
||||||
|
return $unreconciled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: reconcileNewLedgerEntry
|
||||||
|
* - Returns which ledger entries a new credit/debit would
|
||||||
|
* reconcile, and how much.
|
||||||
|
*
|
||||||
|
* - REVISIT <AP> 20090617
|
||||||
|
* This should be subject to different algorithms, such
|
||||||
|
* as apply to oldest charges first, newest first, to fees
|
||||||
|
* before rent, etc. Until we get there, I'll hardcode
|
||||||
|
* whatever algorithm is simplest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function reconcileNewLedgerEntry($id, $fundamental_type, $amount) {
|
||||||
|
$reconciled = $this->Account->reconcileNewLedgerEntry
|
||||||
|
($this->Account->accountReceivableAccountID(),
|
||||||
|
$fundamental_type,
|
||||||
|
$amount,
|
||||||
|
array('LedgerEntry.customer_id' => $id));
|
||||||
|
|
||||||
|
return $reconciled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: details
|
||||||
|
* - Returns detail information for the customer
|
||||||
|
*/
|
||||||
|
|
||||||
|
function details($id = null) {
|
||||||
|
// Query the DB for need information.
|
||||||
|
$customer = $this->find
|
||||||
|
('first', array
|
||||||
|
('contain' => array
|
||||||
|
(// Models
|
||||||
|
'Contact' =>
|
||||||
|
array(// 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->findSecurityDeposits($id);
|
||||||
|
|
||||||
|
return $customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested customer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function stats($id = null) {
|
||||||
|
if (!$id)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
$stats = $this->Account->stats($this->Account->accountReceivableAccountID(), true,
|
||||||
|
array('LedgerEntry.customer_id' => $id));
|
||||||
|
|
||||||
|
// Pull to the top level and return
|
||||||
|
$stats = $stats['Ledger'];
|
||||||
|
return $stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
<?php
|
||||||
|
class Lease extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Lease';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'number' => array('alphanumeric'),
|
||||||
|
'lease_type_id' => array('numeric'),
|
||||||
|
'unit_id' => array('numeric'),
|
||||||
|
'late_schedule_id' => array('numeric'),
|
||||||
|
'lease_date' => array('date'),
|
||||||
|
'movein_planned_date' => array('date'),
|
||||||
|
'movein_date' => array('date'),
|
||||||
|
'moveout_date' => array('date'),
|
||||||
|
'moveout_planned_date' => array('date'),
|
||||||
|
'notice_given_date' => array('date'),
|
||||||
|
'notice_received_date' => array('date'),
|
||||||
|
'close_date' => array('date'),
|
||||||
|
'deposit' => array('money'),
|
||||||
|
'amount' => array('money'),
|
||||||
|
'next_amount' => array('money'),
|
||||||
|
'next_amount_date' => array('date')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'LeaseType',
|
||||||
|
'Unit',
|
||||||
|
'Customer',
|
||||||
|
'LateSchedule',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'LedgerEntry',
|
||||||
|
|
||||||
|
// Cheat to get Account set as part of this class
|
||||||
|
'Account',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: accountId
|
||||||
|
* - Returns the accountId of the given lease
|
||||||
|
*/
|
||||||
|
function accountId($id) {
|
||||||
|
return $this->Account->invoiceAccountID();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findAccountEntries
|
||||||
|
* - Returns an array of ledger entries from the account of the given
|
||||||
|
* lease.
|
||||||
|
*/
|
||||||
|
function findAccountEntries($id, $all = false, $cond = null, $link = null) {
|
||||||
|
/* pr(array('function' => 'Lease::findAccountEntries', */
|
||||||
|
/* 'args' => compact('id', 'all', 'cond', 'link'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
if (!isset($cond))
|
||||||
|
$cond = array();
|
||||||
|
$cond[] = array('LedgerEntry.lease_id' => $id);
|
||||||
|
|
||||||
|
$entries = $this->Account->findLedgerEntries($this->accountId($id),
|
||||||
|
$all, $cond, $link);
|
||||||
|
|
||||||
|
/* pr(array('function' => 'Lease::findAccountEntries', */
|
||||||
|
/* 'args' => compact('id', 'all', 'cond', 'link'), */
|
||||||
|
/* 'vars' => compact('lease'), */
|
||||||
|
/* 'return' => compact('entries'), */
|
||||||
|
/* )); */
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findSecurityDeposits
|
||||||
|
* - Returns an array of security deposit entries
|
||||||
|
*/
|
||||||
|
function findSecurityDeposits($id, $link = null) {
|
||||||
|
/* pr(array('function' => 'Lease::findSecurityDeposits', */
|
||||||
|
/* 'args' => compact('id', 'link'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
$entries = $this->Account->findLedgerEntriesRelatedToAccount
|
||||||
|
($this->accountId($id),
|
||||||
|
$this->Account->securityDepositAccountID(),
|
||||||
|
true, array('LedgerEntry.lease_id' => $id), $link);
|
||||||
|
|
||||||
|
/* pr(array('function' => 'Lease::findSecurityDeposits', */
|
||||||
|
/* 'args' => compact('id', 'link'), */
|
||||||
|
/* 'vars' => compact('lease'), */
|
||||||
|
/* 'return' => compact('entries'), */
|
||||||
|
/* )); */
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findUnreconciledLedgerEntries
|
||||||
|
* - Returns ledger entries that are not yet reconciled
|
||||||
|
* (such as charges not paid).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function findUnreconciledLedgerEntries($id = null, $fundamental_type = null) {
|
||||||
|
return $this->Account->findUnreconciledLedgerEntries
|
||||||
|
($this->accountId($id), $fundamental_type, array('LedgerEntry.lease_id' => $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: reconcileNewLedgerEntry
|
||||||
|
* - Returns which ledger entries a new credit/debit would
|
||||||
|
* reconcile, and how much.
|
||||||
|
*
|
||||||
|
* - REVISIT <AP> 20090617
|
||||||
|
* This should be subject to different algorithms, such
|
||||||
|
* as apply to oldest charges first, newest first, to fees
|
||||||
|
* before rent, etc. Until we get there, I'll hardcode
|
||||||
|
* whatever algorithm is simplest.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function reconcileNewLedgerEntry($id, $fundamental_type, $amount) {
|
||||||
|
return $this->Account->reconcileNewLedgerEntry
|
||||||
|
($this->accountId($id), $fundamental_type, $amount, array('LedgerEntry.lease_id' => $id));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested lease.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function stats($id = null) {
|
||||||
|
if (!$id)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
$stats = $this->Account->stats($this->Account->accountReceivableAccountID(), true,
|
||||||
|
array('LedgerEntry.lease_id' => $id));
|
||||||
|
|
||||||
|
// Pull to the top level and return
|
||||||
|
$stats = $stats['Ledger'];
|
||||||
|
return $stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
<?php
|
||||||
|
class Ledger extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Ledger';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'name' => array('notempty'),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'Account',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'LedgerEntry' => array(
|
||||||
|
'foreignKey' => false,
|
||||||
|
|
||||||
|
// conditions will be used when JOINing tables
|
||||||
|
// (such as find with LinkableBehavior)
|
||||||
|
'conditions' => array('OR' =>
|
||||||
|
array('LedgerEntry.debit_ledger_id = %{MODEL_ALIAS}.id',
|
||||||
|
'LedgerEntry.credit_ledger_id = %{MODEL_ALIAS}.id')),
|
||||||
|
|
||||||
|
// finderQuery will be used when tables are put
|
||||||
|
// together across several querys, not with JOIN.
|
||||||
|
// (such as find with ContainableBehavior)
|
||||||
|
'finderQuery' => 'SELECT `LedgerEntry`.*
|
||||||
|
FROM pmgr_ledger_entries AS `LedgerEntry`
|
||||||
|
WHERE LedgerEntry.debit_ledger_id = ({$__cakeID__$})
|
||||||
|
OR LedgerEntry.credit_ledger_id = ({$__cakeID__$})',
|
||||||
|
|
||||||
|
'counterQuery' => ''
|
||||||
|
),
|
||||||
|
'DebitLedgerEntry' => array(
|
||||||
|
'className' => 'LedgerEntry',
|
||||||
|
'foreignKey' => 'debit_ledger_id',
|
||||||
|
'dependent' => false,
|
||||||
|
),
|
||||||
|
'CreditLedgerEntry' => array(
|
||||||
|
'className' => 'LedgerEntry',
|
||||||
|
'foreignKey' => 'credit_ledger_id',
|
||||||
|
'dependent' => false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findLedgerEntries
|
||||||
|
* - Returns an array of ledger entries that belong to a given
|
||||||
|
* ledger. There is extra work done... see the LedgerEntry model.
|
||||||
|
*/
|
||||||
|
function findLedgerEntries($id, $account_type = null, $cond = null, $link = null) {
|
||||||
|
/* pr(array('function' => 'Ledger::findLedgerEntries', */
|
||||||
|
/* 'args' => compact('id', 'account_type', 'cond', 'link'), */
|
||||||
|
/* )); */
|
||||||
|
|
||||||
|
if (!isset($account_type)) {
|
||||||
|
$ledger = $this->find('first', array
|
||||||
|
('contain' => array
|
||||||
|
('Account' => array
|
||||||
|
('fields' => array('type'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'fields' => array(),
|
||||||
|
'conditions' => array(array('Ledger.id' => $id)),
|
||||||
|
));
|
||||||
|
$account_type = $ledger['Account']['type'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the requested entries are limited by date, we must calculate
|
||||||
|
// a balance forward, or the resulting balance will be thrown off.
|
||||||
|
//
|
||||||
|
// REVISIT <AP>: This obviously is more general than date.
|
||||||
|
// As such, it will not work (or, only work if the
|
||||||
|
// condition only manages to exclude the first parts
|
||||||
|
// of the ledger, nothing in the middle or at the
|
||||||
|
// end. For now, I'll just create an 'other' entry,
|
||||||
|
// not necessarily a balance forward.
|
||||||
|
|
||||||
|
$bf = array();
|
||||||
|
if (0 && isset($cond)) {
|
||||||
|
//$date = '<NOT IMPLEMENTED>';
|
||||||
|
$stats = $this->stats($id, array('NOT' => array($cond)));
|
||||||
|
$bf = array(array(array('debit' => $stats['debits'],
|
||||||
|
'credit' => $stats['credits'],
|
||||||
|
'balance' => $stats['balance']),
|
||||||
|
|
||||||
|
'LedgerEntry' => array('id' => null,
|
||||||
|
//'comment' => "Balance Forward from $date"),
|
||||||
|
'comment' => "-- SUMMARY OF EXCLUDED ENTRIES --"),
|
||||||
|
|
||||||
|
'Transaction' => array('id' => null,
|
||||||
|
//'stamp' => $date,
|
||||||
|
'stamp' => null,
|
||||||
|
'comment' => null),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries = $this->LedgerEntry->findInLedgerContext($id, $account_type, $cond, $link);
|
||||||
|
/* pr(array('function' => 'Ledger::findLedgerEntries', */
|
||||||
|
/* 'args' => compact('id', 'account_type', 'cond', 'link'), */
|
||||||
|
/* 'vars' => compact('ledger'), */
|
||||||
|
/* 'return' => compact('entries'), */
|
||||||
|
/* )); */
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested ledger.
|
||||||
|
*/
|
||||||
|
function stats($id, $cond = null) {
|
||||||
|
if (!isset($cond))
|
||||||
|
$cond = array();
|
||||||
|
$cond[] = array('Ledger.id' => $id);
|
||||||
|
|
||||||
|
$stats = $this->find
|
||||||
|
('first', array
|
||||||
|
('link' =>
|
||||||
|
array(// Models
|
||||||
|
'Account' => array('fields' => array()),
|
||||||
|
//'LedgerEntry' => array('fields' => array()),
|
||||||
|
'LedgerEntry' =>
|
||||||
|
array('fields' => array(),
|
||||||
|
'Transaction' => array('fields' => array('stamp')),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'fields' =>
|
||||||
|
array("SUM(IF(LedgerEntry.debit_ledger_id = Ledger.id,
|
||||||
|
LedgerEntry.amount, NULL)) AS debits",
|
||||||
|
"SUM(IF(LedgerEntry.credit_ledger_id = Ledger.id,
|
||||||
|
LedgerEntry.amount, NULL)) AS credits",
|
||||||
|
"SUM(IF(Account.type IN ('ASSET', 'EXPENSE'),
|
||||||
|
IF(LedgerEntry.debit_ledger_id = Ledger.id, 1, -1),
|
||||||
|
IF(LedgerEntry.credit_ledger_id = Ledger.id, 1, -1)
|
||||||
|
) * IF(LedgerEntry.amount, LedgerEntry.amount, 0)
|
||||||
|
) AS balance",
|
||||||
|
"COUNT(LedgerEntry.id) AS entries"),
|
||||||
|
'conditions' => $cond,
|
||||||
|
'group' => 'Ledger.id',
|
||||||
|
));
|
||||||
|
|
||||||
|
// The fields are all tucked into the [0] index,
|
||||||
|
// and the rest of the array is useless (empty).
|
||||||
|
return $stats[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
<?php
|
||||||
|
class LedgerEntry extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'LedgerEntry';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'transaction_id' => array('numeric'),
|
||||||
|
'amount' => array('money')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'MonetarySource',
|
||||||
|
'Transaction',
|
||||||
|
'Customer',
|
||||||
|
'Lease',
|
||||||
|
|
||||||
|
'DebitLedger' => array(
|
||||||
|
'className' => 'Ledger',
|
||||||
|
'foreignKey' => 'debit_ledger_id',
|
||||||
|
),
|
||||||
|
'CreditLedger' => array(
|
||||||
|
'className' => 'Ledger',
|
||||||
|
'foreignKey' => 'credit_ledger_id',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasAndBelongsToMany = array(
|
||||||
|
'DebitReconciliationLedgerEntry' => array(
|
||||||
|
'className' => 'LedgerEntry',
|
||||||
|
'joinTable' => 'reconciliations',
|
||||||
|
'foreignKey' => 'credit_ledger_entry_id',
|
||||||
|
'associationForeignKey' => 'debit_ledger_entry_id',
|
||||||
|
),
|
||||||
|
'CreditReconciliationLedgerEntry' => array(
|
||||||
|
'className' => 'LedgerEntry',
|
||||||
|
'joinTable' => 'reconciliations',
|
||||||
|
'foreignKey' => 'debit_ledger_entry_id',
|
||||||
|
'associationForeignKey' => 'credit_ledger_entry_id',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: conditionEntryAsCreditOrDebit
|
||||||
|
* - returns the condition necessary to match a set of
|
||||||
|
* Ledgers to all related LedgerEntries
|
||||||
|
*/
|
||||||
|
function conditionEntryAsCreditOrDebit($ledger_ids) {
|
||||||
|
return array('OR' =>
|
||||||
|
array(array('debit_ledger_id' => $ledger_ids),
|
||||||
|
array('credit_ledger_id' => $ledger_ids)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: ledgerContext query helpers
|
||||||
|
* - Returns parameters necessary to generate a query which
|
||||||
|
* puts ledger entries into the context of a ledger. Since
|
||||||
|
* debit/credit depends on the account type, it is required
|
||||||
|
* as an argument for each function to avoid having to
|
||||||
|
* query the ledger/account to find it out.
|
||||||
|
*/
|
||||||
|
function ledgerContextFields($ledger_id = null, $account_type = null) {
|
||||||
|
$fields = array('id', 'name', 'comment', 'amount');
|
||||||
|
|
||||||
|
if (isset($ledger_id)) {
|
||||||
|
$fields[] = ("IF(LedgerEntry.debit_ledger_id = $ledger_id," .
|
||||||
|
" LedgerEntry.amount, NULL) AS debit");
|
||||||
|
$fields[] = ("IF(LedgerEntry.credit_ledger_id = $ledger_id," .
|
||||||
|
" LedgerEntry.amount, NULL) AS credit");
|
||||||
|
|
||||||
|
if (isset($account_type)) {
|
||||||
|
if (in_array($account_type, array('ASSET', 'EXPENSE')))
|
||||||
|
$ledger_type = 'debit';
|
||||||
|
else
|
||||||
|
$ledger_type = 'credit';
|
||||||
|
|
||||||
|
$fields[] = ("(IF(LedgerEntry.{$ledger_type}_ledger_id = $ledger_id," .
|
||||||
|
" 1, -1) * LedgerEntry.amount) AS balance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ledgerContextFields2($ledger_id = null, $account_id = null, $account_type = null) {
|
||||||
|
$fields = array('id', 'name', 'comment', 'amount');
|
||||||
|
|
||||||
|
if (isset($ledger_id)) {
|
||||||
|
$fields[] = ("IF(LedgerEntry.debit_ledger_id = $ledger_id," .
|
||||||
|
" SUM(LedgerEntry.amount), NULL) AS debit");
|
||||||
|
$fields[] = ("IF(LedgerEntry.credit_ledger_id = $ledger_id," .
|
||||||
|
" SUM(LedgerEntry.amount), NULL) AS credit");
|
||||||
|
|
||||||
|
if (isset($account_id) || isset($account_type)) {
|
||||||
|
$Account = new Account();
|
||||||
|
$account_ftype = $Account->fundamentalType($account_id ? $account_id : $account_type);
|
||||||
|
$fields[] = ("(IF(LedgerEntry.{$account_ftype}_ledger_id = $ledger_id," .
|
||||||
|
" 1, -1) * SUM(LedgerEntry.amount)) AS balance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (isset($account_id)) {
|
||||||
|
$fields[] = ("IF(DebitLedger.account_id = $account_id," .
|
||||||
|
" SUM(LedgerEntry.amount), NULL) AS debit");
|
||||||
|
$fields[] = ("IF(CreditLedger.account_id = $account_id," .
|
||||||
|
" SUM(LedgerEntry.amount), NULL) AS credit");
|
||||||
|
|
||||||
|
$Account = new Account();
|
||||||
|
$account_ftype = ucfirst($Account->fundamentalType($account_id));
|
||||||
|
$fields[] = ("(IF({$account_ftype}Ledger.account_id = $account_id," .
|
||||||
|
" 1, -1) * SUM(LedgerEntry.amount)) AS balance");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ledgerContextConditions($ledger_id, $account_type) {
|
||||||
|
if (isset($ledger_id)) {
|
||||||
|
return array
|
||||||
|
('OR' =>
|
||||||
|
array(array('LedgerEntry.debit_ledger_id' => $ledger_id),
|
||||||
|
array('LedgerEntry.credit_ledger_id' => $ledger_id)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findInLedgerContext
|
||||||
|
* - Returns an array of ledger entries that belong to a given ledger.
|
||||||
|
* There is extra logic to also figure out whether the ledger_entry
|
||||||
|
* amount is either a credit, or a debit, depending on how it was
|
||||||
|
* written into the ledger, as well as whether the amount increases or
|
||||||
|
* decreases the balance depending on the particular account type of
|
||||||
|
* the ledger.
|
||||||
|
*/
|
||||||
|
function findInLedgerContext($ledger_id, $account_type, $cond = null, $link = null) {
|
||||||
|
if (!isset($link))
|
||||||
|
$link = array('Transaction');
|
||||||
|
|
||||||
|
if (!isset($cond))
|
||||||
|
$cond = array();
|
||||||
|
|
||||||
|
$fields = $this->ledgerContextFields($ledger_id, $account_type);
|
||||||
|
$cond[] = $this->ledgerContextConditions($ledger_id, $account_type);
|
||||||
|
$order = array('Transaction.stamp');
|
||||||
|
|
||||||
|
$entries = $this->find
|
||||||
|
('all',
|
||||||
|
array('link' => $link,
|
||||||
|
'fields' => $fields,
|
||||||
|
'conditions' => $cond,
|
||||||
|
'order' => $order,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: findReconciledLedgerEntries
|
||||||
|
* - Returns ledger entries that are reconciled to the given entry.
|
||||||
|
* (such as payments towards a charge).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function findReconciledLedgerEntries($id = null, $fundamental_type = null) {
|
||||||
|
foreach (($fundamental_type
|
||||||
|
? array($fundamental_type)
|
||||||
|
: array('debit', 'credit')) AS $fund) {
|
||||||
|
$ucfund = ucfirst($fund);
|
||||||
|
$reconciled[$fund]['entry'] = $this->find
|
||||||
|
('all', array
|
||||||
|
('link' => array
|
||||||
|
("ReconciliationLedgerEntry" => array
|
||||||
|
('class' => "{$ucfund}ReconciliationLedgerEntry",
|
||||||
|
'fields' => array
|
||||||
|
('id',
|
||||||
|
"COALESCE(SUM(Reconciliation.amount),0) AS 'reconciled'",
|
||||||
|
"LedgerEntry.amount - COALESCE(SUM(Reconciliation.amount),0) AS 'balance'",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'group' => ("ReconciliationLedgerEntry.id"),
|
||||||
|
'conditions' => array('LedgerEntry.id' => $id),
|
||||||
|
'fields' => array(),
|
||||||
|
));
|
||||||
|
//pr($reconciled);
|
||||||
|
$balance = 0;
|
||||||
|
foreach ($reconciled[$fund]['entry'] AS &$entry) {
|
||||||
|
$entry = array_merge($entry["ReconciliationLedgerEntry"], $entry[0]);
|
||||||
|
$balance += $entry['balance'];
|
||||||
|
}
|
||||||
|
$reconciled[$fund]['balance'] = $balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $reconciled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
**************************************************************************
|
||||||
|
* function: stats
|
||||||
|
* - Returns summary data from the requested ledger entry
|
||||||
|
*/
|
||||||
|
function stats($id) {
|
||||||
|
|
||||||
|
$query = array
|
||||||
|
(
|
||||||
|
'fields' => array("SUM(Reconciliation.amount) AS 'reconciled'"),
|
||||||
|
|
||||||
|
'conditions' => array(isset($cond) ? $cond : array(),
|
||||||
|
array('LedgerEntry.id' => $id)),
|
||||||
|
|
||||||
|
'group' => 'LedgerEntry.id',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get the applied amounts on the debit side
|
||||||
|
$query['link'] =
|
||||||
|
array('DebitReconciliationLedgerEntry' => array('alias' => 'DRLE', 'DRLETransaction' => array('class' => 'Transaction')));
|
||||||
|
$tmpstats = $this->find('first', $query);
|
||||||
|
$stats['debit_amount_reconciled'] = $tmpstats[0]['reconciled'];
|
||||||
|
|
||||||
|
// Get the applied amounts on the credit side
|
||||||
|
$query['link'] =
|
||||||
|
array('CreditReconciliationLedgerEntry' => array('alias' => 'CRLE', 'CRLETransaction' => array('class' => 'Transaction')));
|
||||||
|
$tmpstats = $this->find('first', $query);
|
||||||
|
$stats['credit_amount_reconciled'] = $tmpstats[0]['reconciled'];
|
||||||
|
|
||||||
|
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,20 @@
|
|||||||
|
<?php
|
||||||
|
class MonetarySource extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'MonetarySource';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'name' => array('notempty'),
|
||||||
|
'tillable' => array('boolean')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'MonetaryType',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'LedgerEntry',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
class MonetaryType extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'MonetaryType';
|
||||||
|
var $validate = array(
|
||||||
|
'id' => array('numeric'),
|
||||||
|
'name' => array('notempty'),
|
||||||
|
'tillable' => array('boolean')
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'MonetarySource',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -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,28 @@
|
|||||||
|
<?php
|
||||||
|
class Transaction extends AppModel {
|
||||||
|
|
||||||
|
var $name = 'Transaction';
|
||||||
|
/* var $validate = array( */
|
||||||
|
/* 'stamp' => array('date') */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
|
var $belongsTo = array(
|
||||||
|
'Customer',
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'LedgerEntry',
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
function beforeSave() {
|
||||||
|
|
||||||
|
if(!empty($this->data['Transaction']['stamp'])) {
|
||||||
|
$this->data['Transaction']['stamp'] =
|
||||||
|
$this->dateFormatBeforeSave($this->data['Transaction']['stamp']);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<?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.close_date IS NULL',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
var $hasMany = array(
|
||||||
|
'Lease',
|
||||||
|
);
|
||||||
|
|
||||||
|
function statusEnums() {
|
||||||
|
static $status_enums;
|
||||||
|
if (!isset($status_enums))
|
||||||
|
$status_enums = $this->getEnumValues('status');
|
||||||
|
return $status_enums;
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 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',
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
Vendored
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
@@ -1,68 +0,0 @@
|
|||||||
N - GATE
|
|
||||||
N - ACH / CREDIT CARD PROCESSING
|
|
||||||
Y - CREDIT CARD ENTRY
|
|
||||||
Y - ACH ENTRY
|
|
||||||
P - INVENTORY TRACKING / POS
|
|
||||||
Y - UNIT TYPES
|
|
||||||
Y - UNIT SIZES
|
|
||||||
Y - UNITS
|
|
||||||
Y - MOVE IN / OUT
|
|
||||||
Y - UNIT TRANSFERS
|
|
||||||
Y - LEASE TRACKING (PDF Generation)
|
|
||||||
Y - LETTERS (PDF Generation)
|
|
||||||
Y - REMINDERS
|
|
||||||
Y - MULTIPLE LATE RENT SCHEDULES (Tenant A vs Tenant B)
|
|
||||||
Y - ACCOUNTING (assign charges to accounts)
|
|
||||||
Y - DETAILED REPORTING (HTML & PDF)
|
|
||||||
Y - SITE MAP; HOT CLICKABLE
|
|
||||||
P - PROSPECTIVE TENANTS
|
|
||||||
Y - MARKETING
|
|
||||||
P - RESERVATIONS
|
|
||||||
P - MOVE OUT NOTICES
|
|
||||||
P - MULTI-SITE (One database, multiple sites)
|
|
||||||
Y - GENERATE GEOGRAPHIC MAP OF CUSTOMERS USING GOOGLE!
|
|
||||||
- Major advantage here... MapPoint only choice with competitors
|
|
||||||
Y - WEB BASED
|
|
||||||
Y - CUSTOMER VIEW / MANAGER VIEW
|
|
||||||
Y - CUSTOMERS CAN CREATE ACCOUNTS, VIEW HISTORY
|
|
||||||
Y - CUSTOMERS CAN SIGN UP FOR AUTO PAY
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
Operations to be functional
|
|
||||||
'X' marks functionality sufficiently completed
|
|
||||||
|
|
||||||
X - Create Customer ID/Account
|
|
||||||
X - Add Contact information to Customer
|
|
||||||
X - Move Customer into Unit
|
|
||||||
X - 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
|
|
||||||
X - Reverse rent charges (early moveout on prepaid occupancy)
|
|
||||||
X - Handle NSF checks
|
|
||||||
X - Assess NSF Fees
|
|
||||||
X - Determine Lease Paid-Through status
|
|
||||||
X - Report: List of customers overdue
|
|
||||||
X - Flag unit as overlocked
|
|
||||||
X - Flag unit as evicting
|
|
||||||
X - Flag unit as normal status
|
|
||||||
X - Flag unit as dirty
|
|
||||||
- Enter notes when communicating with Customer
|
|
||||||
X - Accept pre-payments
|
|
||||||
X - Record Customer Move-Out from Unit
|
|
||||||
X - Record utilization of Security Deposit
|
|
||||||
X - Record issuing of a refund
|
|
||||||
- Record Deposit into Petty Cash
|
|
||||||
- Record Payment from Petty Cash to expenses
|
|
||||||
X - Record Petty Cash to refund.
|
|
||||||
X - Write Off Bad Debt
|
|
||||||
X - Perform a Deposit
|
|
||||||
X - Close the Books (nightly / weekly, etc)
|
|
||||||
X - Determine Rents Collected for a given period.
|
|
||||||
@@ -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
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,518 +0,0 @@
|
|||||||
<?php
|
|
||||||
/* SVN FILE: $Id: app_model.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Application model for Cake.
|
|
||||||
*
|
|
||||||
* This file is application-wide model file. You can put all
|
|
||||||
* application-wide model-related methods here.
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Application model for Cake.
|
|
||||||
*
|
|
||||||
* Add your application-wide methods in the class below, your models
|
|
||||||
* will inherit them.
|
|
||||||
*
|
|
||||||
* @package cake
|
|
||||||
* @subpackage cake.app
|
|
||||||
*/
|
|
||||||
class AppModel extends Model {
|
|
||||||
|
|
||||||
var $actsAs = array('Containable', 'Linkable');
|
|
||||||
var $useNullForEmpty = true;
|
|
||||||
var $formatDateFields = true;
|
|
||||||
|
|
||||||
// Loaded related models with no association
|
|
||||||
var $knows = array();
|
|
||||||
var $app_knows = array('Option');
|
|
||||||
|
|
||||||
// Default Log Level, if not specified at the function level
|
|
||||||
var $default_log_level = 5;
|
|
||||||
|
|
||||||
// Class specific log levels
|
|
||||||
var $class_log_level = array('Model' => 5);
|
|
||||||
|
|
||||||
// Function specific log levels
|
|
||||||
var $function_log_level = array();
|
|
||||||
|
|
||||||
// Force the module to log at LEAST at this level
|
|
||||||
var $min_log_level;
|
|
||||||
|
|
||||||
// Force logging of nothing higher than this level
|
|
||||||
var $max_log_level;
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: __construct
|
|
||||||
*/
|
|
||||||
|
|
||||||
function __construct($id = false, $table = null, $ds = null) {
|
|
||||||
parent::__construct($id, $table, $ds);
|
|
||||||
|
|
||||||
$this->knows = array_merge($this->app_knows, $this->knows);
|
|
||||||
//$this->pr(1, array('knows' => $this->knows));
|
|
||||||
foreach ($this->knows as $alias => $modelName) {
|
|
||||||
if (is_numeric($alias)) {
|
|
||||||
$alias = $modelName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't overwrite any existing alias
|
|
||||||
if (!empty($this->{$alias}) || get_class($this) == $alias)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
$model = array('class' => $modelName, 'alias' => $alias);
|
|
||||||
if (PHP5) {
|
|
||||||
$this->{$alias} = ClassRegistry::init($model);
|
|
||||||
} else {
|
|
||||||
$this->{$alias} =& ClassRegistry::init($model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: pr
|
|
||||||
* - Prints out debug information, if the log level allows
|
|
||||||
*/
|
|
||||||
|
|
||||||
function prClassLevel($level, $class = null) {
|
|
||||||
$trace = debug_backtrace(false);
|
|
||||||
$caller = array_shift($trace);
|
|
||||||
$caller = array_shift($trace);
|
|
||||||
if (empty($class))
|
|
||||||
$class = get_class($this);
|
|
||||||
$this->pr(50, compact('class', 'level'));
|
|
||||||
$this->class_log_level[$class] = $level;
|
|
||||||
}
|
|
||||||
|
|
||||||
function prFunctionLevel($level, $function = null, $class = null) {
|
|
||||||
$trace = debug_backtrace(false);
|
|
||||||
$caller = array_shift($trace);
|
|
||||||
$caller = array_shift($trace);
|
|
||||||
if (empty($class))
|
|
||||||
$class = get_class($this);
|
|
||||||
if (empty($function))
|
|
||||||
$function = $caller['function'];
|
|
||||||
$this->pr(50, compact('class', 'function', 'level'));
|
|
||||||
$this->function_log_level["{$class}-{$function}"] = $level;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _pr($level, $mixed, $checkpoint = null) {
|
|
||||||
if (Configure::read() <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
$log_level = $this->default_log_level;
|
|
||||||
|
|
||||||
$trace = debug_backtrace(false);
|
|
||||||
|
|
||||||
// Get rid of pr/prEnter/prReturn
|
|
||||||
$caller = array_shift($trace);
|
|
||||||
|
|
||||||
// The next entry shows where pr was called from, but it
|
|
||||||
// shows _what_ was called, which is pr/prEntry/prReturn.
|
|
||||||
$caller = array_shift($trace);
|
|
||||||
$file = $caller['file'];
|
|
||||||
$line = $caller['line'];
|
|
||||||
|
|
||||||
// So, this caller holds the calling function name
|
|
||||||
$caller = $trace[0];
|
|
||||||
$function = $caller['function'];
|
|
||||||
$class = $caller['class'];
|
|
||||||
//$class = $this->name;
|
|
||||||
|
|
||||||
// Use class or function specific log level if available
|
|
||||||
if (isset($this->class_log_level[$class]))
|
|
||||||
$log_level = $this->class_log_level[$class];
|
|
||||||
if (isset($this->function_log_level["{$class}-{$function}"]))
|
|
||||||
$log_level = $this->function_log_level["{$class}-{$function}"];
|
|
||||||
|
|
||||||
// Establish log level minimums
|
|
||||||
$min_log_level = $this->min_log_level;
|
|
||||||
if (is_array($this->min_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 ($level > $log_level)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!empty($checkpoint)) {
|
|
||||||
$chk = array("checkpoint" => $checkpoint);
|
|
||||||
if (is_array($mixed))
|
|
||||||
$mixed = $chk + $mixed;
|
|
||||||
else
|
|
||||||
$mixed = $chk + array($mixed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static $pr_unique_number = 0;
|
|
||||||
$pr_id = 'pr-section-class-' . $class . '-print-' . (++$pr_unique_number);
|
|
||||||
$pr_trace_id = $pr_id . '-trace';
|
|
||||||
$pr_output_id = $pr_id . '-output';
|
|
||||||
|
|
||||||
$pr_entire_base_class = "pr-section";
|
|
||||||
$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) {
|
|
||||||
$this->_pr($level, $mixed, $checkpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prEnter($args, $level = 15) {
|
|
||||||
$this->_pr($level, $args, 'Function Entry');
|
|
||||||
}
|
|
||||||
|
|
||||||
function prReturn($retval, $level = 16) {
|
|
||||||
$this->_pr($level, $retval, 'Function Return');
|
|
||||||
return $retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: queryInit
|
|
||||||
* - Initializes the query fields
|
|
||||||
*/
|
|
||||||
function prDump($all = false) {
|
|
||||||
$vars = get_object_vars($this);
|
|
||||||
foreach (array_keys($vars) AS $name) {
|
|
||||||
if (preg_match("/^[A-Z]/", $name))
|
|
||||||
unset($vars[$name]);
|
|
||||||
if (preg_match("/^_/", $name) && !$all)
|
|
||||||
unset($vars[$name]);
|
|
||||||
}
|
|
||||||
//$vars['class'] = get_class_vars(get_class($this));
|
|
||||||
|
|
||||||
$this->pr(1, $vars);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Enum Values
|
|
||||||
* Snippet v0.1.3
|
|
||||||
* http://cakeforge.org/snippet/detail.php?type=snippet&id=112
|
|
||||||
*
|
|
||||||
* Gets the enum values for MySQL 4 and 5 to use in selectTag()
|
|
||||||
*/
|
|
||||||
function getEnumValues($columnName=null, $tableName=null)
|
|
||||||
{
|
|
||||||
if ($columnName==null) { return array(); } //no field specified
|
|
||||||
|
|
||||||
if (!isset($tableName)) {
|
|
||||||
//Get the name of the table
|
|
||||||
$db =& ConnectionManager::getDataSource($this->useDbConfig);
|
|
||||||
$tableName = $db->fullTableName($this, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get the values for the specified column (database and version specific, needs testing)
|
|
||||||
$result = $this->query("SHOW COLUMNS FROM {$tableName} LIKE '{$columnName}'");
|
|
||||||
|
|
||||||
//figure out where in the result our Types are (this varies between mysql versions)
|
|
||||||
$types = null;
|
|
||||||
if ( isset( $result[0]['COLUMNS']['Type'] ) ) { //MySQL 5
|
|
||||||
$types = $result[0]['COLUMNS']['Type']; $default = $result[0]['COLUMNS']['Default'];
|
|
||||||
}
|
|
||||||
elseif ( isset( $result[0][0]['Type'] ) ) { //MySQL 4
|
|
||||||
$types = $result[0][0]['Type']; $default = $result[0][0]['Default'];
|
|
||||||
}
|
|
||||||
else { //types return not accounted for
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get the values
|
|
||||||
return array_flip(array_merge(array(''), // MySQL sets 0 to be the empty string
|
|
||||||
explode("','", strtoupper(preg_replace("/(enum)\('(.+?)'\)/","\\2", $types)))
|
|
||||||
));
|
|
||||||
} //end getEnumValues
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: queryInit
|
|
||||||
* - Initializes the query fields
|
|
||||||
*/
|
|
||||||
function queryInit(&$query, $link = true) {
|
|
||||||
if (!isset($query))
|
|
||||||
$query = array();
|
|
||||||
if (!isset($query['conditions']))
|
|
||||||
$query['conditions'] = array();
|
|
||||||
if (!isset($query['group']))
|
|
||||||
$query['group'] = null;
|
|
||||||
if (!isset($query['fields']))
|
|
||||||
$query['fields'] = null;
|
|
||||||
if ($link && !isset($query['link']))
|
|
||||||
$query['link'] = array();
|
|
||||||
if (!$link && !isset($query['contain']))
|
|
||||||
$query['contain'] = array();
|
|
||||||
|
|
||||||
// In case caller expects query to come back
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: nameToID
|
|
||||||
* - Returns the ID of the named item
|
|
||||||
*/
|
|
||||||
function nameToID($name) {
|
|
||||||
$this->cacheQueries = true;
|
|
||||||
$item = $this->find('first', array
|
|
||||||
('recursive' => -1,
|
|
||||||
'conditions' => compact('name'),
|
|
||||||
));
|
|
||||||
$this->cacheQueries = false;
|
|
||||||
if ($item) {
|
|
||||||
$item = current($item);
|
|
||||||
return $item['id'];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: statMerge
|
|
||||||
* - Merges summary data from $b into $a
|
|
||||||
*/
|
|
||||||
|
|
||||||
function statsMerge (&$a, $b) {
|
|
||||||
if (!isset($b))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!isset($a)) {
|
|
||||||
$a = $b;
|
|
||||||
}
|
|
||||||
elseif (!is_array($a) && !is_array($b)) {
|
|
||||||
$a += $b;
|
|
||||||
}
|
|
||||||
elseif (is_array($a) && is_array($b)) {
|
|
||||||
foreach (array_intersect_key($a, $b) AS $k => $v)
|
|
||||||
{
|
|
||||||
if (preg_match("/^sp\./", $k))
|
|
||||||
$a[$k] .= '; ' . $b[$k];
|
|
||||||
else
|
|
||||||
$this->statsMerge($a[$k], $b[$k]);
|
|
||||||
}
|
|
||||||
$a = array_merge($a, array_diff_key($b, $a));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
die ("Can't yet merge array and non-array stats");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function filter_null($array) {
|
|
||||||
return array_diff_key($array, array_filter($array, 'is_null'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function recursive_array_replace($find, $replace, &$data) {
|
|
||||||
if (!isset($data))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (is_array($data)) {
|
|
||||||
foreach ($data as $key => &$value) {
|
|
||||||
$this->recursive_array_replace($find, $replace, $value);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($replace))
|
|
||||||
$data = preg_replace($find, $replace, $data);
|
|
||||||
elseif (preg_match($find, $data))
|
|
||||||
$data = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function beforeSave() {
|
|
||||||
/* pr(array('class' => $this->name, */
|
|
||||||
/* 'alias' => $this->alias, */
|
|
||||||
/* 'function' => 'AppModel::beforeSave')); */
|
|
||||||
|
|
||||||
// Replace all empty strings with NULL.
|
|
||||||
// If a particular model doesn't like this, they'll have to
|
|
||||||
// override the behavior, or set useNullForEmpty to false.
|
|
||||||
if ($this->useNullForEmpty)
|
|
||||||
$this->recursive_array_replace("/^\s*$/", null, $this->data);
|
|
||||||
|
|
||||||
if ($this->formatDateFields) {
|
|
||||||
$alias = $this->alias;
|
|
||||||
|
|
||||||
foreach ($this->_schema AS $field => $info) {
|
|
||||||
if ($info['type'] == 'date' || $info['type'] == 'timestamp') {
|
|
||||||
if (isset($this->data[$alias][$field])) {
|
|
||||||
/* pr("Fix Date for '$alias'.'$field'; current value = " . */
|
|
||||||
/* "'{$this->data[$alias][$field]}'"); */
|
|
||||||
if ($this->data[$alias][$field] === 'CURRENT_TIMESTAMP')
|
|
||||||
// Seems CakePHP is broken for the default timestamp.
|
|
||||||
// It tries to automagically set the value to CURRENT_TIMESTAMP
|
|
||||||
// which is wholly rejected by MySQL. Just put it back to NULL
|
|
||||||
// and let the SQL engine deal with the defaults... it's not
|
|
||||||
// Cake's place to do this anyway :-/
|
|
||||||
$this->data[$alias][$field] = null;
|
|
||||||
else
|
|
||||||
$this->data[$alias][$field] =
|
|
||||||
$this->dateFormatBeforeSave($this->data[$alias][$field]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
**************************************************************************
|
|
||||||
* function: dateFormatBeforeSave
|
|
||||||
* - convert dates to database format
|
|
||||||
*/
|
|
||||||
|
|
||||||
function dateFormatBeforeSave($dateString) {
|
|
||||||
/* $time = ''; */
|
|
||||||
/* if (preg_match('/(\d+(:\d+))/', $dateString, $match)) */
|
|
||||||
/* $time = ' '.$match[1]; */
|
|
||||||
/* $dateString = preg_replace('/(\d+(:\d+))/', '', $dateString); */
|
|
||||||
/* return date('Y-m-d', strtotime($dateString)) . $time; */
|
|
||||||
|
|
||||||
if (preg_match('/:/', $dateString))
|
|
||||||
return date('Y-m-d H:i:s', strtotime($dateString));
|
|
||||||
else
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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!
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user