Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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,54 @@
|
||||
<?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', 'Number', 'Time');
|
||||
|
||||
function sideMenuLinks() {
|
||||
return array(
|
||||
array('name' => 'Common', 'header' => true),
|
||||
array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)),
|
||||
array('name' => 'Tenants', 'url' => array('controller' => 'contacts', 'action' => 'index')),
|
||||
array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')),
|
||||
);
|
||||
}
|
||||
|
||||
function beforeRender() {
|
||||
$this->set('sidemenu', $this->sideMenuLinks());
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -37,14 +37,5 @@ App::import('Core', 'Helper');
|
||||
* @subpackage cake.cake
|
||||
*/
|
||||
class AppHelper extends Helper {
|
||||
|
||||
function url($url = null, $full = false) {
|
||||
foreach(array('sand_route', 'dev_route') AS $mod) {
|
||||
if (isset($this->params[$mod]) && is_array($url) && !isset($url[$mod]))
|
||||
$url[$mod] = $this->params[$mod];
|
||||
}
|
||||
return parent::url($url, $full);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
<?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');
|
||||
var $actsAs = array('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
|
||||
|
||||
|
||||
// Overriding pagination, since the stupid count mechanism blows.
|
||||
// This is also a crappy solution, especially if the query returns
|
||||
// a really large number of rows. However, trying to untagle this
|
||||
// without changing a bunch of core code is near impossible.
|
||||
|
||||
var $paginate_rows_save;
|
||||
function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = null) {
|
||||
/* pr("paginate"); */
|
||||
/* pr(array_merge(compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive', 'extra'))); */
|
||||
if ($page > 1 && isset($limit))
|
||||
$offset = ($page - 1) * $limit;
|
||||
else
|
||||
$offset = 0;
|
||||
return array_slice($this->paginate_rows_save, $offset, $limit);
|
||||
}
|
||||
function paginateCount($conditions = null, $recursive = null, $extra = null) {
|
||||
/* pr("paginateCount"); */
|
||||
/* pr(array_merge(compact('conditions', 'recursive', 'extra'))); */
|
||||
|
||||
if (!isset($recursive))
|
||||
$recursive = $this->recursive;
|
||||
$parameters = array_merge(compact('conditions', 'recursive'), $extra);
|
||||
$results = $this->find('all', $parameters);
|
||||
|
||||
$this->paginate_rows_save = $results;
|
||||
return count($this->paginate_rows_save);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
Configure::write('Session.cookie', 'PMGR');
|
||||
Configure::write('Session.cookie', 'CAKEPHP');
|
||||
/**
|
||||
* Session time out time (in seconds).
|
||||
* Actual value depends on 'Security.level' setting.
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class DATABASE_CONFIG {
|
||||
|
||||
var $default = array(
|
||||
'driver' => 'mysql',
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'login' => 'pmgr',
|
||||
'password' => 'pmgruser',
|
||||
'database' => 'property_manager',
|
||||
'prefix' => 'pmgr_',
|
||||
);
|
||||
}
|
||||
?>
|
||||
@@ -38,7 +38,7 @@
|
||||
*
|
||||
* $uninflectedPlural = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox');
|
||||
*/
|
||||
$uninflectedPlural = array('.*cash');
|
||||
$uninflectedPlural = array();
|
||||
/**
|
||||
* This is a key => value array of plural irregular words.
|
||||
* If key matches then the value is returned.
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/* SVN FILE: $Id: routes.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||
/**
|
||||
* Short description for file.
|
||||
*
|
||||
* In this file, you set up routes to your controllers and their actions.
|
||||
* Routes are very important mechanism that allows you to freely connect
|
||||
* different urls to chosen controllers and their actions (functions).
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
||||
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @filesource
|
||||
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.app.config
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @version $Revision: 7945 $
|
||||
* @modifiedby $LastChangedBy: gwoo $
|
||||
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
||||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
||||
*/
|
||||
/**
|
||||
* Here, we are connecting '/' (base path) to controller called 'Pages',
|
||||
* its action called 'display', and we pass a param to select the view file
|
||||
* to use (in this case, /app/views/pages/home.ctp)...
|
||||
*/
|
||||
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
|
||||
/**
|
||||
* ...and connect the rest of 'Pages' controller's urls.
|
||||
*/
|
||||
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
|
||||
?>
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
class ChargesController extends AppController {
|
||||
var $paginate = array('limit' => 100,
|
||||
'group' => 'Charge.id',
|
||||
'order' => array('Charge.charge_date' => 'ASC'));
|
||||
|
||||
var $sidemenu_links =
|
||||
array(array('name' => 'Charges', 'header' => true),
|
||||
array('name' => 'Cleared', 'url' => array('controller' => 'charges', 'action' => 'cleared')),
|
||||
array('name' => 'Unresolved', 'url' => array('controller' => 'charges', 'action' => 'unresolved')),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: sideMenuLinks
|
||||
* - Generates controller specific links for the side menu
|
||||
*/
|
||||
function sideMenuLinks() {
|
||||
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index
|
||||
* - Lists all charges
|
||||
*/
|
||||
|
||||
function index() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: cleared
|
||||
* - Lists cleared charges
|
||||
*/
|
||||
|
||||
function cleared() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: unresolved
|
||||
* - Lists unresolved charges
|
||||
*/
|
||||
|
||||
function unresolved() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: all
|
||||
* - Lists all charges
|
||||
*/
|
||||
|
||||
function all() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'ChargeType',
|
||||
'Receipt',
|
||||
'Lease' => array('fields' => array('number'))
|
||||
),
|
||||
));
|
||||
|
||||
$title = 'All Charges';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('charges', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific charge
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$this->Charge->Behaviors->attach('Containable');
|
||||
$this->Charge->contain
|
||||
(array(// Models
|
||||
'ChargeType',
|
||||
'Receipt',
|
||||
'Lease' => array('fields' => array('number')),
|
||||
)
|
||||
);
|
||||
$charge = $this->Charge->read(null, $id);
|
||||
//pr($charge);
|
||||
|
||||
$payment_amount = 0;
|
||||
foreach($charge['Receipt'] AS $receipt)
|
||||
$payment_amount += $receipt['ChargesReceipt']['amount'];
|
||||
$balance_amount = $charge['Charge']['total'] - $payment_amount;
|
||||
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Operations', 'header' => true); */
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Move-Out', 'url' => array('controller' => 'charges', 'action' => 'move-out')); */
|
||||
|
||||
$title = 'Charge #' . $charge['Charge']['id'];
|
||||
$this->set(compact('charge', 'title',
|
||||
'payment_amount',
|
||||
'balance_amount'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
class ContactsController extends AppController {
|
||||
var $paginate = array('limit' => 100,
|
||||
'group' => 'Contact.id',
|
||||
'order' => array('Contact.last_name' => 'ASC',
|
||||
'Contact.first_name' => 'ASC'));
|
||||
|
||||
var $sidemenu_links =
|
||||
array(array('name' => 'Tenants', 'header' => true),
|
||||
array('name' => 'Current', 'url' => array('controller' => 'contacts', 'action' => 'current')),
|
||||
array('name' => 'Past', 'url' => array('controller' => 'contacts', 'action' => 'past')),
|
||||
array('name' => 'All Tenants', 'url' => array('controller' => 'contacts', 'action' => 'tenants')),
|
||||
array('name' => 'All Contacts', 'url' => array('controller' => 'contacts', 'action' => 'all')),
|
||||
);
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: sideMenuLinks
|
||||
* - Generates controller specific links for the side menu
|
||||
*/
|
||||
function sideMenuLinks() {
|
||||
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index
|
||||
* - Lists all current tenants
|
||||
*/
|
||||
|
||||
function index() {
|
||||
$this->current();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: past
|
||||
* - Lists all tenants, past and present
|
||||
*/
|
||||
|
||||
function tenants() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'Lease' =>
|
||||
array('fields' => array(),
|
||||
'type' => 'INNER',
|
||||
),
|
||||
),
|
||||
'conditions' => array('ContactsLease.type !=' => 'ALTERNATE')
|
||||
));
|
||||
|
||||
$title = 'All Tenants';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('contacts', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: current
|
||||
* - Lists all current tenants
|
||||
*/
|
||||
|
||||
function current() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'Lease' =>
|
||||
array('fields' => array(),
|
||||
'type' => 'INNER',
|
||||
),
|
||||
),
|
||||
'conditions' => array('ContactsLease.type !=' => 'ALTERNATE',
|
||||
'Lease.close_date IS NULL')
|
||||
));
|
||||
|
||||
$title = 'Current Tenants';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('contacts', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: past
|
||||
* - Lists all past tenants
|
||||
*/
|
||||
|
||||
function past() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'Lease' =>
|
||||
array('fields' => array(),
|
||||
'type' => 'INNER',
|
||||
),
|
||||
),
|
||||
'conditions' => array('ContactsLease.type !=' => 'ALTERNATE',
|
||||
'Lease.close_date IS NOT NULL')
|
||||
));
|
||||
|
||||
$title = 'Past Tenants';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('contacts', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: all
|
||||
* - Lists all contacts, including non-tenants
|
||||
*/
|
||||
|
||||
function all() {
|
||||
$title = 'All Contacts';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('contacts', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* 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'));
|
||||
}
|
||||
|
||||
$this->Contact->Behaviors->attach('Containable');
|
||||
$this->Contact->contain
|
||||
(array(// Models
|
||||
'ContactPhone',
|
||||
'ContactEmail',
|
||||
'ContactAddress',
|
||||
'Lease' =>
|
||||
array('order' => 'movein_date',
|
||||
'conditions' => array('Lease.lease_date IS NOT NULL',
|
||||
'ContactsLease.type !=' => 'ALTERNATE'),
|
||||
// Models
|
||||
'Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
'Charge' =>
|
||||
array('order' => array('charge_date'),
|
||||
// Models
|
||||
'ChargeType',
|
||||
'Receipt',
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$contact = $this->Contact->read(null, $id);
|
||||
|
||||
$outstanding_deposit = 0;
|
||||
$outstanding_balance = 0;
|
||||
foreach($contact['Lease'] AS $lease) {
|
||||
foreach($lease['Charge'] AS $charge) {
|
||||
$outstanding_balance += $charge['total'];
|
||||
foreach ($charge['Receipt'] AS $receipt) {
|
||||
$outstanding_balance -= $receipt['ChargesReceipt']['amount'];
|
||||
// REVISIT <AP> 20090530:
|
||||
// Using hardcoded value for security deposit...
|
||||
// That can't be good!
|
||||
if ($charge['charge_type_id'] == 1)
|
||||
$outstanding_deposit += $receipt['ChargesReceipt']['amount'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Move-Out', 'url' => array('controller' => 'units', 'action' => 'move-out'));
|
||||
|
||||
$title = $contact['Contact']['display_name'];
|
||||
$this->set(compact('contact', 'title',
|
||||
'outstanding_balance',
|
||||
'outstanding_deposit'));
|
||||
}
|
||||
}
|
||||
@@ -2,44 +2,22 @@
|
||||
|
||||
class MapsController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / all
|
||||
* - Generate a listing of maps
|
||||
* action: index
|
||||
* - Generates a list of all site maps
|
||||
*
|
||||
* REVISIT <AP> 20090528:
|
||||
* We'll need to present only those site area maps that correspond
|
||||
* to the users particular site.
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function all() { $this->gridView('All Maps', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
return array
|
||||
('link' => array('SiteArea' => array('fields' => array('SiteArea.id', 'SiteArea.name')),
|
||||
),
|
||||
);
|
||||
function index() {
|
||||
$this->Map->recursive = 0;
|
||||
$this->set('maps', $this->paginate());
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Map'] = array('id');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
@@ -52,9 +30,7 @@ class MapsController extends AppController {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
$this->sideMenuEnable('SITE', $this->op_area);
|
||||
$this->set('info', $this->mapInfo($id, $requested_width));
|
||||
$this->set('title', "Site Map");
|
||||
}
|
||||
|
||||
|
||||
@@ -86,35 +62,11 @@ class MapsController extends AppController {
|
||||
'units' => array());
|
||||
|
||||
// Find all of the map/unit information from this SiteArea
|
||||
$map = $this->Map->find('first', array('contain' => false,
|
||||
'conditions' => array('id' => $id)));
|
||||
|
||||
$units = $this->Map->Unit->find
|
||||
('all',
|
||||
array('link' =>
|
||||
array('Map' =>
|
||||
array('fields' => array()),
|
||||
|
||||
'CurrentLease' =>
|
||||
array('fields' => array('id', 'paid_through_date',
|
||||
$this->Map->Unit->CurrentLease->
|
||||
delinquentField('CurrentLease')),
|
||||
'Customer'),
|
||||
|
||||
'UnitSize' =>
|
||||
array('fields' => array('id', 'depth', 'width',
|
||||
'MapsUnit.pt_top',
|
||||
'MapsUnit.pt_left',
|
||||
'MapsUnit.transpose')),
|
||||
),
|
||||
'fields' => array('id', 'name', 'status'),
|
||||
'conditions' => array('Map.id' => $id),
|
||||
));
|
||||
|
||||
/* pr(compact('map', 'units')); */
|
||||
/* $this->render('/empty'); */
|
||||
/* return; */
|
||||
|
||||
$this->Map->recursive = 2;
|
||||
$this->Map->SiteArea->unbindModel(array('hasOne' => array('Map')));
|
||||
$map = $this->Map->read(null, $id);
|
||||
//pr($map);
|
||||
|
||||
/*****
|
||||
* The preference would be to leave all things "screen" related
|
||||
* to reside in the view. However, two separate views need this
|
||||
@@ -138,7 +90,7 @@ class MapsController extends AppController {
|
||||
$info['depth'] = $bottom * $screen_adjustment_factor;
|
||||
|
||||
// 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;
|
||||
$top = $unit['MapsUnit']['pt_top'] + $boundary_adjustment;
|
||||
|
||||
@@ -157,9 +109,10 @@ class MapsController extends AppController {
|
||||
$width *= $screen_adjustment_factor;
|
||||
$depth *= $screen_adjustment_factor;
|
||||
|
||||
//$info['units'][$unit['id']] =
|
||||
$info['units'][] =
|
||||
array( 'id' => $unit['Unit']['id'],
|
||||
'name' => $unit['Unit']['name'],
|
||||
array( 'id' => $unit['id'],
|
||||
'name' => $unit['name'],
|
||||
'left' => $lft,
|
||||
'right' => $lft + $width,
|
||||
'top' => $top,
|
||||
@@ -167,18 +120,30 @@ class MapsController extends AppController {
|
||||
'width' => $width,
|
||||
'depth' => $depth,
|
||||
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
|
||||
'status' => (($unit['Unit']['status'] === 'OCCUPIED' &&
|
||||
!empty($unit[0]['delinquent']))
|
||||
? 'LATE' : $unit['Unit']['status']),
|
||||
'data' => $unit,
|
||||
'status' => $unit['status']
|
||||
);
|
||||
}
|
||||
|
||||
/* pr($info); */
|
||||
/* $this->render('/empty'); exit(); */
|
||||
//pr($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 +153,9 @@ class MapsController extends AppController {
|
||||
*/
|
||||
|
||||
function legend($id = null, $requested_width = 400) {
|
||||
$status = array_keys($this->Map->Unit->activeStatusEnums());
|
||||
$occupied_key = array_search('OCCUPIED', $status);
|
||||
array_splice($status, $occupied_key+1, 0, array('LATE'));
|
||||
|
||||
$rows = 2;
|
||||
$cols = (int)((count($status) + $rows - 1) / $rows);
|
||||
$status = $this->unitStatusList();
|
||||
$cols = 6;
|
||||
$rows = (int)((count($status) + $cols - 1) / $cols);
|
||||
|
||||
$info = array('units' => array());
|
||||
|
||||
@@ -221,7 +183,7 @@ class MapsController extends AppController {
|
||||
$item_width *= $screen_adjustment_factor;
|
||||
$item_depth *= $screen_adjustment_factor;
|
||||
|
||||
foreach ($status AS $code) {
|
||||
foreach ($status AS $code => $color) {
|
||||
$info['units'][] = array('name' => $code,
|
||||
'status' => $code,
|
||||
'width' => $item_width,
|
||||
@@ -249,13 +211,9 @@ class MapsController extends AppController {
|
||||
*/
|
||||
|
||||
function image($info, $legend = false) {
|
||||
$debug = false;
|
||||
|
||||
if (!$debug) {
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
Configure::write('debug', '0');
|
||||
}
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
Configure::write('debug', '0');
|
||||
|
||||
// Define our color palate
|
||||
// REVISIT <AP>: 20090513
|
||||
@@ -271,9 +229,9 @@ class MapsController extends AppController {
|
||||
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
|
||||
$info['palate']['unit']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
|
||||
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
|
||||
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
|
||||
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
|
||||
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 0, 'blue' => 128);
|
||||
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
|
||||
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 128, 'blue' => 128);
|
||||
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
|
||||
|
||||
// Determine text color to go with each background
|
||||
foreach ($info['palate']['unit'] AS &$code) {
|
||||
@@ -296,7 +254,9 @@ class MapsController extends AppController {
|
||||
$code['fg'] = $component;
|
||||
}
|
||||
|
||||
$this->set(compact('info', 'debug'));
|
||||
//pr($info);
|
||||
|
||||
$this->set(compact('info'));
|
||||
$this->render('image');
|
||||
}
|
||||
|
||||
@@ -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,118 @@
|
||||
<?php
|
||||
|
||||
class PaymentsController extends AppController {
|
||||
var $paginate = array('limit' => 100,
|
||||
'group' => 'Payment.id',
|
||||
'order' => array('Payment.id' => 'ASC'));
|
||||
|
||||
var $sidemenu_links =
|
||||
array(array('name' => 'Payments', 'header' => true),
|
||||
array('name' => 'Cleared', 'url' => array('controller' => 'payments', 'action' => 'cleared')),
|
||||
array('name' => 'Unresolved', 'url' => array('controller' => 'payments', 'action' => 'unresolved')),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: sideMenuLinks
|
||||
* - Generates controller specific links for the side menu
|
||||
*/
|
||||
function sideMenuLinks() {
|
||||
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index
|
||||
* - Lists all payments
|
||||
*/
|
||||
|
||||
function index() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: cleared
|
||||
* - Lists cleared payments
|
||||
*/
|
||||
|
||||
function cleared() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: unresolved
|
||||
* - Lists unresolved payments
|
||||
*/
|
||||
|
||||
function unresolved() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: all
|
||||
* - Lists all payments
|
||||
*/
|
||||
|
||||
function all() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'PaymentType',
|
||||
'Receipt',
|
||||
),
|
||||
));
|
||||
|
||||
$title = 'All Payments';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('payments', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific payment
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$this->Payment->Behaviors->attach('Containable');
|
||||
$this->Payment->contain
|
||||
(array(// Models
|
||||
'PaymentType',
|
||||
'Receipt',
|
||||
)
|
||||
);
|
||||
$payment = $this->Payment->read(null, $id);
|
||||
//pr($payment);
|
||||
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Operations', 'header' => true); */
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Move-Out', 'url' => array('controller' => 'payments', 'action' => 'move-out')); */
|
||||
|
||||
$title = 'Payment #' . $payment['Payment']['id'];
|
||||
$this->set(compact('payment', 'title'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
class ReceiptsController extends AppController {
|
||||
var $paginate = array('limit' => 100,
|
||||
'group' => 'Receipt.id',
|
||||
'order' => array('Receipt.stamp' => 'ASC'));
|
||||
|
||||
var $sidemenu_links =
|
||||
array(array('name' => 'Receipts', 'header' => true),
|
||||
array('name' => 'Cleared', 'url' => array('controller' => 'receipts', 'action' => 'cleared')),
|
||||
array('name' => 'Unresolved', 'url' => array('controller' => 'receipts', 'action' => 'unresolved')),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: sideMenuLinks
|
||||
* - Generates controller specific links for the side menu
|
||||
*/
|
||||
function sideMenuLinks() {
|
||||
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index
|
||||
* - Lists all receipts
|
||||
*/
|
||||
|
||||
function index() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: cleared
|
||||
* - Lists cleared receipts
|
||||
*/
|
||||
|
||||
function cleared() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: unresolved
|
||||
* - Lists unresolved receipts
|
||||
*/
|
||||
|
||||
function unresolved() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: all
|
||||
* - Lists all receipts
|
||||
*/
|
||||
|
||||
function all() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'Charge',
|
||||
'Payment'
|
||||
),
|
||||
));
|
||||
|
||||
$title = 'All Receipts';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('receipts', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific receipt
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$this->Receipt->Behaviors->attach('Containable');
|
||||
$this->Receipt->contain
|
||||
(array(// Models
|
||||
'Charge' => array(// Models
|
||||
'Lease' => array('fields' => array('number')),
|
||||
'ChargesReceipt',
|
||||
'ChargeType'),
|
||||
'Payment' => array(// Models
|
||||
'PaymentType'),
|
||||
)
|
||||
);
|
||||
$receipt = $this->Receipt->read(null, $id);
|
||||
//pr($receipt);
|
||||
|
||||
$charge_amount = 0;
|
||||
$payment_amount = 0;
|
||||
foreach($receipt['Charge'] AS $charge)
|
||||
$charge_amount += $charge['ChargesReceipt']['amount'];
|
||||
foreach($receipt['Payment'] AS $payment)
|
||||
$payment_amount += $payment['amount'];
|
||||
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Operations', 'header' => true); */
|
||||
/* $this->sidemenu_links[] = */
|
||||
/* array('name' => 'Move-Out', 'url' => array('controller' => 'receipts', 'action' => 'move-out')); */
|
||||
|
||||
$title = 'Receipt #' . $receipt['Receipt']['id'];
|
||||
$this->set(compact('receipt', 'title',
|
||||
'charge_amount',
|
||||
'payment_amount'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
class UnitsController extends AppController {
|
||||
var $paginate = array('limit' => 100,
|
||||
'group' => 'Unit.id',
|
||||
'order' => array('Unit.sort_order' => 'ASC'));
|
||||
|
||||
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
|
||||
* - Lists all units
|
||||
*/
|
||||
|
||||
function index() {
|
||||
$this->all();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: unavailable
|
||||
* - Lists unavailable units
|
||||
*/
|
||||
|
||||
function unavailable() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'UnitSize' => array('fields' => array('name')),
|
||||
),
|
||||
'conditions' => $this->Unit->conditionUnavailable()
|
||||
));
|
||||
|
||||
$title = 'Unavailable Units';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('units', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: vacant
|
||||
* - Lists vacant units
|
||||
*/
|
||||
|
||||
function vacant() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'UnitSize' => array('fields' => array('name')),
|
||||
),
|
||||
'conditions' => $this->Unit->conditionVacant()
|
||||
));
|
||||
|
||||
$title = 'Vacant Units';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('units', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: occupied
|
||||
* - Lists occupied units
|
||||
*/
|
||||
|
||||
function occupied() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'UnitSize' => array('fields' => array('name')),
|
||||
'Lease' => array('fields' => array(),
|
||||
|
||||
// Models
|
||||
'Contact' => array('fields' => array('display_name'),
|
||||
//'type' => 'LEFT',
|
||||
),
|
||||
),
|
||||
),
|
||||
'conditions' => $this->Unit->conditionOccupied()
|
||||
));
|
||||
|
||||
$title = 'Occupied Units';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('units', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: all
|
||||
* - Lists all units
|
||||
*/
|
||||
|
||||
function all() {
|
||||
$this->paginate = array_merge
|
||||
($this->paginate,
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'UnitSize' => array('fields' => array('name')),
|
||||
),
|
||||
));
|
||||
|
||||
$title = 'All Units';
|
||||
$this->set('title', $title); $this->set('heading', $title);
|
||||
$this->set('units', $this->paginate());
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific unit
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>''));
|
||||
}
|
||||
|
||||
$this->Unit->Behaviors->attach('Containable');
|
||||
$this->Unit->contain
|
||||
(array(// Models
|
||||
'UnitSize',
|
||||
'Lease' =>
|
||||
array('order' => 'movein_date',
|
||||
'conditions' => array('Lease.lease_date IS NOT NULL',
|
||||
),
|
||||
// Models
|
||||
'Contact' =>
|
||||
array(//'order' => array('sort_order'),
|
||||
'fields' => array('id', 'display_name'),
|
||||
),
|
||||
'Charge' =>
|
||||
array('order' => array('charge_date'),
|
||||
// Models
|
||||
'ChargeType',
|
||||
'Receipt' => array(// Models
|
||||
'Payment'
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$unit = $this->Unit->read(null, $id);
|
||||
//pr($unit);
|
||||
|
||||
$outstanding_deposit = 0;
|
||||
$outstanding_balance = 0;
|
||||
foreach($unit['Lease'] AS $lease) {
|
||||
foreach($lease['Charge'] AS $charge) {
|
||||
$outstanding_balance += $charge['total'];
|
||||
foreach ($charge['Receipt'] AS $receipt) {
|
||||
$outstanding_balance -= $receipt['ChargesReceipt']['amount'];
|
||||
|
||||
/* foreach($receipt['Payment'] AS $payment) */
|
||||
/* $outstanding_balance -= $payment['amount']; */
|
||||
|
||||
// REVISIT <AP> 20090530:
|
||||
// Using hardcoded value for security deposit...
|
||||
// That can't be good!
|
||||
if ($charge['charge_type_id'] == 1)
|
||||
$outstanding_deposit += $receipt['ChargesReceipt']['amount'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Operations', 'header' => true);
|
||||
$this->sidemenu_links[] =
|
||||
array('name' => 'Move-Out', 'url' => array('controller' => 'units', 'action' => 'move-out'));
|
||||
|
||||
$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
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
class Account extends AppModel {
|
||||
|
||||
var $name = 'Account';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
'external_name' => array('notempty')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $hasMany = array(
|
||||
'ChargeType' => array(
|
||||
'className' => 'ChargeType',
|
||||
'foreignKey' => 'account_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,193 @@
|
||||
<?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;
|
||||
*/
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
protected $_defaults = array('type' => 'LEFT');
|
||||
|
||||
public function beforeFind(&$Model, $query) {
|
||||
/* pr("Linkable::beforeFind() begin"); pr($query); */
|
||||
if (isset($query[$this->_key])) {
|
||||
$optionsDefaults = $this->_defaults + array('reference' => $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);
|
||||
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['table']) && empty($options['class'])) {
|
||||
$options['class'] = $options['alias'];
|
||||
} elseif (!empty($options['table']) && empty($options['class'])) {
|
||||
$options['class'] = Inflector::classify($options['table']);
|
||||
}
|
||||
$_Model =& ClassRegistry::init($options['class']); // the incoming model to be linked in query
|
||||
$Reference =& ClassRegistry::init($options['reference']); // the already in query model that links to $_Model
|
||||
/* pr("_Model: $options[class] : $_Model->name ($_Model->alias)"); */
|
||||
/* pr("Reference: $options[reference] : $Reference->name ($Reference->alias)"); */
|
||||
$db =& $_Model->getDataSource();
|
||||
$associations = $_Model->getAssociated();
|
||||
if (isset($associations[$Reference->alias])) {
|
||||
$type = $associations[$Reference->alias];
|
||||
$association = $_Model->{$type}[$Reference->alias];
|
||||
} else {
|
||||
$_Model->bind($Reference->alias);
|
||||
$type = 'belongsTo';
|
||||
$association = $_Model->{$type}[$Reference->alias];
|
||||
$_Model->unbindModel(array('belongsTo' => array($Reference->alias)));
|
||||
}
|
||||
|
||||
if (empty($options['conditions'])) {
|
||||
if ($type === 'belongsTo') {
|
||||
$modelKey = $_Model->escapeField($association['foreignKey']);
|
||||
$referenceKey = $Reference->escapeField($Reference->primaryKey);
|
||||
$options['conditions'] = "{$referenceKey} = {$modelKey}";
|
||||
} elseif ($type === 'hasAndBelongsToMany') {
|
||||
if (isset($association['with']))
|
||||
$Link =& $_Model->{$association['with']};
|
||||
else
|
||||
$Link =& $_Model->{Inflector::classify($association['joinTable'])};
|
||||
|
||||
$linkAlias = $Link->alias;
|
||||
//$linkAlias = $Link->alias . $options['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();
|
||||
$modelKey = $_Model->escapeField();
|
||||
|
||||
// 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' => $options['alias'],
|
||||
'conditions' => "{$modelKey} = {$modelLink}",
|
||||
'table' => $db->fullTableName($_Model, true));
|
||||
|
||||
// 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'] = $association['conditions'];
|
||||
elseif (!empty($association['conditions']))
|
||||
$options['conditions'] = array($association['conditions']);
|
||||
|
||||
// Now for the top level join. This will be added into the list
|
||||
// of joins down below, outside of the HABTM specific code.
|
||||
$options['alias'] = $linkAlias;
|
||||
$options['table'] = $Link->getDataSource()->fullTableName($Link);
|
||||
$options['conditions'][] = "{$referenceLink} = {$referenceKey}";
|
||||
} else {
|
||||
$referenceKey = $Reference->escapeField($association['foreignKey']);
|
||||
$modelKey = $_Model->escapeField($_Model->primaryKey);
|
||||
$options['conditions'] = "{$modelKey} = {$referenceKey}";
|
||||
}
|
||||
}
|
||||
if (empty($options['table'])) {
|
||||
$options['table'] = $db->fullTableName($_Model, true);
|
||||
}
|
||||
|
||||
if (!isset($options['fields']) || !is_array($options['fields']))
|
||||
$options['fields'] = $db->fields($_Model);
|
||||
elseif (!empty($options['fields']))
|
||||
$options['fields'] = $db->fields($_Model, null, $options['fields']);
|
||||
|
||||
$query['fields'] = array_merge($query['fields'], $options['fields'],
|
||||
(empty($association['fields'])
|
||||
? array() : $db->fields($_Model, null, $association['fields'])));
|
||||
|
||||
|
||||
$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' => $options['class'])));
|
||||
}
|
||||
$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("Linkable::beforeFind() end"); pr($query); */
|
||||
return $query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
class Charge extends AppModel {
|
||||
|
||||
var $name = 'Charge';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'charge_type_id' => array('numeric'),
|
||||
'lease_id' => array('numeric'),
|
||||
'charge_date' => array('date'),
|
||||
'charge_to_date' => array('date'),
|
||||
'due_date' => array('date'),
|
||||
'amount' => array('money'),
|
||||
'tax' => array('money'),
|
||||
'total' => array('money')
|
||||
);
|
||||
|
||||
var $belongsTo = array(
|
||||
'ChargeType' => array(
|
||||
'className' => 'ChargeType',
|
||||
'foreignKey' => 'charge_type_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
),
|
||||
'Lease' => array(
|
||||
'className' => 'Lease',
|
||||
'foreignKey' => 'lease_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
)
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Receipt' => array(
|
||||
'className' => 'Receipt',
|
||||
'joinTable' => 'charges_receipts',
|
||||
'foreignKey' => 'charge_id',
|
||||
'associationForeignKey' => 'receipt_id',
|
||||
'unique' => true,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
class ChargeType extends AppModel {
|
||||
|
||||
var $name = 'ChargeType';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
'account_id' => array('numeric')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
/* var $belongsTo = array( */
|
||||
/* 'Account' => array( */
|
||||
/* 'className' => 'Account', */
|
||||
/* 'foreignKey' => 'account_id', */
|
||||
/* 'conditions' => '', */
|
||||
/* 'fields' => '', */
|
||||
/* 'order' => '' */
|
||||
/* ) */
|
||||
/* ); */
|
||||
|
||||
var $hasMany = array(
|
||||
'Charge' => array(
|
||||
'className' => 'Charge',
|
||||
'foreignKey' => 'charge_type_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,76 @@
|
||||
<?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(
|
||||
'Lease' => array(
|
||||
'className' => 'Lease',
|
||||
'joinTable' => 'contacts_leases',
|
||||
'foreignKey' => 'contact_id',
|
||||
'associationForeignKey' => 'lease_id',
|
||||
'unique' => true,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
),
|
||||
'ContactAddress' => array(
|
||||
'className' => 'ContactAddress',
|
||||
'joinTable' => 'contacts_methods',
|
||||
'foreignKey' => 'contact_id',
|
||||
'associationForeignKey' => 'method_id',
|
||||
'unique' => true,
|
||||
'conditions' => "method = 'POST'",
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
),
|
||||
'ContactPhone' => array(
|
||||
'className' => 'ContactPhone',
|
||||
'joinTable' => 'contacts_methods',
|
||||
'foreignKey' => 'contact_id',
|
||||
'associationForeignKey' => 'method_id',
|
||||
'unique' => true,
|
||||
'conditions' => "method = 'PHONE'",
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
),
|
||||
'ContactEmail' => array(
|
||||
'className' => 'ContactEmail',
|
||||
'joinTable' => 'contacts_methods',
|
||||
'foreignKey' => 'contact_id',
|
||||
'associationForeignKey' => 'method_id',
|
||||
'unique' => true,
|
||||
'conditions' => "method = 'EMAIL'",
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?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'",
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
)
|
||||
);
|
||||
}
|
||||
?>
|
||||
@@ -2,7 +2,6 @@
|
||||
class ContactEmail extends AppModel {
|
||||
|
||||
var $name = 'ContactEmail';
|
||||
var $displayField = 'email';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'email' => array('email')
|
||||
@@ -16,12 +15,15 @@ class ContactEmail extends AppModel {
|
||||
'associationForeignKey' => 'contact_id',
|
||||
'unique' => true,
|
||||
'conditions' => "method = 'EMAIL'",
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
function emailList() {
|
||||
return $this->find('list');
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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'",
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,85 @@
|
||||
<?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_planed_date' => array('date'),
|
||||
'movein_date' => array('date'),
|
||||
'moveout_date' => array('date'),
|
||||
'moveout_planed_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')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $belongsTo = array(
|
||||
'LeaseType' => array(
|
||||
'className' => 'LeaseType',
|
||||
'foreignKey' => 'lease_type_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
),
|
||||
'Unit' => array(
|
||||
'className' => 'Unit',
|
||||
'foreignKey' => 'unit_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
),
|
||||
'LateSchedule' => array(
|
||||
'className' => 'LateSchedule',
|
||||
'foreignKey' => 'late_schedule_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
)
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Charge' => array(
|
||||
'className' => 'Charge',
|
||||
'foreignKey' => 'lease_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Contact' => array(
|
||||
'className' => 'Contact',
|
||||
'joinTable' => 'contacts_leases',
|
||||
'foreignKey' => 'lease_id',
|
||||
'associationForeignKey' => 'contact_id',
|
||||
'unique' => true,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
class LeaseType extends AppModel {
|
||||
|
||||
var $name = 'LeaseType';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $hasMany = array(
|
||||
'Lease' => array(
|
||||
'className' => 'Lease',
|
||||
'foreignKey' => 'lease_type_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
class Map extends AppModel {
|
||||
|
||||
var $name = 'Map';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'site_id' => array('numeric'),
|
||||
'site_area_id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
'width' => array('numeric'),
|
||||
'depth' => array('numeric')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $belongsTo = array(
|
||||
'SiteArea' => array(
|
||||
'className' => 'SiteArea',
|
||||
'foreignKey' => 'site_area_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
)
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Unit' => array(
|
||||
'className' => 'Unit',
|
||||
'joinTable' => 'maps_units',
|
||||
'foreignKey' => 'map_id',
|
||||
'associationForeignKey' => 'unit_id',
|
||||
'unique' => true,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -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,31 @@
|
||||
<?php
|
||||
class Payment extends AppModel {
|
||||
|
||||
var $name = 'Payment';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'receipt_id' => array('numeric'),
|
||||
'payment_type_id' => array('numeric'),
|
||||
'amount' => array('money')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $belongsTo = array(
|
||||
'Receipt' => array(
|
||||
'className' => 'Receipt',
|
||||
'foreignKey' => 'receipt_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
),
|
||||
'PaymentType' => array(
|
||||
'className' => 'PaymentType',
|
||||
'foreignKey' => 'payment_type_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
class PaymentType extends AppModel {
|
||||
|
||||
var $name = 'PaymentType';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
'tillable' => array('boolean')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $hasMany = array(
|
||||
'Payment' => array(
|
||||
'className' => 'Payment',
|
||||
'foreignKey' => 'payment_type_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
class Receipt extends AppModel {
|
||||
|
||||
var $name = 'Receipt';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'stamp' => array('time')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $hasMany = array(
|
||||
'Payment' => array(
|
||||
'className' => 'Payment',
|
||||
'foreignKey' => 'receipt_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Charge' => array(
|
||||
'className' => 'Charge',
|
||||
'joinTable' => 'charges_receipts',
|
||||
'foreignKey' => 'receipt_id',
|
||||
'associationForeignKey' => 'charge_id',
|
||||
'unique' => true,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'finderQuery' => '',
|
||||
'deleteQuery' => '',
|
||||
'insertQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
class Site extends AppModel {
|
||||
|
||||
var $name = 'Site';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $hasMany = array(
|
||||
'SiteArea' => array(
|
||||
'className' => 'SiteArea',
|
||||
'foreignKey' => 'site_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
),
|
||||
'SiteOption' => array(
|
||||
'className' => 'SiteOption',
|
||||
'foreignKey' => 'site_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
class SiteArea extends AppModel {
|
||||
|
||||
var $name = 'SiteArea';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'site_id' => array('numeric'),
|
||||
'name' => array('notempty')
|
||||
);
|
||||
|
||||
//The Associations below have been created with all possible keys, those that are not needed can be removed
|
||||
var $belongsTo = array(
|
||||
'Site' => array(
|
||||
'className' => 'Site',
|
||||
'foreignKey' => 'site_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
)
|
||||
);
|
||||
|
||||
var $hasOne = array(
|
||||
'Map' => array(
|
||||
'className' => 'Map',
|
||||
'foreignKey' => 'site_area_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,79 @@
|
||||
<?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' => array(
|
||||
'className' => 'UnitSize',
|
||||
'foreignKey' => 'unit_size_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
),
|
||||
/* 'Map' => array( */
|
||||
/* 'className' => 'MapsUnit', */
|
||||
/* 'foreignKey' => 'unit_id', */
|
||||
/* 'conditions' => '', */
|
||||
/* 'fields' => '', */
|
||||
/* 'order' => '' */
|
||||
/* ) */
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Lease' => array(
|
||||
'className' => 'Lease',
|
||||
'foreignKey' => 'unit_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
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'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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' => array(
|
||||
'className' => 'UnitType',
|
||||
'foreignKey' => 'unit_type_id',
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => ''
|
||||
)
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Unit' => array(
|
||||
'className' => 'Unit',
|
||||
'foreignKey' => 'unit_size_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
class UnitType extends AppModel {
|
||||
|
||||
var $name = 'UnitType';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'code' => array('notempty'),
|
||||
'name' => array('notempty')
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'UnitSize' => array(
|
||||
'className' => 'UnitSize',
|
||||
'foreignKey' => 'unit_type_id',
|
||||
'dependent' => false,
|
||||
'conditions' => '',
|
||||
'fields' => '',
|
||||
'order' => '',
|
||||
'limit' => '',
|
||||
'offset' => '',
|
||||
'exclusive' => '',
|
||||
'finderQuery' => '',
|
||||
'counterQuery' => ''
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,20 +0,0 @@
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
|
||||
RewriteRule ^$ webroot/ [L]
|
||||
|
||||
# Need this prevent a 400 error without trailing /
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule (.*) webroot/$1 [L]
|
||||
|
||||
</IfModule>
|
||||
|
||||
# Need to make sure directories can't be listed, since the rewrite
|
||||
# rule excludes rewriting when an actual directory is requested
|
||||
Options -Indexes
|
||||
|
||||
# Provide a mechanism for user authentication
|
||||
AuthType Basic
|
||||
AuthName "Valley Storage"
|
||||
AuthUserFile "/home/perki2/valley_storage.pmgr.htpasswd"
|
||||
Require valid-user
|
||||
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,137 +0,0 @@
|
||||
<?php
|
||||
/* SVN FILE: $Id: bootstrap.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||
/**
|
||||
* Short description for file.
|
||||
*
|
||||
* Long description for file
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
||||
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @filesource
|
||||
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.app.config
|
||||
* @since CakePHP(tm) v 0.10.8.2117
|
||||
* @version $Revision: 7945 $
|
||||
* @modifiedby $LastChangedBy: gwoo $
|
||||
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
||||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
||||
*/
|
||||
/**
|
||||
*
|
||||
* This file is loaded automatically by the app/webroot/index.php file after the core bootstrap.php is loaded
|
||||
* This is an application wide file to load any function that is not used within a class define.
|
||||
* You can also use this to include or require any files in your application.
|
||||
*
|
||||
*/
|
||||
|
||||
function _box($type) {
|
||||
static $box = array('type' => null, 'test' => array());
|
||||
if (!isset($box['type']) && !isset($box['test'][$type])) {
|
||||
$r = Router::requestRoute();
|
||||
/* if (!preg_match("/gridData/", $_SERVER['REQUEST_URI'])) { */
|
||||
/* print("<PRE>Route:\n");print_r($r);print("\n</PRE>\n"); */
|
||||
/* } */
|
||||
$box['test'][$type] = !empty($r[3]["${type}_route"]);
|
||||
if ($box['test'][$type])
|
||||
$box['type'] = $type;
|
||||
}
|
||||
return $box['type'] == $type;
|
||||
}
|
||||
|
||||
function sandbox() { return _box('sand'); }
|
||||
function devbox() { return _box('dev'); }
|
||||
|
||||
function server_request_var($var) {
|
||||
if (preg_match("/^HTTP_ACCEPT|REMOTE_PORT/", $var))
|
||||
return false;
|
||||
return (preg_match("/^HTTP|REQUEST|REMOTE/", $var));
|
||||
}
|
||||
|
||||
function INTERNAL_ERROR($message, $exit = true, $drop = 0) {
|
||||
$O = new Object();
|
||||
for ($i=0; $i<3; ++$i) {
|
||||
$O->log(str_repeat("\\", 80));
|
||||
$O->log(str_repeat("/", 80));
|
||||
}
|
||||
$O->log("INTERNAL ERROR: $message");
|
||||
echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">' . "\n";
|
||||
echo '<H1 style="color:#000; margin-bottom:0.2em; font-size:2em;">INTERNAL ERROR:</H1>' . "\n";
|
||||
echo '<H2 style="color:#000; margin-top:0; margin-left:1.5em; font-size:1.5em">' . $message . '</H2>' . "\n";
|
||||
echo '<H4 style="color:#000;">This error was not caused by anything that you did wrong.' . "\n";
|
||||
echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>' . "\n";
|
||||
|
||||
// Print out the entire stack trace
|
||||
$O->log(str_repeat("-", 30));
|
||||
$O->log("Stack:");
|
||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nStack Trace:\n";
|
||||
echo '<OL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
|
||||
$trace = array_slice(debug_backtrace(false), $drop);
|
||||
for ($i = 0; $i < count($trace); ++$i) {
|
||||
$bline = $trace[$i]['line'];
|
||||
$bfile = $trace[$i]['file'];
|
||||
$bfile = str_replace(ROOT.DS, '', $bfile);
|
||||
$bfile = str_replace(CAKE_CORE_INCLUDE_PATH.DS, '', $bfile);
|
||||
|
||||
if ($i < count($trace)-1) {
|
||||
$bfunc = $trace[$i+1]['function'];
|
||||
$bclas = $trace[$i+1]['class'];
|
||||
} else {
|
||||
$bfunc = null;
|
||||
$bclas = null;
|
||||
}
|
||||
|
||||
$O->log(" $bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")");
|
||||
echo("<LI>$bfile:$bline (" . ($bclas ? "$bclas::$bfunc" : "entry point") . ")</LI>\n");
|
||||
}
|
||||
echo "</OL>\n";
|
||||
|
||||
$O->log(str_repeat("-", 30));
|
||||
$O->log("HTTP Request:");
|
||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nHTTP Request:\n";
|
||||
echo '<UL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
|
||||
foreach($_REQUEST AS $k => $v) {
|
||||
$O->log(sprintf(" %-20s => %s", $k, $v));
|
||||
echo("<LI>$k => $v</LI>\n");
|
||||
}
|
||||
echo "</UL>\n";
|
||||
|
||||
$O->log(str_repeat("-", 30));
|
||||
$O->log("Server:");
|
||||
$SRV = array_intersect_key($_SERVER, array_flip(array_filter(array_keys($_SERVER), 'server_request_var')));
|
||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nServer:\n";
|
||||
echo '<UL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
|
||||
foreach($SRV AS $k => $v) {
|
||||
if ($k == 'REQUEST_TIME')
|
||||
$v = date('c', $v);
|
||||
$O->log(sprintf(" %-20s => %s", $k, $v));
|
||||
echo("<LI>$k => $v</LI>\n");
|
||||
}
|
||||
echo "</UL>\n";
|
||||
|
||||
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\n";
|
||||
echo date('c') . "<BR>\n";
|
||||
|
||||
echo '</DIV>';
|
||||
if ($exit)
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings below can be used to set additional paths to models, views and controllers.
|
||||
* This is related to Ticket #470 (https://trac.cakephp.org/ticket/470)
|
||||
*
|
||||
* $modelPaths = array('full path to models', 'second full path to models', 'etc...');
|
||||
* $viewPaths = array('this path to views', 'second full path to views', 'etc...');
|
||||
* $controllerPaths = array('this path to controllers', 'second full path to controllers', 'etc...');
|
||||
*
|
||||
*/
|
||||
//EOF
|
||||
?>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
class DATABASE_CONFIG {
|
||||
|
||||
var $default = array(
|
||||
'driver' => 'mysql',
|
||||
'persistent' => false,
|
||||
'host' => 'localhost',
|
||||
'login' => 'perki2_pmgruser',
|
||||
'password' => 'pmgrauth',
|
||||
'database' => 'perki2_pmgr',
|
||||
'prefix' => '',
|
||||
);
|
||||
|
||||
function __construct() {
|
||||
if (devbox())
|
||||
$this->default['database'] = 'perki2_pmgr_dev';
|
||||
if (sandbox())
|
||||
$this->default['database'] = 'perki2_pmgr_sand';
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
/* SVN FILE: $Id: routes.php 7945 2008-12-19 02:16:01Z gwoo $ */
|
||||
/**
|
||||
* Short description for file.
|
||||
*
|
||||
* In this file, you set up routes to your controllers and their actions.
|
||||
* Routes are very important mechanism that allows you to freely connect
|
||||
* different urls to chosen controllers and their actions (functions).
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* CakePHP(tm) : Rapid Development Framework (http://www.cakephp.org)
|
||||
* Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||
*
|
||||
* Licensed under The MIT License
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @filesource
|
||||
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
|
||||
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
|
||||
* @package cake
|
||||
* @subpackage cake.app.config
|
||||
* @since CakePHP(tm) v 0.2.9
|
||||
* @version $Revision: 7945 $
|
||||
* @modifiedby $LastChangedBy: gwoo $
|
||||
* @lastmodified $Date: 2008-12-18 18:16:01 -0800 (Thu, 18 Dec 2008) $
|
||||
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
|
||||
*/
|
||||
|
||||
$default_path = array('controller' => 'maps', 'action' => 'view', '1');
|
||||
|
||||
/**
|
||||
* Here, we are connecting '/' (base path) to our site map.
|
||||
* It's hardcoded to map #1, but at some point we'll implement
|
||||
* a login mechanism and the default path will be to log on instead.
|
||||
*/
|
||||
Router::connect('/', $default_path);
|
||||
|
||||
/*
|
||||
* Route for sandbox functionality
|
||||
*/
|
||||
Router::connect('/sand',
|
||||
array('sand_route' => true) + $default_path);
|
||||
Router::connect('/sand/:controller/:action/*',
|
||||
array('sand_route' => true, 'action' => null));
|
||||
/* Unfortunately, for some reason we need an extra route to solve
|
||||
* a bug with form generation. When $this->data is set by the
|
||||
* controller, and a URL is generated by the FormHelper, this
|
||||
* route is required to ensure the form action is correct. An
|
||||
* example of a broken page is for /customers/edit/XX. It appears
|
||||
* the page location uses the route above, it's only URL generation
|
||||
* that seems to be broken.
|
||||
*/
|
||||
Router::connect('/sand/:controller/:action/:id/*',
|
||||
array('sand_route' => true,'action' => null, 'id'=>null));
|
||||
|
||||
/*
|
||||
* Route for developement functionality
|
||||
*/
|
||||
Router::connect('/dev',
|
||||
array('dev_route' => true) + $default_path);
|
||||
Router::connect('/dev/:controller/:action/*',
|
||||
array('dev_route' => true, 'action' => null));
|
||||
/* Unfortunately, for some reason we need an extra route to solve
|
||||
* a bug with form generation. When $this->data is set by the
|
||||
* controller, and a URL is generated by the FormHelper, this
|
||||
* route is required to ensure the form action is correct. An
|
||||
* example of a broken page is for /customers/edit/XX. It appears
|
||||
* the page location uses the route above, it's only URL generation
|
||||
* that seems to be broken.
|
||||
*/
|
||||
Router::connect('/dev/:controller/:action/:id/*',
|
||||
array('dev_route' => true,'action' => null, 'id'=>null));
|
||||
|
||||
?>
|
||||
@@ -1,210 +0,0 @@
|
||||
<?php
|
||||
|
||||
class AccountsController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('Asset',
|
||||
array('controller' => 'accounts', 'action' => 'asset'), null,
|
||||
'CONTROLLER', $this->admin_area);
|
||||
$this->addSideMenuLink('Liability',
|
||||
array('controller' => 'accounts', 'action' => 'liability'), null,
|
||||
'CONTROLLER', $this->admin_area);
|
||||
$this->addSideMenuLink('Equity',
|
||||
array('controller' => 'accounts', 'action' => 'equity'), null,
|
||||
'CONTROLLER', $this->admin_area);
|
||||
$this->addSideMenuLink('Income',
|
||||
array('controller' => 'accounts', 'action' => 'income'), null,
|
||||
'CONTROLLER', $this->admin_area);
|
||||
$this->addSideMenuLink('Expense',
|
||||
array('controller' => 'accounts', 'action' => 'expense'), null,
|
||||
'CONTROLLER', $this->admin_area);
|
||||
$this->addSideMenuLink('All',
|
||||
array('controller' => 'accounts', 'action' => 'all'), null,
|
||||
'CONTROLLER', $this->admin_area);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / asset / liability / equity / income / expense / all
|
||||
* - Generate a chart of accounts
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function asset() { $this->gridView('Asset Accounts'); }
|
||||
function liability() { $this->gridView('Liability Accounts'); }
|
||||
function equity() { $this->gridView('Equity Accounts'); }
|
||||
function income() { $this->gridView('Income Accounts'); }
|
||||
function expense() { $this->gridView('Expense Accounts'); }
|
||||
function all() { $this->gridView('All Accounts', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataSetup(&$params) {
|
||||
parent::gridDataSetup($params);
|
||||
if (!isset($params['action']))
|
||||
$params['action'] = 'all';
|
||||
}
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
// Our count should NOT include anything extra,
|
||||
// so we need the virtual function to prevent
|
||||
// the base class from just calling our
|
||||
// gridDataTables function
|
||||
return parent::gridDataTables($params, $model);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
return array
|
||||
('link' =>
|
||||
array(// Models
|
||||
'CurrentLedger' => array
|
||||
(// Models
|
||||
'LedgerEntry'
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
return array_merge($fields,
|
||||
$this->Account->Ledger->LedgerEntry->debitCreditFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
if (in_array($params['action'], array('asset', 'liability', 'equity', 'income', 'expense'))) {
|
||||
$conditions[] = array('Account.type' => strtoupper($params['action']));
|
||||
}
|
||||
|
||||
$conditions[] = array('Account.level >=' =>
|
||||
$this->Permission->level('controller.accounts'));
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Account'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: newledger
|
||||
* - Close the current account ledger and create a new one,
|
||||
* carrying forward any balance if necessary.
|
||||
*/
|
||||
|
||||
function newledger($id = null) {
|
||||
$result = $this->Account->closeCurrentLedgers($id);
|
||||
|
||||
if ($result['error']) {
|
||||
pr(compact('result'));
|
||||
die("Unable to create new ledger.");
|
||||
$this->Session->setFlash(__('Unable to create new Ledger.', true));
|
||||
}
|
||||
if ($id)
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
else
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: collected
|
||||
* - Displays the items actually collected for the period
|
||||
* e.g. How much was collected in rent from 4/1/09 - 5/1/09
|
||||
*/
|
||||
function collected($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$this->Account->recursive = -1;
|
||||
$account = $this->Account->read(null, $id);
|
||||
$account = $account['Account'];
|
||||
|
||||
$accounts = $this->Account->collectableAccounts();
|
||||
$payment_accounts = $accounts['all'];
|
||||
$default_accounts = $accounts['default'];
|
||||
$this->set(compact('payment_accounts', 'default_accounts'));
|
||||
|
||||
$title = ($account['name'] . ': Collected Report');
|
||||
$this->set(compact('account', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific account
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
$account = $this->Account->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
array(// Models
|
||||
'CurrentLedger' =>
|
||||
array('fields' => array('id', 'sequence', 'name')),
|
||||
|
||||
'Ledger' =>
|
||||
array('CloseTransaction' => array
|
||||
('order' => array('CloseTransaction.stamp' => 'DESC'))),
|
||||
),
|
||||
'conditions' => array(array('Account.id' => $id),
|
||||
array('Account.level >=' =>
|
||||
$this->Permission->level('controller.accounts')),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if (empty($account)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Obtain stats across ALL ledgers for the summary infobox
|
||||
$stats = $this->Account->stats($id, true);
|
||||
$stats = $stats['Ledger'];
|
||||
|
||||
$this->addSideMenuLink('New Ledger',
|
||||
array('action' => 'newledger', $id), null,
|
||||
'ACTION', $this->admin_area);
|
||||
$this->addSideMenuLink('Collected',
|
||||
array('action' => 'collected', $id), null,
|
||||
'ACTION', $this->admin_area);
|
||||
|
||||
// Prepare to render
|
||||
$title = 'Account: ' . $account['Account']['name'];
|
||||
$this->set(compact('account', 'title', 'stats'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
<?php
|
||||
|
||||
class ContactsController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / all
|
||||
* - Generate a listing of contacts
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function all() { $this->gridView('All Contacts', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataFilterTablesConfig(&$params, &$model, $table) {
|
||||
$config = parent::gridDataFilterTablesConfig($params, $model, $table);
|
||||
|
||||
// Special case for Customer; We need the Contact/Customer relationship
|
||||
if ($table == 'Customer')
|
||||
$config = array('fields' => array('ContactsCustomer.type',
|
||||
'ContactsCustomer.active'),
|
||||
'conditions' => array('ContactsCustomer.active' => true),
|
||||
);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
// After sorting by whatever the user wants, add these
|
||||
// defaults into the sort mechanism. If we're already
|
||||
// sorting by one of them, it will only be redundant,
|
||||
// and should cause no harm (possible a longer query?)
|
||||
$order[] = 'Contact.last_name ' . $direction;
|
||||
$order[] = 'Contact.first_name ' . $direction;
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Contact'] = array('display_name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* 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),
|
||||
));
|
||||
|
||||
// Set up dynamic menu items
|
||||
$this->addSideMenuLink('Edit',
|
||||
array('action' => 'edit', $id), null,
|
||||
'ACTION');
|
||||
|
||||
// Prepare to render.
|
||||
$title = 'Contact: ' . $contact['Contact']['display_name'];
|
||||
$this->set(compact('contact', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
*/
|
||||
|
||||
function edit($id = null, $customer_id = null) {
|
||||
if (isset($this->data)) {
|
||||
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (isset($this->data['Contact']['id']))
|
||||
$this->redirect(array('action'=>'view', $this->data['Contact']['id']));
|
||||
/* else */
|
||||
/* $this->redirect(array('controller' => 'customers', */
|
||||
/* 'action'=>'add', $this->data['Customer']['id'])); */
|
||||
return;
|
||||
}
|
||||
|
||||
// Go through each contact method and strip the bogus ID if new
|
||||
foreach (array_intersect_key($this->data,
|
||||
array('ContactPhone'=>1,
|
||||
'ContactAddress'=>1,
|
||||
'ContactEmail'=>1)) AS $type => $arr) {
|
||||
foreach ($arr AS $idx => $item) {
|
||||
if (isset($item['source']) && $item['source'] === 'new')
|
||||
unset($this->data[$type][$idx]['id']);
|
||||
}
|
||||
}
|
||||
|
||||
// Save the contact and all associated data
|
||||
$this->Contact->saveContact($this->data['Contact']['id'], $this->data);
|
||||
|
||||
// Now that the work is done, let the user view the updated contact
|
||||
$this->redirect(array('action'=>'view', $this->data['Contact']['id']));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->data = $this->Contact->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'ContactPhone',
|
||||
'ContactEmail',
|
||||
'ContactAddress',
|
||||
'Customer'),
|
||||
|
||||
'conditions' => array('Contact.id' => $id),
|
||||
));
|
||||
|
||||
$title = 'Contact: ' . $this->data['Contact']['display_name'] . " : Edit";
|
||||
}
|
||||
else {
|
||||
$title = "Enter New Contact";
|
||||
$this->data = array('ContactPhone' => array(),
|
||||
'ContactAddress' => array(),
|
||||
'ContactEmail' => array());
|
||||
}
|
||||
|
||||
$phone_types = array_flip($this->Contact->ContactPhone->getEnumValues('type'));
|
||||
unset($phone_types[0]);
|
||||
// REVISIT <AP> 20090705
|
||||
// Use this to have a mixed case enum
|
||||
// array_map('ucfirst', array_map('strtolower', $phone_types))
|
||||
$phone_types = array_combine($phone_types, $phone_types);
|
||||
$this->set(compact('phone_types'));
|
||||
|
||||
$method_types = array_flip($this->Contact->getEnumValues
|
||||
('type',
|
||||
$this->Contact->tablePrefix . 'contacts_methods'));
|
||||
unset($method_types[0]);
|
||||
$method_types = array_combine($method_types, $method_types);
|
||||
$this->set(compact('method_types'));
|
||||
|
||||
$method_preferences = array_flip($this->Contact->getEnumValues
|
||||
('preference',
|
||||
$this->Contact->tablePrefix . 'contacts_methods'));
|
||||
unset($method_preferences[0]);
|
||||
$method_preferences = array_combine($method_preferences, $method_preferences);
|
||||
$this->set(compact('method_preferences'));
|
||||
|
||||
$contact_phones = $this->Contact->ContactPhone->phoneList();
|
||||
$this->set(compact('contact_phones'));
|
||||
|
||||
$contact_addresses = $this->Contact->ContactAddress->addressList();
|
||||
$this->set(compact('contact_addresses'));
|
||||
|
||||
$contact_emails = $this->Contact->ContactEmail->emailList();
|
||||
$this->set(compact('contact_emails'));
|
||||
|
||||
// Prepare to render.
|
||||
//pr($this->data);
|
||||
$this->set(compact('title'));
|
||||
$this->render('edit');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: add
|
||||
* - Adds a new contact
|
||||
*/
|
||||
|
||||
function add($customer_id = null) {
|
||||
$this->edit(null, $customer_id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,584 +0,0 @@
|
||||
<?php
|
||||
|
||||
class CustomersController extends AppController {
|
||||
|
||||
var $components = array('RequestHandler');
|
||||
|
||||
// DEBUG FUNCTION ONLY!
|
||||
// Call without id to update ALL customers
|
||||
function force_update($id = null) {
|
||||
$this->Customer->update($id);
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('Current',
|
||||
array('controller' => 'customers', 'action' => 'current'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Past',
|
||||
array('controller' => 'customers', 'action' => 'past'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('All',
|
||||
array('controller' => 'customers', 'action' => 'all'), null,
|
||||
'CONTROLLER');
|
||||
|
||||
/* $this->addSideMenuLink('New Customer', */
|
||||
/* array('controller' => 'customers', 'action' => 'add'), null, */
|
||||
/* 'CONTROLLER', $this->new_area); */
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / current / past / all
|
||||
* - Creates a list of customers
|
||||
*/
|
||||
|
||||
function index() { $this->current(); }
|
||||
function current() { $this->gridView('Current Tenants', 'current'); }
|
||||
function past() { $this->gridView('Past Tenants'); }
|
||||
function all() { $this->gridView('All Customers'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
return array
|
||||
('link' =>
|
||||
array(// Models
|
||||
'PrimaryContact',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$link = $this->gridDataCountTables($params, $model);
|
||||
// StatementEntry is needed to determine customer balance
|
||||
$link['link']['StatementEntry'] = array('fields' => array());
|
||||
return $link;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
return array_merge($fields,
|
||||
$this->Customer->StatementEntry->chargeDisbursementFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
if ($params['action'] === 'current') {
|
||||
$conditions[] = array('Customer.current_lease_count >' => 0);
|
||||
}
|
||||
elseif ($params['action'] === 'past') {
|
||||
$conditions[] = array('Customer.current_lease_count' => 0);
|
||||
$conditions[] = array('Customer.past_lease_count >' => 0);
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataFilterTablesConfig(&$params, &$model, $table) {
|
||||
$config = parent::gridDataFilterTablesConfig($params, $model, $table);
|
||||
|
||||
// Special case for Contact; We need the Contact/Customer relationship
|
||||
if ($table == 'Contact')
|
||||
$config = array('fields' => array('ContactsCustomer.type',
|
||||
'ContactsCustomer.active'),
|
||||
'conditions' => array('ContactsCustomer.active' => true),
|
||||
);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
// After sorting by whatever the user wants, add these
|
||||
// defaults into the sort mechanism. If we're already
|
||||
// sorting by one of them, it will only be redundant,
|
||||
// and should cause no harm (possible a longer query?)
|
||||
$order[] = 'PrimaryContact.last_name ' . $direction;
|
||||
$order[] = 'PrimaryContact.first_name ' . $direction;
|
||||
$order[] = 'Customer.id ' . $direction;
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Customer'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: move_in
|
||||
* - Sets up the move-in page for the given customer.
|
||||
*/
|
||||
|
||||
function move_in($id = null, $unit_id = null) {
|
||||
$customer = array();
|
||||
$unit = array();
|
||||
|
||||
if (!empty($id)) {
|
||||
$this->Customer->recursive = -1;
|
||||
$customer = current($this->Customer->read(null, $id));
|
||||
}
|
||||
if (!empty($unit_id)) {
|
||||
$this->Customer->Lease->Unit->recursive = -1;
|
||||
$unit = current($this->Customer->Lease->Unit->read(null, $unit_id));
|
||||
}
|
||||
$this->set(compact('customer', 'unit'));
|
||||
|
||||
$title = 'Customer Move-In';
|
||||
$this->set(compact('title'));
|
||||
$this->render('/leases/move');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: move_out
|
||||
* - prepare to move a customer out of one of their units
|
||||
*/
|
||||
|
||||
function move_out($id) {
|
||||
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Lease' =>
|
||||
array('conditions' => array('Lease.moveout_date' => null),
|
||||
// Models
|
||||
'Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
'conditions' => array('Customer.id' => $id),
|
||||
));
|
||||
$this->set('customer', $lease['Customer']);
|
||||
$this->set('unit', array());
|
||||
|
||||
$redirect = array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$id);
|
||||
|
||||
$title = $customer['Customer']['name'] . ': Prepare Move-Out';
|
||||
$this->set(compact('title', 'customer', 'redirect'));
|
||||
$this->render('/leases/move');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific customer
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Get details on this customer, its contacts and leases
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Contact' =>
|
||||
array('order' => array('Contact.display_name'),
|
||||
// Models
|
||||
'ContactPhone',
|
||||
'ContactEmail',
|
||||
'ContactAddress',
|
||||
),
|
||||
'Lease' =>
|
||||
array('Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
'conditions' => array('Customer.id' => $id),
|
||||
));
|
||||
//pr($customer);
|
||||
|
||||
// Determine how long this customer has been with us.
|
||||
$leaseinfo = $this->Customer->find
|
||||
('first', array
|
||||
('link' => array('Lease' => array('fields' => array())),
|
||||
'fields' => array('MIN(Lease.movein_date) AS since',
|
||||
'IF(Customer.current_lease_count = 0, MAX(Lease.moveout_date), NULL) AS until'),
|
||||
'conditions' => array('Customer.id' => $id),
|
||||
'group' => 'Customer.id',
|
||||
));
|
||||
$this->set($leaseinfo[0]);
|
||||
|
||||
// Figure out the outstanding balances for this customer
|
||||
//$this->set('stats', $this->Customer->stats($id));
|
||||
$outstanding_balance = $this->Customer->balance($id);
|
||||
$outstanding_deposit = $this->Customer->securityDepositBalance($id);
|
||||
|
||||
// Figure out if this customer has any non-closed leases
|
||||
$show_moveout = false; $moveout_lease_id = null;
|
||||
$show_payment = false; $payment_lease_id = null;
|
||||
foreach ($customer['Lease'] AS $lease) {
|
||||
if (!isset($lease['close_date'])) {
|
||||
if ($show_payment)
|
||||
$payment_lease_id = null;
|
||||
else
|
||||
$payment_lease_id = $lease['id'];
|
||||
$show_payment = true;
|
||||
}
|
||||
if (!isset($lease['moveout_date'])) {
|
||||
if ($show_moveout)
|
||||
$moveout_lease_id = null;
|
||||
else
|
||||
$moveout_lease_id = $lease['id'];
|
||||
$show_moveout = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up dynamic menu items
|
||||
|
||||
if ($show_payment || $outstanding_balance > 0)
|
||||
$this->addSideMenuLink('New Receipt',
|
||||
array('action' => 'receipt', $id), null,
|
||||
'ACTION');
|
||||
|
||||
if ($show_payment) {
|
||||
/* $ids = $this->Customer->leaseIds($id, true); */
|
||||
/* if (count($ids) == 1) */
|
||||
/* $lease_id = $ids[0]; */
|
||||
/* else */
|
||||
/* $lease_id = null; */
|
||||
|
||||
$this->addSideMenuLink('New Invoice',
|
||||
array('controller' => 'leases',
|
||||
'action' => 'invoice',
|
||||
$payment_lease_id), null,
|
||||
'ACTION');
|
||||
}
|
||||
|
||||
$this->addSideMenuLink('Move-In',
|
||||
array('action' => 'move_in', $id), null,
|
||||
'ACTION');
|
||||
|
||||
if ($show_moveout) {
|
||||
$this->addSideMenuLink('Move-Out',
|
||||
array('controller' => 'leases',
|
||||
'action' => 'move_out',
|
||||
$moveout_lease_id), null,
|
||||
'ACTION');
|
||||
}
|
||||
|
||||
if (!$show_moveout && $outstanding_balance > 0)
|
||||
$this->addSideMenuLink('Write-Off',
|
||||
array('action' => 'bad_debt', $id), null,
|
||||
'ACTION');
|
||||
|
||||
if ($outstanding_balance < 0)
|
||||
$this->addSideMenuLink('Issue Refund',
|
||||
array('action' => 'refund', $id), null,
|
||||
'ACTION');
|
||||
|
||||
$this->addSideMenuLink('Edit',
|
||||
array('action' => 'edit', $id), null,
|
||||
'ACTION');
|
||||
|
||||
if ($this->admin())
|
||||
$this->addSideMenuLink('Merge',
|
||||
array('action' => 'merge', $id), null,
|
||||
'ACTION');
|
||||
|
||||
// Prepare to render.
|
||||
$title = 'Customer: ' . $customer['Customer']['name'];
|
||||
$this->set(compact('customer', 'title',
|
||||
'outstanding_balance',
|
||||
'outstanding_deposit'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
* - Edit customer information
|
||||
*/
|
||||
|
||||
function edit($id = null) {
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (isset($this->data['Customer']['id']))
|
||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Make sure we have at least one contact
|
||||
if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) {
|
||||
$this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true);
|
||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||
}
|
||||
|
||||
// Make sure there is a primary contact
|
||||
if (!isset($this->data['Customer']['primary_contact_entry'])) {
|
||||
$this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true);
|
||||
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
|
||||
}
|
||||
|
||||
// Go through each customer and strip the bogus ID if new
|
||||
foreach ($this->data['Contact'] AS &$contact) {
|
||||
if (isset($contact['source']) && $contact['source'] === 'new')
|
||||
unset($contact['id']);
|
||||
}
|
||||
|
||||
// Save the customer and all associated data
|
||||
if (!$this->Customer->saveCustomer($this->data['Customer']['id'],
|
||||
$this->data,
|
||||
$this->data['Customer']['primary_contact_entry'])) {
|
||||
$this->Session->setFlash("CUSTOMER SAVE FAILED", true);
|
||||
pr("CUSTOMER SAVE FAILED");
|
||||
}
|
||||
|
||||
// If existing customer, then view it.
|
||||
if ($this->data['Customer']['id'])
|
||||
$this->redirect(array('action'=>'view', $this->Customer->id));
|
||||
|
||||
// Since this is a new customer, go to the move in screen.
|
||||
// First set the move-in unit id, if there is one, ...
|
||||
if (empty($this->data['movein']['Unit']['id']))
|
||||
$unit_id = null;
|
||||
else
|
||||
$unit_id = $this->data['movein']['Unit']['id'];
|
||||
|
||||
// ... then redirect
|
||||
$this->redirect(array('action'=>'move_in',
|
||||
$this->Customer->id,
|
||||
$unit_id,
|
||||
));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
// REVISIT <AP>: 20090816
|
||||
// This should never need to be done by a controller.
|
||||
// However, until things stabilize, this gives the
|
||||
// user a way to update any cached items on the
|
||||
// customer, by just clicking Edit then Cancel.
|
||||
$this->Customer->update($id);
|
||||
|
||||
// Get details on this customer, its contacts and leases
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Contact' =>
|
||||
array('order' => array('Contact.display_name'),
|
||||
// Models
|
||||
'ContactPhone',
|
||||
'ContactEmail',
|
||||
'ContactAddress',
|
||||
),
|
||||
'Lease' =>
|
||||
array('Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
'conditions' => array('Customer.id' => $id),
|
||||
));
|
||||
|
||||
$this->data = $customer;
|
||||
$title = 'Customer: ' . $this->data['Customer']['name'] . " : Edit";
|
||||
}
|
||||
else {
|
||||
$title = "Enter New Customer";
|
||||
$this->data = array('Contact' => array(), 'PrimaryContact' => null);
|
||||
}
|
||||
|
||||
$contact_types = array_flip($this->Customer->ContactsCustomer->getEnumValues('type'));
|
||||
unset($contact_types[0]);
|
||||
$contact_types = array_combine($contact_types, $contact_types);
|
||||
$this->set(compact('contact_types'));
|
||||
|
||||
$contacts = $this->Customer->Contact->contactList();
|
||||
$this->set(compact('contacts'));
|
||||
|
||||
// Prepare to render.
|
||||
//pr($this->data);
|
||||
$this->set(compact('title'));
|
||||
$this->render('edit');
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: add
|
||||
* - Add a new customer
|
||||
*/
|
||||
|
||||
function add($unit_id = null) {
|
||||
$this->set('movein', array('Unit' => array('id' => $unit_id)));
|
||||
$this->edit();
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: merge
|
||||
* - Merges two customers
|
||||
*/
|
||||
|
||||
function merge($id = null) {
|
||||
if ($id) {
|
||||
$this->Customer->recursive = -1;
|
||||
$customer = $this->Customer->read(null, $id);
|
||||
$customer = $customer['Customer'];
|
||||
if (empty($customer))
|
||||
$this->INTERNAL_ERROR("Customer $id does not exist");
|
||||
$this->set('dst_customer', $customer);
|
||||
$this->set('dst_name', $customer['name']);
|
||||
$this->set('dst_id', $id);
|
||||
}
|
||||
else {
|
||||
$this->INTERNAL_ERROR("Merge called with invalid customer");
|
||||
}
|
||||
}
|
||||
|
||||
function mergeFinal() {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
$post = $this->params['form'];
|
||||
$this->Customer->merge($post['dst-id'], $post['src-id'],
|
||||
unserialize($post['contact-ids']));
|
||||
$this->redirect(array('action'=>'view', $post['dst-id']));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: receipt
|
||||
* - Sets up the receipt entry page for the given customer.
|
||||
*/
|
||||
|
||||
function receipt($id = null) {
|
||||
if (isset($id)) {
|
||||
$this->Customer->recursive = -1;
|
||||
$customer = $this->Customer->read(null, $id);
|
||||
$customer = $customer['Customer'];
|
||||
}
|
||||
else {
|
||||
$customer = null;
|
||||
}
|
||||
|
||||
$TT = new TenderType();
|
||||
$payment_types = $TT->paymentTypes();
|
||||
$default_type = $TT->defaultPaymentType();
|
||||
$this->set(compact('payment_types', 'default_type'));
|
||||
|
||||
$title = ($customer['name'] . ': Receipt Entry');
|
||||
$this->set(compact('customer', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: refund
|
||||
* - Refunds customer charges
|
||||
*/
|
||||
|
||||
function refund($id) {
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
'conditions' => array(array('Customer.id' => $id),
|
||||
),
|
||||
));
|
||||
if (empty($customer)) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// Determine the customer balance, bailing if the customer owes money
|
||||
$balance = $this->Customer->balance($id);
|
||||
if ($balance >= 0) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// The refund will be for a positive amount
|
||||
$balance *= -1;
|
||||
|
||||
// Get the accounts capable of paying the refund
|
||||
$refundAccounts = $this->Customer->StatementEntry->Account->refundAccounts();
|
||||
$defaultAccount = current($refundAccounts);
|
||||
$this->set(compact('refundAccounts', 'defaultAccount'));
|
||||
|
||||
// Prepare to render
|
||||
$title = ($customer['Customer']['name'] . ': Refund');
|
||||
$this->set(compact('title', 'customer', 'balance'));
|
||||
$this->render('/transactions/refund');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: bad_debt
|
||||
* - Sets up the write-off entry page, so that the
|
||||
* user can write off remaining charges of a customer.
|
||||
*/
|
||||
|
||||
function bad_debt($id) {
|
||||
$this->Customer->id = $id;
|
||||
$customer = $this->Customer->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
));
|
||||
|
||||
// Make sure we have a valid customer to write off
|
||||
if (empty($customer))
|
||||
$this->redirect(array('action' => 'index'));
|
||||
|
||||
// Get the customer balance
|
||||
$balance = $this->Customer->balance($id);
|
||||
|
||||
// Prepare to render
|
||||
$title = ($customer['Customer']['name'] . ': Write Off Bad Debt');
|
||||
$this->set(compact('title', 'customer', 'balance'));
|
||||
$this->render('/transactions/bad_debt');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
class DoubleEntriesController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific entry
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
// Get the Entry and related fields
|
||||
$entry = $this->DoubleEntry->find
|
||||
('first',
|
||||
array('contain' => array('DebitEntry', 'CreditEntry'),
|
||||
'conditions' => array('DoubleEntry.id' => $id),
|
||||
));
|
||||
|
||||
$entry += $this->DoubleEntry->DebitEntry->Transaction->find
|
||||
('first',
|
||||
array('contain' => false,
|
||||
'conditions' => array('id' => $entry['DebitEntry']['transaction_id']),
|
||||
));
|
||||
|
||||
$entry += $this->DoubleEntry->DebitEntry->find
|
||||
('first',
|
||||
array('contain' => array('Ledger' => array('Account')),
|
||||
'conditions' => array('DebitEntry.id' => $entry['DebitEntry']['id']),
|
||||
));
|
||||
$entry['Ledger']['link'] =
|
||||
$entry['Ledger']['Account']['level'] >=
|
||||
$this->Permission->level('controller.accounts');
|
||||
$entry['DebitLedger'] = $entry['Ledger'];
|
||||
unset($entry['Ledger']);
|
||||
|
||||
$entry += $this->DoubleEntry->CreditEntry->find
|
||||
('first',
|
||||
array('contain' => array('Ledger' => array('Account')),
|
||||
'conditions' => array('CreditEntry.id' => $entry['CreditEntry']['id']),
|
||||
));
|
||||
$entry['Ledger']['link'] =
|
||||
$entry['Ledger']['Account']['level'] >=
|
||||
$this->Permission->level('controller.accounts');
|
||||
$entry['CreditLedger'] = $entry['Ledger'];
|
||||
unset($entry['Ledger']);
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}";
|
||||
$this->set(compact('entry', 'title'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,601 +0,0 @@
|
||||
<?php
|
||||
|
||||
class LeasesController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('Active',
|
||||
array('controller' => 'leases', 'action' => 'active'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Closed',
|
||||
array('controller' => 'leases', 'action' => 'closed'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Delinquent',
|
||||
array('controller' => 'leases', 'action' => 'delinquent'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('All',
|
||||
array('controller' => 'leases', 'action' => 'all'), null,
|
||||
'CONTROLLER');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / active / closed / all
|
||||
* - Generate a listing of leases
|
||||
*/
|
||||
|
||||
function index() { $this->active(); }
|
||||
function active() { $this->gridView('Active Leases', 'active'); }
|
||||
function delinquent() { $this->gridView('Delinquent Leases'); }
|
||||
function closed() { $this->gridView('Closed Leases'); }
|
||||
function all() { $this->gridView('All Leases'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataSetup(&$params) {
|
||||
parent::gridDataSetup($params);
|
||||
if (!isset($params['action']))
|
||||
$params['action'] = 'all';
|
||||
}
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
return array
|
||||
('link' => array('Unit' => array('fields' => array('id', 'name')),
|
||||
'Customer' => array('fields' => array('id', 'name'))));
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$link = $this->gridDataCountTables($params, $model);
|
||||
$link['link']['StatementEntry'] = array('fields' => array());
|
||||
return $link;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
$fields[] = ("IF(" . $this->Lease->conditionDelinquent() . "," .
|
||||
" 'DELINQUENT', 'CURRENT') AS 'status'");
|
||||
return array_merge($fields,
|
||||
$this->Lease->StatementEntry->chargeDisbursementFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
if ($params['action'] === 'active') {
|
||||
$conditions[] = 'Lease.close_date IS NULL';
|
||||
}
|
||||
elseif ($params['action'] === 'delinquent') {
|
||||
$conditions[] = $this->Lease->conditionDelinquent();
|
||||
}
|
||||
elseif ($params['action'] === 'closed') {
|
||||
$conditions[] = 'Lease.close_date IS NOT NULL';
|
||||
}
|
||||
|
||||
if (isset($customer_id))
|
||||
$conditions[] = array('Lease.customer_id' => $customer_id);
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
// Do not sort by number, which is type varchar and
|
||||
// sorts on an ascii basis. Sort by ID instead.
|
||||
if ($index === 'Lease.number')
|
||||
$index = 'Lease.id';
|
||||
|
||||
// Instead of sorting by name, sort by defined order
|
||||
if ($index === 'Unit.name')
|
||||
$index = 'Unit.sort_order';
|
||||
|
||||
$order = array();
|
||||
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
// If sorting by anything other than id/number
|
||||
// add sorting by id as a secondary condition.
|
||||
if ($index !== 'Lease.id' && $index !== 'Lease.number')
|
||||
$order[] = parent::gridDataOrder($params, $model,
|
||||
'Lease.id', $direction);
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/* function gridDataPostProcess(&$params, &$model, &$records) { */
|
||||
/* foreach ($records AS &$record) { */
|
||||
/* $record['Lease']['through_date'] */
|
||||
/* = $this->Lease->rentChargeThrough($record['Lease']['id']); */
|
||||
/* } */
|
||||
|
||||
/* parent::gridDataPostProcess($params, $model, $records); */
|
||||
/* } */
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Lease'] = array('number');
|
||||
$links['Unit'] = array('name');
|
||||
$links['Customer'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: move_in
|
||||
* - execute a move in on a new lease
|
||||
*/
|
||||
|
||||
function move_in() {
|
||||
if (!$this->data)
|
||||
die("Should have some data");
|
||||
|
||||
// Handle the move in based on the data given
|
||||
//pr(array('Move-in data', $this->data));
|
||||
foreach (array('deposit', 'rent') AS $currency) {
|
||||
$this->data['Lease'][$currency]
|
||||
= str_replace('$', '', $this->data['Lease'][$currency]);
|
||||
}
|
||||
|
||||
$lid = $this->Lease->moveIn($this->data['Lease']['customer_id'],
|
||||
$this->data['Lease']['unit_id'],
|
||||
$this->data['Lease']['deposit'],
|
||||
$this->data['Lease']['rent'],
|
||||
$this->data['Lease']['movein_date'],
|
||||
$this->data['Lease']['comment']
|
||||
);
|
||||
|
||||
// Since this is a new lease, go to the invoice
|
||||
// screen so we can start assessing charges.
|
||||
$this->redirect(array('action'=>'invoice', $lid, 'move-in'));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: move_out
|
||||
* - prepare or execute a move out on a specific lease
|
||||
*/
|
||||
|
||||
function move_out($id = null) {
|
||||
if ($this->data) {
|
||||
// Handle the move out based on the data given
|
||||
$this->Lease->moveOut($this->data['Lease']['id'],
|
||||
'VACANT',
|
||||
$this->data['Lease']['moveout_date']
|
||||
);
|
||||
|
||||
$lease = $this->Lease->find
|
||||
('first', array
|
||||
('contain' => array('Customer.id'),
|
||||
'conditions' => array(array('Lease.id' => $this->data['Lease']['id'])),
|
||||
));
|
||||
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$lease['Customer']['id']));
|
||||
}
|
||||
|
||||
if (isset($id)) {
|
||||
$lease = $this->Lease->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
|
||||
'Customer' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
array('Lease.close_date' => null),
|
||||
),
|
||||
));
|
||||
$this->set('customer', $lease['Customer']);
|
||||
$this->set('unit', $lease['Unit']);
|
||||
$this->set('lease', $lease['Lease']);
|
||||
|
||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||
$lease['Unit']['name'] . ': ' .
|
||||
$lease['Customer']['name'] . ': Move-Out');
|
||||
}
|
||||
else {
|
||||
$title = 'Move-Out';
|
||||
}
|
||||
|
||||
$this->set(compact('title'));
|
||||
$this->render('/leases/move');
|
||||
}
|
||||
|
||||
|
||||
/* /\************************************************************************** */
|
||||
/* ************************************************************************** */
|
||||
/* ************************************************************************** */
|
||||
/* * action: promote_credit */
|
||||
/* * - Moves any lease credit up to the customer level, so that */
|
||||
/* * it may be used for charges other than those on this lease. */
|
||||
/* *\/ */
|
||||
|
||||
/* function promote_surplus($id) { */
|
||||
/* $this->Lease->promoteSurplus($id); */
|
||||
/* $this->redirect(array('controller' => 'leases', */
|
||||
/* 'action' => 'view', */
|
||||
/* $id)); */
|
||||
/* } */
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: refund
|
||||
* - Provides lease customer with a refund
|
||||
*/
|
||||
|
||||
function refund($id) {
|
||||
$lease = $this->Lease->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Unit' => array('fields' => array('id', 'name')),
|
||||
'Customer' => array('fields' => array('id', 'name')),
|
||||
),
|
||||
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
// Make sure lease is not closed...
|
||||
array('Lease.close_date' => null),
|
||||
),
|
||||
));
|
||||
if (empty($lease)) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// Determine the lease balance, bailing if the customer owes money
|
||||
$balance = $this->Lease->balance($id);
|
||||
if ($balance >= 0) {
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// The refund will be for a positive amount
|
||||
$balance *= -1;
|
||||
|
||||
// Get the accounts capable of paying the refund
|
||||
$refundAccounts = $this->Lease->StatementEntry->Account->refundAccounts();
|
||||
$defaultAccount = current($refundAccounts);
|
||||
$this->set(compact('refundAccounts', 'defaultAccount'));
|
||||
|
||||
// Prepare to render
|
||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||
$lease['Unit']['name'] . ': ' .
|
||||
$lease['Customer']['name'] . ': Refund');
|
||||
$this->set(compact('title', 'lease', 'balance'));
|
||||
$this->render('/transactions/refund');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: bad_debt
|
||||
* - Sets up the write-off entry page, so that the
|
||||
* user can write off remaining charges on a lease.
|
||||
*/
|
||||
|
||||
function bad_debt($id) {
|
||||
$this->Lease->id = $id;
|
||||
$lease = $this->Lease->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Unit' => array('fields' => array('id', 'name')),
|
||||
'Customer' => array('fields' => array('id', 'name')),
|
||||
),
|
||||
));
|
||||
|
||||
// Make sure we have a valid lease to write off
|
||||
if (empty($lease))
|
||||
$this->redirect(array('action' => 'view', $id));
|
||||
|
||||
// Get the lease balance
|
||||
$balance = $this->Lease->balance($id);
|
||||
|
||||
// Prepare to render
|
||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||
$lease['Unit']['name'] . ': ' .
|
||||
$lease['Customer']['name'] . ': Write Off Bad Debt');
|
||||
$this->set(compact('title', 'lease', 'balance'));
|
||||
$this->render('/transactions/bad_debt');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: close
|
||||
* - Closes a lease to any further action
|
||||
*/
|
||||
|
||||
function close($id) {
|
||||
// REVISIT <AP>: 20090708
|
||||
// We should probably seek confirmation first...
|
||||
if (!$this->Lease->closeable($id)) {
|
||||
$this->INTERNAL_ERROR("This lease is not ready to close");
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
$this->Lease->close($id);
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: open
|
||||
* - Re-opens a lease for further action
|
||||
*/
|
||||
|
||||
function open($id) {
|
||||
// REVISIT <AP>: 20131204
|
||||
// We should probably seek confirmation first, since this wipes out
|
||||
// the old close date, with no way to restore that date.
|
||||
$this->Lease->reopen($id);
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: invoice
|
||||
* - Sets up the invoice entry page for the given customer.
|
||||
*/
|
||||
|
||||
function invoice($id = null, $type = null) {
|
||||
|
||||
$lease = $this->Lease->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'Unit' =>
|
||||
array('order' => array('sort_order'),
|
||||
'fields' => array('id', 'name'),
|
||||
),
|
||||
|
||||
'Customer' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
array('Lease.close_date' => null),
|
||||
),
|
||||
));
|
||||
|
||||
$A = new Account();
|
||||
$charge_accounts = $A->invoiceAccounts();
|
||||
$default_account = $A->rentAccountID();
|
||||
$rent_account = $A->rentAccountID();
|
||||
$security_deposit_account = $A->securityDepositAccountID();
|
||||
$this->set(compact('charge_accounts', 'default_account',
|
||||
'rent_account', 'security_deposit_account'));
|
||||
|
||||
// REVISIT <AP> 20090705:
|
||||
// Of course, the late charge should come from the late_schedule
|
||||
$default_late = 10;
|
||||
$this->set(compact('default_late'));
|
||||
|
||||
if ($type === 'move-in') {
|
||||
// Make sure we have a valid lease that we're moving in
|
||||
if (empty($lease))
|
||||
$this->redirect(array('action' => 'index'));
|
||||
|
||||
$movein = array();
|
||||
$movein['time'] = strtotime($lease['Lease']['movein_date']);
|
||||
$movein['effective_time'] = strtotime($lease['Lease']['movein_date']);
|
||||
$movein_date = getdate($movein['effective_time']);
|
||||
$movein['through_time'] = mktime(0, 0, 0, $movein_date['mon'] + 1, 0, $movein_date['year']);
|
||||
$days_in_month = idate('d', $movein['through_time']);
|
||||
$movein['prorated_days'] = $days_in_month - $movein_date['mday'] + 1;
|
||||
$movein['prorated_rent'] = $lease['Lease']['rent'] * $movein['prorated_days'] / $days_in_month;
|
||||
$movein['prorated'] = $movein['prorated_days'] != $days_in_month;
|
||||
$movein['deposit'] = $lease['Lease']['deposit'];
|
||||
$this->set(compact('movein'));
|
||||
}
|
||||
|
||||
|
||||
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
|
||||
$lease['Unit']['name'] . ': ' .
|
||||
$lease['Customer']['name'] . ': Charge Entry');
|
||||
$this->set(compact('title', 'lease', 'charge'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: assess_rent/late
|
||||
* - Assesses the new monthly rent/late charge, if need be
|
||||
*/
|
||||
|
||||
function assess_rent($date = null) {
|
||||
$this->Lease->assessMonthlyRentAll($date);
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
function assess_late($date = null) {
|
||||
$this->Lease->assessMonthlyLateAll($date);
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
function assess_all($date = null) {
|
||||
$this->Lease->assessMonthlyRentAll($date);
|
||||
$this->Lease->assessMonthlyLateAll($date);
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: overview
|
||||
* - Displays lease up information
|
||||
*/
|
||||
function overview($months = 12) {
|
||||
|
||||
$overview = array('months' => array());
|
||||
|
||||
for ($month = 0; $month < $months; ++$month) {
|
||||
//for ($month = 12; $month >= 0; --$month) {
|
||||
$this_month = "(DATE(NOW() - INTERVAL $month MONTH - INTERVAL DAY(NOW())-1 DAY))";
|
||||
$next_month = "($this_month + INTERVAL 1 MONTH)";
|
||||
|
||||
$row = $this->Lease->find
|
||||
('first', array('link' => array(),
|
||||
'fields' => array("MONTHNAME($this_month) AS month",
|
||||
"YEAR($this_month) AS year"),
|
||||
));
|
||||
|
||||
$mname = $row[0]['month'] .', '. $row[0]['year'];
|
||||
$overview['months'][$mname] = array('name' => $mname);
|
||||
|
||||
foreach(array('start' => array('before' => $this_month, 'after' => $this_month),
|
||||
'finish' => array('before' => $next_month, 'after' => $next_month),
|
||||
'peak' => array('before' => $next_month, 'after' => $this_month))
|
||||
AS $type => $parm) {
|
||||
$count = $this->Lease->find
|
||||
('count',
|
||||
array('link' => array(),
|
||||
'conditions' => array("movein_date < {$parm['before']}",
|
||||
"(moveout_date IS NULL OR moveout_date >= {$parm['after']})",
|
||||
),
|
||||
));
|
||||
$overview['months'][$mname][$type] = $count;
|
||||
}
|
||||
|
||||
foreach(array('movein', 'moveout') AS $mvinout) {
|
||||
$count = $this->Lease->find
|
||||
('count',
|
||||
array('link' => array(),
|
||||
'conditions' => array("{$mvinout}_date < $next_month",
|
||||
"{$mvinout}_date >= $this_month")
|
||||
));
|
||||
$overview['months'][$mname][$mvinout] = $count;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable the Reports menu section
|
||||
$this->sideMenuAreaActivate('REPORT');
|
||||
|
||||
// Prepare to render.
|
||||
$this->set('title', 'Lease Up Report');
|
||||
$this->set(compact('overview'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific lease
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Get details about the lease and its ledgers (no ledger entries yet)
|
||||
$lease = $this->Lease->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
array(// Models
|
||||
'LeaseType(id,name)',
|
||||
'Unit(id,name)',
|
||||
'Customer(id,name)',
|
||||
),
|
||||
'fields' => array('Lease.*', $this->Lease->delinquentField()),
|
||||
'conditions' => array(array('Lease.id' => $id)),
|
||||
)
|
||||
);
|
||||
$lease['Lease'] += $lease[0];
|
||||
unset($lease[0]);
|
||||
|
||||
// Figure out the outstanding balances for this lease
|
||||
$outstanding_balance = $this->Lease->balance($id);
|
||||
$outstanding_deposit = $this->Lease->securityDepositBalance($id);
|
||||
|
||||
// Set up dynamic menu items. Normally, these will only be present
|
||||
// on an open lease, but it's possible for a lease to be closed, and
|
||||
// yet still have an outstanding balance. This can happen if someone
|
||||
// were to reverse charges, or if a payment should come back NSF.
|
||||
if (!isset($lease['Lease']['close_date']) || $outstanding_balance > 0) {
|
||||
if (!isset($lease['Lease']['moveout_date']))
|
||||
$this->addSideMenuLink('Move-Out',
|
||||
array('action' => 'move_out', $id), null,
|
||||
'ACTION');
|
||||
|
||||
if (!isset($lease['Lease']['close_date']))
|
||||
$this->addSideMenuLink('New Invoice',
|
||||
array('action' => 'invoice', $id), null,
|
||||
'ACTION');
|
||||
|
||||
$this->addSideMenuLink('New Receipt',
|
||||
array('controller' => 'customers',
|
||||
'action' => 'receipt',
|
||||
$lease['Customer']['id']), null,
|
||||
'ACTION');
|
||||
|
||||
// REVISIT <AP>:
|
||||
// Not allowing refund to be issued from the lease, as
|
||||
// in fact, we should never have a positive lease balance.
|
||||
// I'll flag this at the moment, since we might get one
|
||||
// when a charge is reimbursed; a bug that we'll either
|
||||
// need to fix, or we'll have to revisit this assumption.
|
||||
if ($outstanding_balance < 0)
|
||||
$this->INTERNAL_ERROR("Should not have a customer lease credit.");
|
||||
|
||||
/* if ($outstanding_balance < 0) */
|
||||
/* $this->addSideMenuLink('Issue Refund', */
|
||||
/* array('action' => 'refund', $id), null, */
|
||||
/* 'ACTION'); */
|
||||
|
||||
if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0)
|
||||
$this->addSideMenuLink('Write-Off',
|
||||
array('action' => 'bad_debt', $id), null,
|
||||
'ACTION');
|
||||
}
|
||||
|
||||
if ($this->Lease->closeable($id))
|
||||
$this->addSideMenuLink('Close',
|
||||
array('action' => 'close', $id), null,
|
||||
'ACTION');
|
||||
|
||||
if ($this->Lease->isClosed($id))
|
||||
$this->addSideMenuLink('Re-Open',
|
||||
array('action' => 'open', $id), null,
|
||||
'ACTION');
|
||||
|
||||
// Prepare to render
|
||||
$title = 'Lease: #' . $lease['Lease']['id'];
|
||||
$this->set(compact('lease', 'title',
|
||||
'outstanding_deposit',
|
||||
'outstanding_balance'));
|
||||
}
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
<?php
|
||||
|
||||
class LedgerEntriesController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / current / past / all
|
||||
* - Creates a list of ledger entries
|
||||
*/
|
||||
|
||||
function index() { $this->gridView('All Ledger Entries'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$link =
|
||||
array(// Models
|
||||
'Transaction' =>
|
||||
array('fields' => array('id', 'stamp'),
|
||||
),
|
||||
|
||||
'Ledger' =>
|
||||
array('fields' => array('id', 'sequence'),
|
||||
'Account' =>
|
||||
array('fields' => array('id', 'name', 'type'),
|
||||
),
|
||||
),
|
||||
|
||||
'Tender' =>
|
||||
array('fields' => array('id', 'name', 'nsf_transaction_id'),
|
||||
),
|
||||
|
||||
/* 'DebitEntry', */
|
||||
/* 'CreditEntry', */
|
||||
);
|
||||
|
||||
return array('link' => $link);
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
return array_merge($fields,
|
||||
$this->LedgerEntry->debitCreditFields());
|
||||
}
|
||||
|
||||
function gridDataFilterTablesTable(&$params, &$model, $table) {
|
||||
$table = $this->gridDataFilterTableName($params, $model, $table);
|
||||
// Account is already part of our standard table set.
|
||||
// Ensure we don't add it in again as part of filtering.
|
||||
if ($table == 'Account')
|
||||
return null;
|
||||
|
||||
// Customer needs to be added beneath Transaction
|
||||
if ($table == 'Customer')
|
||||
return 'Transaction';
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
function gridDataFilterTablesConfig(&$params, &$model, $table) {
|
||||
$config = parent::gridDataFilterTablesConfig($params, $model, $table);
|
||||
|
||||
// Customer is special in that its linked in by Transaction
|
||||
// Therefore, the actual table used for the join is 'Transaction',
|
||||
// not 'Customer', and so we need to specify Customer here.
|
||||
if ($table == 'Customer')
|
||||
$config = array('Customer' => $config);
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
function gridDataFilterConditionsStatement(&$params, &$model, $table, $key, $value) {
|
||||
//pr(compact('table', 'key', 'value'));
|
||||
if ($table == 'Account' && $value['value_present'] && $value['value'] === '-AR-')
|
||||
$value = $this->LedgerEntry->Ledger->Account->accountReceivableAccountID();
|
||||
return parent::gridDataFilterConditionsStatement($params, $model, $table, $key, $value);
|
||||
}
|
||||
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
/* if ($index === 'balance') */
|
||||
/* return ($index .' '. $direction); */
|
||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
if ($index === 'Transaction.stamp') {
|
||||
$order[] = 'LedgerEntry.id ' . $direction;
|
||||
}
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataPostProcessCalculatedFields(&$params, &$model, &$records) {
|
||||
parent::gridDataPostProcessCalculatedFields($params, $model, $records);
|
||||
foreach ($records AS &$record) {
|
||||
// REVISIT <AP>: 20090730
|
||||
// We really need the grid to handle this. We probably need to
|
||||
// either create a hidden column with the nsf id, or pass back
|
||||
// a list of nsf items as user data. We can then add an onload
|
||||
// function to sweep through the nsf items and format them.
|
||||
// For now... this works.
|
||||
if (!empty($record['Tender']['nsf_transaction_id']))
|
||||
$record['Tender']['name'] =
|
||||
'<SPAN class="nsf-tender">' . $record['Tender']['name'] . '</SPAN>';
|
||||
}
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['LedgerEntry'] = array('id');
|
||||
$links['Transaction'] = array('id');
|
||||
// REVISIT <AP>: 20090827
|
||||
// Need to take 'level' into account
|
||||
if ($this->Permission->allow('controller.accounts')) {
|
||||
$links['Ledger'] = array('id');
|
||||
$links['Account'] = array('name');
|
||||
}
|
||||
$links['Tender'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific entry
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
$entry = $this->LedgerEntry->find
|
||||
('first',
|
||||
array('contain' => array
|
||||
(
|
||||
'Transaction' =>
|
||||
array('fields' => array('id', 'stamp'),
|
||||
),
|
||||
|
||||
'Ledger' =>
|
||||
array('fields' => array('id', 'sequence', 'name'),
|
||||
'Account' =>
|
||||
array('fields' => array('id', 'name', 'type'),
|
||||
),
|
||||
),
|
||||
|
||||
'Tender' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
|
||||
'DebitDoubleEntry' => array('id'),
|
||||
'CreditDoubleEntry' => array('id'),
|
||||
|
||||
'DebitEntry' => array('fields' => array('id', 'crdr')),
|
||||
'CreditEntry' => array('fields' => array('id', 'crdr')),
|
||||
),
|
||||
|
||||
'conditions' => array('LedgerEntry.id' => $id),
|
||||
));
|
||||
|
||||
if (empty($entry) || empty($entry['Ledger']['Account'])) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
if (!empty($entry['DebitEntry']) && !empty($entry['CreditEntry']))
|
||||
die("LedgerEntry has both a matching DebitEntry and CreditEntry");
|
||||
if (empty($entry['DebitEntry']) && empty($entry['CreditEntry']))
|
||||
die("LedgerEntry has neither a matching DebitEntry nor a CreditEntry");
|
||||
if (empty($entry['DebitEntry']) && count($entry['CreditEntry']) != 1)
|
||||
die("LedgerEntry has more than one CreditEntry");
|
||||
if (empty($entry['CreditEntry']) && count($entry['DebitEntry']) != 1)
|
||||
die("LedgerEntry has more than one DebitEntry");
|
||||
|
||||
if (empty($entry['DebitEntry']))
|
||||
$entry['MatchingEntry'] = $entry['CreditEntry'][0];
|
||||
else
|
||||
$entry['MatchingEntry'] = $entry['DebitEntry'][0];
|
||||
|
||||
if (empty($entry['DebitDoubleEntry']['id']))
|
||||
$entry['DoubleEntry'] = $entry['CreditDoubleEntry'];
|
||||
else
|
||||
$entry['DoubleEntry'] = $entry['DebitDoubleEntry'];
|
||||
|
||||
// REVISIT <AP>: 20090816
|
||||
// This page doesn't seem very useful, let's just keep it
|
||||
// all to the double entry view.
|
||||
$this->redirect(array('controller' => 'double_entries',
|
||||
'action' => 'view',
|
||||
$entry['DoubleEntry']['id']));
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Ledger Entry #{$entry['LedgerEntry']['id']}";
|
||||
$this->set(compact('entry', 'title'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<?php
|
||||
|
||||
class LedgersController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('Current',
|
||||
array('controller' => 'ledgers', 'action' => 'current'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Closed',
|
||||
array('controller' => 'ledgers', 'action' => 'closed'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('All',
|
||||
array('controller' => 'ledgers', 'action' => 'all'), null,
|
||||
'CONTROLLER');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / current / closed / all
|
||||
* - Generate a list of ledgers
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function current() { $this->gridView('Current Ledgers'); }
|
||||
function closed() { $this->gridView('Closed Ledgers'); }
|
||||
function all() { $this->gridView('All Ledgers', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataSetup(&$params) {
|
||||
parent::gridDataSetup($params);
|
||||
if (!isset($params['action']))
|
||||
$params['action'] = 'all';
|
||||
}
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
return array
|
||||
('link' =>
|
||||
array(// Models
|
||||
'Account',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$tables = $this->gridDataCountTables($params, $model);
|
||||
$tables['link'][] = 'LedgerEntry';
|
||||
$tables['link'][] = 'CloseTransaction';
|
||||
return $tables;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
$fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence';
|
||||
return array_merge($fields,
|
||||
$this->Ledger->LedgerEntry->debitCreditFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
if ($params['action'] === 'current') {
|
||||
$conditions[] = array('Ledger.close_transaction_id' => null);
|
||||
}
|
||||
elseif ($params['action'] === 'closed') {
|
||||
$conditions[] = array('Ledger.close_transaction_id !=' => null);
|
||||
}
|
||||
|
||||
$conditions[] = array('Account.level >=' =>
|
||||
$this->Permission->level('controller.accounts'));
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
// After sorting by whatever the user wants, add these
|
||||
// defaults into the sort mechanism. If we're already
|
||||
// sorting by one of them, it will only be redundant,
|
||||
// and should cause no harm (possible a longer query?)
|
||||
$order[] = 'Account.name ' . $direction;
|
||||
$order[] = 'Ledger.sequence ' . $direction;
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
// REVISIT <AP>: 20090827
|
||||
// Need to take 'level' into account
|
||||
if ($this->Permission->allow('controller.accounts')) {
|
||||
$links['Ledger'] = array('sequence');
|
||||
$links['Account'] = array('name');
|
||||
}
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific ledger
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
$ledger = $this->Ledger->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
array(// Models
|
||||
'Account',
|
||||
),
|
||||
'conditions' => array(array('Ledger.id' => $id),
|
||||
array('Account.level >=' =>
|
||||
$this->Permission->level('controller.accounts')),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if (empty($ledger)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Get ledger stats for our summary box
|
||||
$stats = $this->Ledger->stats($id);
|
||||
|
||||
// OK, set our view variables and render!
|
||||
$title = 'Ledger: #' . $ledger['Account']['id'] .'-'. $ledger['Ledger']['sequence'];
|
||||
$this->set(compact('ledger', 'title', 'stats'));
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
<?php
|
||||
|
||||
class LocksController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('List',
|
||||
array('controller' => 'locks', 'action' => 'all'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Add',
|
||||
array('controller' => 'locks', 'action' => 'add'), null,
|
||||
'CONTROLLER');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / all
|
||||
* - Generate a listing of locks
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function all() { $this->gridView('Locks', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
/* function gridDataCountTables(&$params, &$model) { */
|
||||
/* return array('link' => array('Unit')); */
|
||||
/* } */
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$tables = parent::gridDataTables($params, $model);
|
||||
$tables['link']['LocksUnit'] = array();
|
||||
return $tables;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
$fields[] = 'COUNT(LocksUnit.id) AS inuse';
|
||||
$fields[] = 'IF(Lock.qty > COUNT(LocksUnit.id), Lock.qty - COUNT(LocksUnit.id), 0) AS avail';
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Lock'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific entry
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'locks', 'action'=>'index'));
|
||||
}
|
||||
|
||||
// Get the lock and related fields
|
||||
$this->Lock->id = $id;
|
||||
$lock = $this->Lock->find
|
||||
('first', array
|
||||
('contain' => array(),
|
||||
));
|
||||
//$lock['Lock'] = $lock[0] + $lock['lock'];
|
||||
//unset($lock[0]);
|
||||
|
||||
$this->addSideMenuLink('Edit',
|
||||
array('action' => 'edit', $id), null,
|
||||
'ACTION');
|
||||
|
||||
$this->addSideMenuLink('Delete',
|
||||
array('action' => 'delete', $id), null,
|
||||
'ACTION');
|
||||
|
||||
$this->set(compact('lock'));
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Lock : {$lock['Lock']['name']}";
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
* - Edit customer information
|
||||
*/
|
||||
|
||||
function edit($id = null) {
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (isset($this->data['Lock']['id']))
|
||||
$this->redirect(array('action'=>'view', $this->data['Lock']['id']));
|
||||
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Save the lock and all associated data
|
||||
if (!$this->Lock->saveLock($this->data)) {
|
||||
$this->Session->setFlash("LOCK SAVE FAILED", true);
|
||||
pr("LOCK SAVE FAILED");
|
||||
}
|
||||
|
||||
// View the lock by redirect
|
||||
$this->redirect(array('action'=>'view', $this->Lock->id));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
// Get details on this customer, its contacts and leases
|
||||
$lock = $this->Lock->find
|
||||
('first', array
|
||||
('conditions' => array('Lock.id' => $id),
|
||||
));
|
||||
|
||||
$this->data = $lock;
|
||||
$title = 'Lock: ' . $this->data['Lock']['name'] . " : Edit";
|
||||
}
|
||||
else {
|
||||
$title = "Enter New Lock Information";
|
||||
$this->data = array();
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
//pr($this->data);
|
||||
$this->set(compact('title'));
|
||||
$this->render('edit');
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: add
|
||||
* - Add a new lock
|
||||
*/
|
||||
|
||||
function add() {
|
||||
$this->edit();
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: delete
|
||||
* - Deletes an old lock
|
||||
*/
|
||||
function delete($id) {
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (isset($this->data['Lock']['id']))
|
||||
$this->redirect(array('action'=>'view', $this->data['Lock']['id']));
|
||||
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Delete the lock and all associated data
|
||||
if (!$this->Lock->destroy($this->data['Lock']['id'])) {
|
||||
$this->Session->setFlash(__('Failed to delete lock.', true));
|
||||
$this->redirect(array('action'=>'view', $this->data['Lock']['id']));
|
||||
}
|
||||
|
||||
// It's gone. Go back to the list of locks
|
||||
$this->redirect(array('controller' => 'locks', 'action'=>'index'));
|
||||
}
|
||||
|
||||
// User must specify an ID.
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'locks', 'action'=>'index'));
|
||||
}
|
||||
|
||||
// Get the lock and related fields
|
||||
$this->Lock->id = $id;
|
||||
$lock = $this->Lock->find
|
||||
('first', array
|
||||
('contain' => array('Unit'),
|
||||
));
|
||||
|
||||
// Make sure the lock isn't in use.
|
||||
if (isset($lock['Unit']) && count($lock['Unit']) > 0) {
|
||||
$this->Session->setFlash(__('Lock currently on units. Cannot be deleted!', true));
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
$this->data = $lock;
|
||||
$title = "Delete Lock : {$lock['Lock']['name']}";
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,409 +0,0 @@
|
||||
<?php
|
||||
|
||||
class StatementEntriesController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / current / past / all
|
||||
* - Creates a list of statement entries
|
||||
*/
|
||||
|
||||
function index() { $this->gridView('All Statement Entries'); }
|
||||
function unpaid() { $this->gridView('Unpaid Charges', 'unreconciled'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
$link =
|
||||
array(// Models
|
||||
'Transaction' =>
|
||||
array('fields' => array('id', 'stamp'),
|
||||
),
|
||||
|
||||
'Customer' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
|
||||
'Lease' =>
|
||||
array('fields' => array('id', 'number'),
|
||||
'Unit' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
|
||||
'Account' =>
|
||||
array('fields' => array('id', 'name', 'type'),
|
||||
),
|
||||
);
|
||||
|
||||
if (!empty($params['post']['custom']['statement_entry_id'])) {
|
||||
$link['ChargeEntry'] = array();
|
||||
// This query actually represents a union...
|
||||
// Unpaid Charge/Surplus: ChargeID - NULL; DisbursementID - NULL
|
||||
// Paid Charge/Refund: ChargeID - NULL; DisbursementID - !NULL
|
||||
// Disbursement/Reversal: ChargeID - !NULL; DisbursementID - NULL
|
||||
// <EMPTY SET>: ChargeID - !NULL; DisbursementID - !NULL
|
||||
//
|
||||
// The query is really slow unless we add the `id` condition to the join.
|
||||
// A cleaner query would be nice, but we must work within the Cake framework.
|
||||
$link['DisbursementEntry'] = array('conditions' =>
|
||||
'`DisbursementEntry`.`id` = '
|
||||
. $params['post']['custom']['statement_entry_id']);
|
||||
}
|
||||
|
||||
return array('link' => $link);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$tables = $this->gridDataCountTables($params, $model);
|
||||
|
||||
if (in_array('applied', $params['post']['fields'])) {
|
||||
$tables['link'] +=
|
||||
array('ChargeEntry' => array(),
|
||||
'DisbursementEntry' => array());
|
||||
}
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
|
||||
if (in_array('applied', $params['post']['fields'])) {
|
||||
$fields[] = ("IF(StatementEntry.type = 'CHARGE'," .
|
||||
" SUM(COALESCE(DisbursementEntry.amount,0))," .
|
||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||
" AS 'applied'");
|
||||
}
|
||||
if (in_array('unapplied', $params['post']['fields'])) {
|
||||
$fields[] = ("StatementEntry.amount - (" .
|
||||
"IF(StatementEntry.type = 'CHARGE'," .
|
||||
" SUM(COALESCE(DisbursementEntry.amount,0))," .
|
||||
" SUM(COALESCE(ChargeEntry.amount,0)))" .
|
||||
") AS 'unapplied'");
|
||||
}
|
||||
|
||||
$fields = array_merge($fields,
|
||||
$this->StatementEntry->chargeDisbursementFields());
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
extract($params['post']['custom']);
|
||||
|
||||
if (!empty($from_date))
|
||||
$conditions[]
|
||||
= array('Transaction.stamp >=' =>
|
||||
$this->StatementEntry->Transaction->dateFormatBeforeSave($from_date));
|
||||
|
||||
if (!empty($through_date))
|
||||
$conditions[]
|
||||
= array('Transaction.stamp <=' =>
|
||||
$this->StatementEntry->Transaction->dateFormatBeforeSave($through_date . ' 23:59:59'));
|
||||
|
||||
if (isset($account_id))
|
||||
$conditions[] = array('StatementEntry.account_id' => $account_id);
|
||||
|
||||
if (isset($customer_id))
|
||||
$conditions[] = array('StatementEntry.customer_id' => $customer_id);
|
||||
|
||||
if (isset($statement_entry_id))
|
||||
$conditions[] = array('OR' =>
|
||||
array(array('ChargeEntry.id' => $statement_entry_id),
|
||||
array('DisbursementEntry.id' => $statement_entry_id)));
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['StatementEntry'] = array('id');
|
||||
$links['Transaction'] = array('id');
|
||||
// REVISIT <AP>: 20090827
|
||||
// Need to take 'level' into account
|
||||
if ($this->Permission->allow('controller.accounts'))
|
||||
$links['Account'] = array('name');
|
||||
$links['Customer'] = array('name');
|
||||
$links['Lease'] = array('number');
|
||||
$links['Unit'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
// After sorting by whatever the user wants, add these
|
||||
// defaults into the sort mechanism. If we're already
|
||||
// sorting by one of them, it will only be redundant,
|
||||
// and should cause no harm (possible a longer query?)
|
||||
if ($index != 'Transaction.stamp' &&
|
||||
$index != 'StatementEntry.effective_date') {
|
||||
$order[] = 'Transaction.stamp ' . $direction;
|
||||
$order[] = 'StatementEntry.effective_date ' . $direction;
|
||||
}
|
||||
$order[] = 'StatementEntry.id ' . $direction;
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataCountExecute(&$params, &$model, $query) {
|
||||
if ($params['action'] === 'unreconciled') {
|
||||
// REVISIT <AP> 20100413:
|
||||
// This is a lame solution, as it runs the same queries twice
|
||||
// (and causes code duplication). However, I'm not in the mood
|
||||
// to flush out an actual "count" solution at the moment, and I
|
||||
// also don't want to cache the results in $params (although
|
||||
// that is probably the most sensible solution). So, I'll just
|
||||
// calculate the reconciled set both times and live with the
|
||||
// performance and maintenance penalty
|
||||
$lquery = array('conditions' => $query['conditions']);
|
||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true);
|
||||
return count($set['entries']);
|
||||
}
|
||||
|
||||
return parent::gridDataCountExecute($params, $model, $query);
|
||||
}
|
||||
|
||||
function gridDataRecordsExecute(&$params, &$model, $query) {
|
||||
|
||||
if ($params['action'] === 'unreconciled') {
|
||||
$lquery = array('conditions' => $query['conditions']);
|
||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $lquery, true);
|
||||
|
||||
$entries = array();
|
||||
foreach ($set['entries'] AS $entry)
|
||||
$entries[] = $entry['StatementEntry']['id'];
|
||||
|
||||
$query['conditions'] = array('StatementEntry.id' => $entries);
|
||||
$params['userdata']['balance'] = $set['summary']['balance'];
|
||||
}
|
||||
|
||||
if ($params['action'] === 'collected') {
|
||||
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
|
||||
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
|
||||
$total = $model->find('first', $tquery);
|
||||
$params['userdata']['total'] = $total[0]['total'];
|
||||
}
|
||||
|
||||
return parent::gridDataRecordsExecute($params, $model, $query);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: reverse the ledger entry
|
||||
*/
|
||||
|
||||
function reverse($id = null) {
|
||||
if ($this->data) {
|
||||
//pr($this->data); die();
|
||||
|
||||
$this->StatementEntry->reverse
|
||||
($this->data['StatementEntry']['id'],
|
||||
$this->data['Transaction']['stamp'],
|
||||
$this->data['Transaction']['comment']);
|
||||
|
||||
$this->redirect(array('action'=>'view',
|
||||
$this->data['StatementEntry']['id']));
|
||||
$this->INTERNAL_ERROR('SHOULD HAVE REDIRECTED');
|
||||
}
|
||||
|
||||
$this->StatementEntry->id = $id;
|
||||
$entry = $this->StatementEntry->find
|
||||
('first', array
|
||||
('contain' => array('Customer', 'Transaction', 'Account'),
|
||||
));
|
||||
|
||||
if (empty($entry)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action'=>'index'));
|
||||
}
|
||||
|
||||
if (!$this->StatementEntry->reversable($id)) {
|
||||
$this->Session->setFlash(__('Item not reversable.', true));
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
$title = ("Charge #{$entry['StatementEntry']['id']}" .
|
||||
" : {$entry['StatementEntry']['amount']}" .
|
||||
" : Reverse");
|
||||
$this->set(compact('entry', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: waive the ledger entry
|
||||
*/
|
||||
|
||||
function waive($id) {
|
||||
$this->StatementEntry->waive($id);
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: incexpbymonth
|
||||
* - Displays income and/or expenses by month
|
||||
*/
|
||||
|
||||
function incexpbymonth($accts, $security_deposits, $months) {
|
||||
$datefrom = 'DATE(NOW() - INTERVAL '.($months-1).' MONTH - INTERVAL DAY(NOW())-1 DAY)';
|
||||
$dateto = 'NOW()';
|
||||
/* $datefrom = '"2009-01-01"'; */
|
||||
/* $dateto = '"2012-12-31"'; */
|
||||
|
||||
$result = $this->StatementEntry->find
|
||||
('all',
|
||||
array('link' => array('Account' => array('fields' => 'name')),
|
||||
'fields' => array_merge(array('MONTHNAME(effective_date) AS month',
|
||||
'YEAR(effective_date) AS year'),
|
||||
$this->StatementEntry->chargeDisbursementFields(true)),
|
||||
'conditions' => array('Account.type' => $accts,
|
||||
"effective_date >= $datefrom",
|
||||
"effective_date <= $dateto",
|
||||
),
|
||||
'group' => array('YEAR(effective_date)', 'MONTH(effective_date)', 'Account.id'),
|
||||
'order' => array('YEAR(effective_date) DESC', 'MONTH(effective_date) DESC', 'Account.type',
|
||||
'IF(Account.id = '.$this->StatementEntry->Account->rentAccountID().', "---", Account.name)'),
|
||||
));
|
||||
|
||||
if ($security_deposits) {
|
||||
$sdresult = $this->StatementEntry->Transaction->LedgerEntry->find
|
||||
('all',
|
||||
array('link' => array('Transaction' => array('StatementEntry' => array('fields' => 'effective_date'),
|
||||
'fields' => array()),
|
||||
'Account' => array('fields' => 'name')),
|
||||
'fields' => array_merge(array('MONTHNAME(effective_date) AS month',
|
||||
'YEAR(effective_date) AS year'),
|
||||
$this->StatementEntry->Transaction->LedgerEntry->debitCreditFields(true)),
|
||||
'conditions' => array('LedgerEntry.account_id' => $this->StatementEntry->Account->securityDepositAccountID(),
|
||||
"effective_date >= $datefrom",
|
||||
"effective_date <= $dateto",
|
||||
'StatementEntry.id = (SELECT MIN(id) FROM statement_entries WHERE transaction_id = `Transaction`.id)'
|
||||
),
|
||||
'group' => array('YEAR(effective_date)', 'MONTH(effective_date)', 'Account.id'),
|
||||
'order' => array('YEAR(effective_date) DESC', 'MONTH(effective_date) DESC', 'Account.type', 'Account.name'),
|
||||
));
|
||||
} else {
|
||||
$sdresult = array();
|
||||
}
|
||||
|
||||
$overview = array('months' => array(), 'amount' => 0);
|
||||
foreach (array_merge($result, $sdresult) AS $row) {
|
||||
$mname = $row[0]['month'] .', '. $row[0]['year'];
|
||||
if (empty($overview['months'][$mname]))
|
||||
$overview['months'][$mname] = array('name' => $mname,
|
||||
'subs' => array(),
|
||||
'amount' => 0);
|
||||
$month = &$overview['months'][$mname];
|
||||
$month['subs'][] = array('name' => $row['Account']['name'],
|
||||
'amount' => $row[0]['balance']);
|
||||
|
||||
$month['amount'] += $row[0]['balance'];
|
||||
$overview['amount'] += $row[0]['balance'];
|
||||
}
|
||||
|
||||
// Enable the Reports menu section
|
||||
$this->sideMenuAreaActivate('REPORT');
|
||||
|
||||
// Prepare to render.
|
||||
$this->set('months', $months);
|
||||
$this->set(compact('overview'));
|
||||
$this->render('chargesbymonth');
|
||||
}
|
||||
|
||||
function incomebymonth($months = 12, $invoice = false) {
|
||||
$this->set('title', 'Monthly Gross Income');
|
||||
$this->set('reptype', 'Gross Income');
|
||||
$this->incexpbymonth(array('INCOME'), $invoice, $months);
|
||||
}
|
||||
|
||||
function expensebymonth($months = 12) {
|
||||
$this->set('title', 'Gross Monthly Expenses');
|
||||
$this->set('reptype', 'Gross Expenses');
|
||||
$this->incexpbymonth(array('EXPENSE'), false, $months);
|
||||
}
|
||||
|
||||
function netbymonth($months = 12) {
|
||||
$this->set('title', 'Net Monthly Income');
|
||||
$this->set('reptype', 'Net Income');
|
||||
$this->incexpbymonth(array('INCOME', 'EXPENSE'), true, $months);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific entry
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
$entry = $this->StatementEntry->find
|
||||
('first',
|
||||
array('contain' => array
|
||||
('Transaction' => array('fields' => array('id', 'type', 'stamp')),
|
||||
'Account' => array('id', 'name', 'type', 'level'),
|
||||
'Customer' => array('fields' => array('id', 'name')),
|
||||
'Lease' => array('fields' => array('id', 'number')),
|
||||
),
|
||||
|
||||
'conditions' => array(array('StatementEntry.id' => $id),
|
||||
),
|
||||
));
|
||||
|
||||
if (empty($entry)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
$entry['Account']['link'] =
|
||||
$entry['Account']['level'] >=
|
||||
$this->Permission->level('controller.accounts');
|
||||
|
||||
$stats = $this->StatementEntry->stats($id);
|
||||
|
||||
if (in_array(strtoupper($entry['StatementEntry']['type']), $this->StatementEntry->debitTypes()))
|
||||
$stats = $stats['Charge'];
|
||||
else
|
||||
$stats = $stats['Disbursement'];
|
||||
|
||||
|
||||
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
|
||||
|
||||
// Set up dynamic menu items
|
||||
if ($this->StatementEntry->reversable($id))
|
||||
$this->addSideMenuLink('Reverse',
|
||||
array('action' => 'reverse', $id), null,
|
||||
'ACTION');
|
||||
|
||||
if ($stats['balance'] > 0)
|
||||
$this->addSideMenuLink('Waive Balance',
|
||||
array('action' => 'waive', $id), null,
|
||||
'ACTION');
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Statement Entry #{$entry['StatementEntry']['id']}";
|
||||
$this->set(compact('entry', 'title', 'stats'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
<?php
|
||||
|
||||
class TendersController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / all
|
||||
* - Generate a listing of Tenders
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function all() { $this->gridView('All Legal Tender', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
return array
|
||||
('link' =>
|
||||
array('TenderType',
|
||||
'Customer',
|
||||
'LedgerEntry' =>
|
||||
array('Transaction',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function gridDataRecordsExecute(&$params, &$model, $query) {
|
||||
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
|
||||
$tquery['fields'] = array("SUM(COALESCE(LedgerEntry.amount,0)) AS 'total'");
|
||||
$total = $model->find('first', $tquery);
|
||||
$params['userdata']['total'] = $total[0]['total'];
|
||||
|
||||
return parent::gridDataRecordsExecute($params, $model, $query);
|
||||
}
|
||||
|
||||
function gridDataPostProcessCalculatedFields(&$params, &$model, &$records) {
|
||||
parent::gridDataPostProcessCalculatedFields($params, $model, $records);
|
||||
foreach ($records AS &$record) {
|
||||
// REVISIT <AP>: 20090730
|
||||
// We really need the grid to handle this. We probably need to
|
||||
// either create a hidden column with the nsf id, or pass back
|
||||
// a list of nsf items as user data. We can then add an onload
|
||||
// function to sweep through the nsf items and format them.
|
||||
// For now... this works.
|
||||
if (!empty($record['Tender']['nsf_transaction_id']))
|
||||
$record['Tender']['name'] =
|
||||
'<SPAN class="nsf-tender">' . $record['Tender']['name'] . '</SPAN>';
|
||||
}
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Tender'] = array('name', 'id');
|
||||
$links['Customer'] = array('name');
|
||||
//$links['TenderType'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: deposit
|
||||
* - Prepares the books for a bank deposit
|
||||
*/
|
||||
|
||||
function deposit() {
|
||||
// Prepare a close page...
|
||||
$deposit_types = $this->Tender->TenderType->depositTypes(
|
||||
// Testing... limit to only one type
|
||||
//array('limit' => 1)
|
||||
);
|
||||
$deposit_accounts = $this->Tender->TenderType->Account->depositAccounts();
|
||||
|
||||
foreach ($deposit_types AS $type_id => &$type)
|
||||
$type = array('id' => $type_id,
|
||||
'name' => $type,
|
||||
'stats' => $this->Tender->TenderType->stats($type_id));
|
||||
|
||||
//pr(compact('deposit_types', 'deposit_accounts'));
|
||||
|
||||
$title = 'Prepare Deposit';
|
||||
$this->set(compact('title', 'deposit_types', 'deposit_accounts'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: nsf
|
||||
* - Marks a tender as having insufficient funds.
|
||||
*/
|
||||
|
||||
function nsf($id = null) {
|
||||
if ($this->data) {
|
||||
$result = $this->Tender->nsf
|
||||
($this->data['Tender']['id'],
|
||||
$this->data['Transaction']['stamp'],
|
||||
$this->data['Transaction']['comment']);
|
||||
$this->redirect(array('controller' => 'tenders',
|
||||
'action' => 'view',
|
||||
$this->data['Tender']['id']));
|
||||
}
|
||||
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$this->Tender->id = $id;
|
||||
$tender = $this->Tender->find
|
||||
('first', array
|
||||
('contain' => array('Customer', 'LedgerEntry' => array('Transaction')),
|
||||
));
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']} : NSF";
|
||||
$this->set(compact('tender', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* 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 Tender and related fields
|
||||
$this->Tender->id = $id;
|
||||
$tender = $this->Tender->find
|
||||
('first', array
|
||||
('contain' => array('TenderType', 'Customer', 'LedgerEntry' => array('Transaction')),
|
||||
));
|
||||
|
||||
|
||||
if (!empty($tender['Tender']['deposit_transaction_id'])
|
||||
&& empty($tender['Tender']['nsf_transaction_id'])
|
||||
// Hard to tell what types of items can come back as NSF.
|
||||
// For now, assume iff it is a named item, it can be NSF.
|
||||
// (or if we're in development mode)
|
||||
&& (!empty($tender['TenderType']['data1_name']) || !empty($this->params['dev']))
|
||||
) {
|
||||
$this->addSideMenuLink('NSF',
|
||||
array('action' => 'nsf', $id), null,
|
||||
'ACTION');
|
||||
}
|
||||
|
||||
// Watch out for the special "Closing" entries, which have
|
||||
// tender_type_id set to NULL. Otherwise, allow editing.
|
||||
if (!empty($tender['TenderType']['id']))
|
||||
$this->addSideMenuLink('Edit',
|
||||
array('action' => 'edit', $id), null,
|
||||
'ACTION');
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']}";
|
||||
$this->set(compact('tender', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
* - Edit tender information
|
||||
*/
|
||||
|
||||
function edit($id = null) {
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (empty($this->data['Tender']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->data['Tender']['id']));
|
||||
}
|
||||
|
||||
// Make sure we have tender data
|
||||
if (empty($this->data['Tender']) || empty($this->data['Tender']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
// Figure out which tender type was chosen
|
||||
// REVISIT <AP>: 20090810; Not ready to change tender type
|
||||
// $tender_type_id = $this->data['Tender']['tender_type_id'];
|
||||
$tender_type_id = $this->Tender->field('tender_type_id');
|
||||
if (empty($tender_type_id))
|
||||
$this->redirect(array('action'=>'view', $this->data['Tender']['id']));
|
||||
|
||||
// Get data fields from the selected tender type
|
||||
$this->data['Tender'] += $this->data['type'][$tender_type_id];
|
||||
unset($this->data['type']);
|
||||
|
||||
// Save the tender and all associated data
|
||||
$this->Tender->create();
|
||||
$this->Tender->id = $this->data['Tender']['id'];
|
||||
if (!$this->Tender->save($this->data, false)) {
|
||||
$this->Session->setFlash("TENDER SAVE FAILED", true);
|
||||
pr("TENDER SAVE FAILED");
|
||||
}
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->Tender->id));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->data = $this->Tender->findById($id);
|
||||
} else {
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$tender_types = $this->Tender->TenderType->find
|
||||
('list', array('order' => array('name')));
|
||||
$this->set(compact('tender_types'));
|
||||
|
||||
$types = $this->Tender->TenderType->find('all', array('contain' => false));
|
||||
$this->set(compact('types'));
|
||||
|
||||
// Prepare to render.
|
||||
$title = ('Tender #' . $this->data['Tender']['id'] .
|
||||
' : ' . $this->data['Tender']['name'] .
|
||||
" : Edit");
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
}
|
||||
@@ -1,520 +0,0 @@
|
||||
<?php
|
||||
|
||||
class TransactionsController extends AppController {
|
||||
|
||||
var $components = array('RequestHandler');
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('Invoices',
|
||||
array('controller' => 'transactions', 'action' => 'invoice'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Receipts',
|
||||
array('controller' => 'transactions', 'action' => 'receipt'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Deposits',
|
||||
array('controller' => 'transactions', 'action' => 'deposit'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('All',
|
||||
array('controller' => 'transactions', 'action' => 'all'), null,
|
||||
'CONTROLLER');
|
||||
|
||||
// REVISIT <AP>: 20090824
|
||||
// Right now, we wish to keep things simple. Don't make these
|
||||
// links available to non-admin users.
|
||||
if (empty($this->params['admin']))
|
||||
$this->sideMenuEnable('CONTROLLER', $this->std_area, false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / all
|
||||
* - Generate a listing of transactions
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function all() { $this->gridView('All Transactions', 'all'); }
|
||||
function invoice() { $this->gridView('Invoices'); }
|
||||
function receipt() { $this->gridView('Receipts'); }
|
||||
function deposit() {
|
||||
/* $this->addSideMenuLink('New Deposit', */
|
||||
/* array('controller' => 'tenders', 'action' => 'deposit'), null, */
|
||||
/* 'CONTROLLER', $this->new_area); */
|
||||
$this->gridView('Deposits');
|
||||
}
|
||||
|
||||
function gridView($title, $action = null, $element = null) {
|
||||
if ($title != 'Deposits')
|
||||
$this->set('include', array('Customer'));
|
||||
parent::gridView($title, $action, $element);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
return array
|
||||
('link' =>
|
||||
array(// Models
|
||||
'Account' => array('fields' => array()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$link = $this->gridDataCountTables($params, $model);
|
||||
$link['link']['StatementEntry'] = array('fields' => array());
|
||||
$link['link']['DepositTender'] = array('fields' => array());
|
||||
$link['link']['Customer'] = array('fields' => array('id', 'name'));
|
||||
return $link;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
//$fields[] = 'COUNT(StatementEntry.id) AS entries';
|
||||
$fields[] = ("IF(Transaction.type = 'DEPOSIT'," .
|
||||
" COUNT(DepositTender.id)," .
|
||||
" COUNT(StatementEntry.id)) AS entries");
|
||||
return array_merge($fields,
|
||||
$this->Transaction->LedgerEntry->debitCreditFields(false, true, 'Transaction'));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
if (in_array($params['action'], array('invoice', 'receipt', 'deposit')))
|
||||
$conditions[] = array('Transaction.type' => strtoupper($params['action']));
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
|
||||
? 'deposit_slip' : 'view'));
|
||||
$links['Customer'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postInvoice
|
||||
* - handles the creation of a charge invoice
|
||||
*/
|
||||
|
||||
function postInvoice($redirect = true) {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->Transaction->addInvoice($this->data, null,
|
||||
$this->data['Lease']['id'])) {
|
||||
$this->Session->setFlash("INVOICE FAILED", true);
|
||||
// REVISIT <AP> 20090706:
|
||||
// Until we can work out the session problems,
|
||||
// just die.
|
||||
die("<H1>INVOICE FAILED</H1>");
|
||||
}
|
||||
|
||||
if ($redirect) {
|
||||
if (!empty($this->data['Customer']['id']))
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action' => 'receipt',
|
||||
$this->data['Customer']['id']));
|
||||
else
|
||||
$this->redirect(array('controller' => 'leases',
|
||||
'action' => 'view',
|
||||
$this->data['Lease']['id']));
|
||||
}
|
||||
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
$this->autoRender = false;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postReceipt
|
||||
* - handles the creation of a receipt
|
||||
*/
|
||||
|
||||
function postReceipt($redirect = true) {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
foreach($this->data['Entry'] AS &$entry) {
|
||||
$entry['Tender'] = $entry['type'][$entry['tender_type_id']];
|
||||
unset($entry['type']);
|
||||
unset($entry['tender_type_id']);
|
||||
}
|
||||
|
||||
if (!$this->Transaction->addReceipt($this->data,
|
||||
$this->data['Customer']['id'],
|
||||
(isset($this->data['Lease']['id'])
|
||||
? $this->data['Lease']['id']
|
||||
: null ))) {
|
||||
$this->Session->setFlash("RECEIPT FAILED", true);
|
||||
// REVISIT <AP> 20090706:
|
||||
// Until we can work out the session problems,
|
||||
// just die.
|
||||
die("<H1>RECEIPT FAILED</H1>");
|
||||
}
|
||||
|
||||
if ($redirect)
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$this->data['Customer']['id']));
|
||||
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
$this->autoRender = false;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postDeposit
|
||||
* - handles the creation of a deposit transaction
|
||||
*/
|
||||
|
||||
function postDeposit() {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
//pr($this->data);
|
||||
|
||||
// Go through each type of tender presented to the user
|
||||
// Determine which are to be deposited, and which are to
|
||||
// have their corresponding account ledgers closed.
|
||||
$deposit_tender_ids = array();
|
||||
$deposit_type_ids = array();
|
||||
$close_type_ids = array();
|
||||
foreach ($this->data['TenderType'] AS $type_id => $type) {
|
||||
$type['items'] = unserialize($type['items']);
|
||||
if (empty($type['selection']) ||
|
||||
$type['selection'] === 'none' ||
|
||||
($type['selection'] === 'subset' && count($type['items']) == 0))
|
||||
continue;
|
||||
|
||||
// The deposit includes either the whole type, or just certain tenders
|
||||
if ($type['selection'] === 'all')
|
||||
$deposit_type_ids[] = $type_id;
|
||||
else
|
||||
$deposit_tender_ids = array_merge($deposit_tender_ids, $type['items']);
|
||||
|
||||
// Should we close the ledger for this tender type?
|
||||
// First, the user would have to request that we do so,
|
||||
// but additionally, we shouldn't close a ledger unless
|
||||
// all the tenders are included in this deposit. That
|
||||
// doesn't guarantee that the ledger has a zero balance,
|
||||
// but it does carry the balance forward, and a total
|
||||
// deposit would imply a fresh start, so go for it.
|
||||
if (!empty($type['close']) && $type['selection'] === 'all')
|
||||
$close_type_ids[] = $type_id;
|
||||
}
|
||||
|
||||
// Make sure we actually have something to deposit
|
||||
if (empty($deposit_type_ids) && empty($deposit_tender_ids)) {
|
||||
$this->Session->setFlash(__('Nothing to Deposit', true));
|
||||
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
|
||||
}
|
||||
|
||||
// Build up a set of conditions based on user selection
|
||||
$deposit_conditions = array();
|
||||
if (!empty($deposit_type_ids))
|
||||
$deposit_conditions[] = array('TenderType.id' => $deposit_type_ids);
|
||||
if (!empty($deposit_tender_ids))
|
||||
$deposit_conditions[] = array('DepositTender.id' => $deposit_tender_ids);
|
||||
|
||||
// Add in confirmation that items have not already been deposited
|
||||
$deposit_conditions =
|
||||
array(array('DepositTender.deposit_transaction_id' => null),
|
||||
array('OR' => $deposit_conditions));
|
||||
|
||||
// Lookup the items to be deposited
|
||||
$tenders = $this->Transaction->DepositTender->find
|
||||
('all',
|
||||
array('contain' => array('TenderType', 'LedgerEntry'),
|
||||
'conditions' => $deposit_conditions,
|
||||
));
|
||||
|
||||
// Build the deposit transaction
|
||||
$deposit = array('Transaction' => array(), 'Entry' => array());
|
||||
foreach ($tenders AS $tender) {
|
||||
$deposit['Entry'][] =
|
||||
array('tender_id' => $tender['DepositTender']['id'],
|
||||
'account_id' => $tender['LedgerEntry']['account_id'],
|
||||
'amount' => $tender['LedgerEntry']['amount'],
|
||||
);
|
||||
}
|
||||
|
||||
//pr(compact('deposit_type_ids', 'deposit_tender_ids', 'close_type_ids', 'deposit_conditions', 'deposit'));
|
||||
|
||||
// OK, perform the deposit and associated accounting
|
||||
$result = $this->Transaction->addDeposit
|
||||
($deposit, $this->data['Deposit']['Account']['id']);
|
||||
//pr(compact('deposit', 'result'));
|
||||
|
||||
// Close any ledgers necessary
|
||||
if (!empty($close_type_ids)) {
|
||||
// Find the accounts associated with the types to close ...
|
||||
$accounts = $this->Transaction->DepositTender->find
|
||||
('all',
|
||||
array('contain' => array('TenderType.account_id'),
|
||||
'conditions' => array(array('TenderType.id' => $close_type_ids)),
|
||||
));
|
||||
|
||||
// ... and close them
|
||||
$this->Transaction->Account->closeCurrentLedgers
|
||||
(array_map(create_function('$item', 'return $item["TenderType"]["account_id"];'), $accounts));
|
||||
}
|
||||
|
||||
// Look out for errors
|
||||
if ($result['error']) {
|
||||
$this->Session->setFlash(__('Unable to Create Deposit', true));
|
||||
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
|
||||
}
|
||||
|
||||
// Present the deposit slip to the user
|
||||
$this->redirect(array('controller' => 'transactions',
|
||||
'action' => 'deposit_slip',
|
||||
$result['transaction_id']));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postWriteOff
|
||||
* - handles the write off of bad debt
|
||||
*/
|
||||
|
||||
function postWriteOff() {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->data;
|
||||
if (empty($data['Customer']['id']))
|
||||
$data['Customer']['id'] = null;
|
||||
if (empty($data['Lease']['id']))
|
||||
$data['Lease']['id'] = null;
|
||||
|
||||
pr(compact('data'));
|
||||
|
||||
if (!$this->Transaction->addWriteOff($data,
|
||||
$data['Customer']['id'],
|
||||
$data['Lease']['id'])) {
|
||||
$this->Session->setFlash("WRITE OFF FAILED", true);
|
||||
// REVISIT <AP> 20090706:
|
||||
// Until we can work out the session problems,
|
||||
// just die.
|
||||
die("<H1>WRITE-OFF FAILED</H1>");
|
||||
}
|
||||
|
||||
// Return to viewing the lease/customer
|
||||
if (empty($data['Lease']['id']))
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$data['Customer']['id']));
|
||||
else
|
||||
$this->redirect(array('controller' => 'leases',
|
||||
'action' => 'view',
|
||||
$data['Lease']['id']));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: postRefund
|
||||
* - handles issuing a customer refund
|
||||
*/
|
||||
|
||||
function postRefund() {
|
||||
if (!$this->RequestHandler->isPost()) {
|
||||
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->data;
|
||||
if (empty($data['Customer']['id']))
|
||||
$data['Customer']['id'] = null;
|
||||
if (empty($data['Lease']['id']))
|
||||
$data['Lease']['id'] = null;
|
||||
|
||||
if (!$this->Transaction->addRefund($data,
|
||||
$data['Customer']['id'],
|
||||
$data['Lease']['id'])) {
|
||||
$this->Session->setFlash("REFUND FAILED", true);
|
||||
// REVISIT <AP> 20090706:
|
||||
// Until we can work out the session problems,
|
||||
// just die.
|
||||
die("<H1>REFUND FAILED</H1>");
|
||||
}
|
||||
|
||||
// Return to viewing the lease/customer
|
||||
if (empty($data['Lease']['id']))
|
||||
$this->redirect(array('controller' => 'customers',
|
||||
'action' => 'view',
|
||||
$data['Customer']['id']));
|
||||
else
|
||||
$this->redirect(array('controller' => 'leases',
|
||||
'action' => 'view',
|
||||
$data['Lease']['id']));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: destroy
|
||||
* - Deletes a transaction and associated entries
|
||||
* - !!WARNING!! This should be used with EXTREME caution, as it
|
||||
* irreversibly destroys the data. It is not for normal use.
|
||||
*/
|
||||
|
||||
function destroy($id) {
|
||||
$this->Transaction->id = $id;
|
||||
$customer_id = $this->Transaction->field('customer_id');
|
||||
$this->Transaction->destroy($id);
|
||||
$this->redirect(array('controller' => 'customers', 'action' => 'view', $customer_id));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific transaction
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
$transaction = $this->Transaction->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
array(// Models
|
||||
'Account(id,name,level)',
|
||||
'Ledger(id,sequence)',
|
||||
'NsfTender(id,name)',
|
||||
),
|
||||
'conditions' => array(array('Transaction.id' => $id),
|
||||
),
|
||||
));
|
||||
|
||||
if (empty($transaction)) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
$transaction['Account']['link'] =
|
||||
$transaction['Account']['level'] >=
|
||||
$this->Permission->level('controller.accounts');
|
||||
|
||||
if ($transaction['Transaction']['type'] === 'DEPOSIT')
|
||||
$this->addSideMenuLink('View Slip',
|
||||
array('action' => 'deposit_slip', $id), null,
|
||||
'ACTION');
|
||||
|
||||
$this->addSideMenuLink('Destroy',
|
||||
array('action' => 'destroy', $id),
|
||||
array('confirmMessage' =>
|
||||
"This may leave the database in an unstable state." .
|
||||
" Do NOT do this unless you know what you're doing." .
|
||||
" Proceed anyway?"),
|
||||
'ACTION', $this->admin_area);
|
||||
|
||||
// OK, prepare to render.
|
||||
$title = 'Transaction #' . $transaction['Transaction']['id'];
|
||||
$this->set(compact('transaction', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: deposit_slip
|
||||
* - Special presentation
|
||||
* Processes the user input and updates the database
|
||||
*/
|
||||
|
||||
function deposit_slip($id) {
|
||||
// Find the deposit transaction
|
||||
$this->Transaction->id = $id;
|
||||
$deposit = $this->Transaction->find('first', array('contain' => array('Account')));
|
||||
|
||||
// Get a summary of all forms of tender in the deposit
|
||||
$tenders = $this->Transaction->find
|
||||
('all',
|
||||
array('link' => array('DepositTender' =>
|
||||
array('fields' => array(),
|
||||
'TenderType',
|
||||
'LedgerEntry' =>
|
||||
array('fields' => array()))),
|
||||
'fields' => array(//'TenderType.id', 'TenderType.name',
|
||||
"COUNT(DepositTender.id) AS 'count'",
|
||||
"SUM(LedgerEntry.amount) AS 'total'"),
|
||||
//'conditions' => array(array('DepositTender.deposit_transaction_id' => $id)),
|
||||
'conditions' => array(array('Transaction.id' => $id)),
|
||||
'group' => 'TenderType.id',
|
||||
));
|
||||
|
||||
// Verify the deposit exists, and that something was actually deposited
|
||||
if (empty($deposit) || empty($tenders)) {
|
||||
$this->Session->setFlash(__('Invalid Deposit.', true));
|
||||
$this->redirect(array('action'=>'deposit'));
|
||||
}
|
||||
|
||||
// Add the summary to our deposit slip data container
|
||||
$deposit['types'] = array();
|
||||
foreach ($tenders AS $tender) {
|
||||
$deposit['types'][$tender['TenderType']['id']] =
|
||||
$tender['TenderType'] + $tender[0];
|
||||
}
|
||||
|
||||
$deposit_total = 0;
|
||||
foreach ($deposit['types'] AS $type)
|
||||
$deposit_total += $type['total'];
|
||||
|
||||
if (abs($deposit['Transaction']['amount'] - $deposit_total) >= .001)
|
||||
$this->INTERNAL_ERROR("Deposit items ($deposit_total) do not add up to deposit slip total (".$deposit['Transaction']['amount'].")");
|
||||
|
||||
$this->addSideMenuLink('View',
|
||||
array('action' => 'view', $id), null,
|
||||
'ACTION');
|
||||
|
||||
$title = 'Deposit Slip';
|
||||
$this->set(compact('title', 'deposit'));
|
||||
$this->render('deposit_slip');
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
<?php
|
||||
|
||||
class UnitSizesController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('1 Bedroom',
|
||||
array('controller' => 'unit_sizes', 'action' => 'bd1'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('2 Bedroom',
|
||||
array('controller' => 'unit_sizes', 'action' => 'bd2'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('3 Bedroom',
|
||||
array('controller' => 'unit_sizes', 'action' => 'bd3'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('4+ Bedroom',
|
||||
array('controller' => 'unit_sizes', 'action' => 'bd4'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Auto',
|
||||
array('controller' => 'unit_sizes', 'action' => 'auto'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Boat',
|
||||
array('controller' => 'unit_sizes', 'action' => 'boat'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('RV',
|
||||
array('controller' => 'unit_sizes', 'action' => 'rv'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('All',
|
||||
array('controller' => 'unit_sizes', 'action' => 'all'), null,
|
||||
'CONTROLLER');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / unavailable / vacant / occupied / all
|
||||
* - Generate a listing of units
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function bd1() { $this->gridView('Sizes for 1 Bedroom'); }
|
||||
function bd2() { $this->gridView('Sizes for 2 Bedrooms'); }
|
||||
function bd3() { $this->gridView('Sizes for 3 Bedroom'); }
|
||||
function bd4() { $this->gridView('Sizes for 4+ Bedroom'); }
|
||||
function auto() { $this->gridView('Sizes for an Automobile'); }
|
||||
function boat() { $this->gridView('Sizes for a Boat'); }
|
||||
function rv() { $this->gridView('Sizes for an RV'); }
|
||||
function all() { $this->gridView('All Unit Sizes', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
return array('link' => array('UnitType'));
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$tables = $this->gridDataCountTables($params, $model);
|
||||
$tables['link']['Unit'] = array();
|
||||
return $tables;
|
||||
}
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
$fields[] = 'ROUND(UnitSize.width/12, 1) AS width';
|
||||
$fields[] = 'ROUND(UnitSize.depth/12, 1) AS depth';
|
||||
$fields[] = 'ROUND(UnitSize.height/12, 1) AS height';
|
||||
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft';
|
||||
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12, 0) AS cuft';
|
||||
$fields[] = 'ROUND(UnitSize.rent / (UnitSize.width/12 * UnitSize.depth/12), 2) AS sqcost';
|
||||
$fields[] = 'ROUND(UnitSize.rent / (UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12), 2) AS cucost';
|
||||
|
||||
$fields[] = 'COUNT(Unit.id) AS units';
|
||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionUnavailable() . ', 1, 0)) AS unavailable';
|
||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionAvailable() . ', 1, 0)) AS available';
|
||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 1, 0)) AS occupied';
|
||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 0, 1)) / COUNT(Unit.id) AS vacancy';
|
||||
$fields[] = 'SUM(IF(' . $this->UnitSize->Unit->conditionOccupied() . ', 1, 0)) / COUNT(Unit.id) AS occupancy';
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
// REVISIT <AP>: 20090825
|
||||
// Sizes should come from the database.
|
||||
// For now, I took an assumed average need, then bracketed
|
||||
// with +/- 50 sqft. This gives a 100sqft range for each.
|
||||
if ($params['action'] === 'bd1') { // 75 sqft
|
||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 125';
|
||||
}
|
||||
elseif ($params['action'] === 'bd2') { // 125 sqft
|
||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 75';
|
||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 175';
|
||||
}
|
||||
elseif ($params['action'] === 'bd3') { // 175 sqft
|
||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 125';
|
||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) <= 225';
|
||||
}
|
||||
elseif ($params['action'] === 'bd4') { // 225 sqft
|
||||
$conditions[] = array('UnitType.id' => array_keys($this->UnitSize->UnitType->enclosedTypes()));
|
||||
$conditions[] = '(UnitSize.width/12 * UnitSize.depth/12) >= 175';
|
||||
}
|
||||
elseif (in_array($params['action'], array('auto', 'boat', 'rv'))) {
|
||||
$conditions[] = array('UnitType.id' =>
|
||||
array_merge(array_keys($this->UnitSize->UnitType->enclosedTypes()),
|
||||
array_keys($this->UnitSize->UnitType->outdoorTypes())));
|
||||
list($width, $depth, $height) = array(8, 15, null);
|
||||
if ($params['action'] === 'auto')
|
||||
$depth = 15;
|
||||
elseif ($params['action'] === 'boat')
|
||||
$depth = 15;
|
||||
elseif ($params['action'] === 'rv')
|
||||
list($width, $depth, $height) = array(10, 25, 12);
|
||||
|
||||
$conditions[] = "(UnitSize.width/12) >= $width";
|
||||
$conditions[] = "(UnitSize.depth/12) >= $depth";
|
||||
if (isset($height))
|
||||
$conditions[] = array('OR' =>
|
||||
array("(UnitSize.height/12) >= $height",
|
||||
//"UnitSize.height IS NULL",
|
||||
array('UnitType.id' =>
|
||||
array_keys($this->UnitSize->UnitType->outdoorTypes())),
|
||||
));
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
if ($index == 'UnitType.name')
|
||||
$index = 'UnitType.code';
|
||||
|
||||
$order = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
// After sorting by whatever the user wants, add these
|
||||
// defaults into the sort mechanism. If we're already
|
||||
// sorting by one of them, it will only be redundant,
|
||||
// and should cause no harm (possible a longer query?)
|
||||
$order[] = 'UnitType.code ' . $direction;
|
||||
$order[] = 'sqft ' . $direction;
|
||||
$order[] = 'UnitSize.rent ' . $direction;
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['UnitSize'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: view
|
||||
* - Displays information about a specific entry
|
||||
*/
|
||||
|
||||
function view($id = null) {
|
||||
if (!$id) {
|
||||
$this->Session->setFlash(__('Invalid Item.', true));
|
||||
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
|
||||
}
|
||||
|
||||
// Get the UnitSize and related fields
|
||||
$this->UnitSize->id = $id;
|
||||
$size = $this->UnitSize->find
|
||||
('first', array
|
||||
('contain' => array('UnitType'),
|
||||
'fields' => array('UnitSize.*', 'UnitType.*',
|
||||
'ROUND(UnitSize.width/12, 1) AS width',
|
||||
'ROUND(UnitSize.depth/12, 1) AS depth',
|
||||
'ROUND(UnitSize.height/12, 1) AS height',
|
||||
'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft',
|
||||
'ROUND(UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12, 0) AS cuft'),
|
||||
));
|
||||
$size['UnitSize'] = $size[0] + $size['UnitSize'];
|
||||
unset($size[0]);
|
||||
|
||||
$this->set(compact('size'));
|
||||
$this->set('stats', $this->UnitSize->stats($id));
|
||||
|
||||
// Prepare to render.
|
||||
$title = "Unit Size : {$size['UnitSize']['name']}";
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
* - Edit unit_size information
|
||||
*/
|
||||
|
||||
function edit($id = null) {
|
||||
$this->INTERNAL_ERROR('NOT READY');
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (empty($this->data['UnitSize']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->data['UnitSize']['id']));
|
||||
}
|
||||
|
||||
// Make sure we have unit_size data
|
||||
if (empty($this->data['UnitSize']) || empty($this->data['UnitSize']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
// Save the unit_size and all associated data
|
||||
$this->UnitSize->create();
|
||||
$this->UnitSize->id = $this->data['UnitSize']['id'];
|
||||
if (!$this->UnitSize->save($this->data, false)) {
|
||||
$this->Session->setFlash("UNIT_SIZE SAVE FAILED", true);
|
||||
pr("UNIT_SIZE SAVE FAILED");
|
||||
}
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->UnitSize->id));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->data = $this->UnitSize->findById($id);
|
||||
} else {
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Prepare to render.
|
||||
$title = ('UnitSize ' . $this->data['UnitSize']['name'] .
|
||||
" : Edit");
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
}
|
||||
@@ -1,521 +0,0 @@
|
||||
<?php
|
||||
|
||||
class UnitsController extends AppController {
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* override: addGridViewSideMenuLinks
|
||||
* - Adds grid view navigation side menu links
|
||||
*/
|
||||
|
||||
function addGridViewSideMenuLinks() {
|
||||
parent::addGridViewSideMenuLinks();
|
||||
|
||||
$this->addSideMenuLink('Unavailable',
|
||||
array('controller' => 'units', 'action' => 'unavailable'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Vacant',
|
||||
array('controller' => 'units', 'action' => 'vacant'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Occupied',
|
||||
array('controller' => 'units', 'action' => 'occupied'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Overlocked',
|
||||
array('controller' => 'units', 'action' => 'locked'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('Liened',
|
||||
array('controller' => 'units', 'action' => 'liened'), null,
|
||||
'CONTROLLER');
|
||||
$this->addSideMenuLink('All',
|
||||
array('controller' => 'units', 'action' => 'all'), null,
|
||||
'CONTROLLER');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: index / unavailable / vacant / occupied / all
|
||||
* - Generate a listing of units
|
||||
*/
|
||||
|
||||
function index() { $this->all(); }
|
||||
function unavailable() { $this->gridView('Unavailable Units'); }
|
||||
function vacant() { $this->gridView('Vacant Units'); }
|
||||
function occupied() { $this->gridView('Occupied Units'); }
|
||||
function locked() { $this->gridView('Overlocked Units'); }
|
||||
function liened() { $this->gridView('Liened Units'); }
|
||||
function all() { $this->gridView('All Units', 'all'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* virtuals: gridData
|
||||
* - With the application controller handling the gridData action,
|
||||
* these virtual functions ensure that the correct data is passed
|
||||
* to jqGrid.
|
||||
*/
|
||||
|
||||
function gridDataSetup(&$params) {
|
||||
parent::gridDataSetup($params);
|
||||
if (!isset($params['action']))
|
||||
$params['action'] = 'all';
|
||||
}
|
||||
|
||||
function gridDataCountTables(&$params, &$model) {
|
||||
return array
|
||||
('link' => array('UnitSize' => array('fields' => array('id', 'name')),
|
||||
'CurrentLease' => array('fields' => array('id'))));
|
||||
|
||||
/* if ($params['action'] === 'occupied') */
|
||||
/* $link['Lease'] = array('fields' => array(), */
|
||||
/* // Models */
|
||||
/* 'Contact' => array('fields' => array('display_name'), */
|
||||
/* //'type' => 'LEFT', */
|
||||
/* ), */
|
||||
/* ); */
|
||||
|
||||
}
|
||||
|
||||
function gridDataTables(&$params, &$model) {
|
||||
$link = $this->gridDataCountTables($params, $model);
|
||||
$link['link']['CurrentLease']['StatementEntry'] = array('fields' => array());
|
||||
$link['link']['Lock'];
|
||||
return $link;
|
||||
}
|
||||
|
||||
/* function gridDataTables(&$params, &$model) { */
|
||||
/* return array */
|
||||
/* ('link' => array('Unit' => array('fields' => array('Unit.id', 'Unit.name')), */
|
||||
/* 'Customer' => array('fields' => array('Customer.id', 'Customer.name')))); */
|
||||
/* } */
|
||||
|
||||
function gridDataFields(&$params, &$model) {
|
||||
$fields = parent::gridDataFields($params, $model);
|
||||
|
||||
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft';
|
||||
return array_merge($fields,
|
||||
$this->Unit->Lease->StatementEntry->chargeDisbursementFields(true));
|
||||
}
|
||||
|
||||
function gridDataConditions(&$params, &$model) {
|
||||
$conditions = parent::gridDataConditions($params, $model);
|
||||
|
||||
if ($params['action'] === 'unavailable') {
|
||||
$conditions[] = $this->Unit->conditionUnavailable();
|
||||
}
|
||||
elseif ($params['action'] === 'vacant') {
|
||||
$conditions[] = $this->Unit->conditionVacant();
|
||||
}
|
||||
elseif ($params['action'] === 'occupied') {
|
||||
$conditions[] = $this->Unit->conditionOccupied();
|
||||
}
|
||||
elseif ($params['action'] === 'unoccupied') {
|
||||
$conditions[] = array('NOT' => array($this->Unit->conditionOccupied()));
|
||||
}
|
||||
elseif ($params['action'] === 'locked') {
|
||||
$conditions[] = $this->Unit->conditionLocked();
|
||||
}
|
||||
elseif ($params['action'] === 'liened') {
|
||||
$conditions[] = $this->Unit->conditionLiened();
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
function gridDataOrder(&$params, &$model, $index, $direction) {
|
||||
// Instead of sorting by name, sort by defined order
|
||||
if ($index === 'Unit.name')
|
||||
$index = 'Unit.sort_order';
|
||||
|
||||
$order = array();
|
||||
$order[] = parent::gridDataOrder($params, $model, $index, $direction);
|
||||
|
||||
// If sorting by anything other than name (defined order)
|
||||
// add the sort-order as a secondary condition
|
||||
if ($index !== 'Unit.name')
|
||||
$order[] = parent::gridDataOrder($params, $model,
|
||||
'Unit.sort_order', $direction);
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
|
||||
$links['Unit'] = array('name');
|
||||
$links['UnitSize'] = array('name');
|
||||
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: move_in
|
||||
* - Sets up the move-in page for the given unit.
|
||||
*/
|
||||
|
||||
function move_in($id = null) {
|
||||
$customer = array();
|
||||
$unit = array();
|
||||
|
||||
if (!empty($id)) {
|
||||
$this->Unit->recursive = -1;
|
||||
$unit = current($this->Unit->read(null, $id));
|
||||
}
|
||||
|
||||
$title = 'Unit Move-In';
|
||||
$this->set(compact('customer', 'unit', 'title'));
|
||||
$this->render('/leases/move');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: move_out
|
||||
* - prepare or execute a move out on a specific lease
|
||||
*/
|
||||
|
||||
function move_out($id) {
|
||||
|
||||
$unit = $this->Unit->find
|
||||
('first', array
|
||||
('contain' => array
|
||||
(// Models
|
||||
'CurrentLease' =>
|
||||
array(//'conditions' => array('Lease.moveout_date' => null),
|
||||
// Models
|
||||
'Customer' =>
|
||||
array('fields' => array('id', 'name'),
|
||||
),
|
||||
),
|
||||
),
|
||||
'conditions' => array('Unit.id' => $id),
|
||||
));
|
||||
$this->set('customer', $unit['CurrentLease']['Customer']);
|
||||
$this->set('unit', $unit['Unit']);
|
||||
$this->set('lease', $unit['CurrentLease']);
|
||||
|
||||
$redirect = array('controller' => 'units',
|
||||
'action' => 'view',
|
||||
$id);
|
||||
|
||||
$title = ('Lease #' . $unit['CurrentLease']['number'] . ': ' .
|
||||
$unit['Unit']['name'] . ': ' .
|
||||
$unit['CurrentLease']['Customer']['name'] . ': Prepare Move-Out');
|
||||
$this->set(compact('title', 'redirect'));
|
||||
$this->render('/leases/move');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: lock/unlock/lien
|
||||
* - Transitions the unit into / out of the LOCKED state
|
||||
*/
|
||||
|
||||
function status($id, $status) {
|
||||
$this->Unit->updateStatus($id, $status, true);
|
||||
$this->redirect(array('action' => 'view', $id));
|
||||
}
|
||||
|
||||
function lock($id) {
|
||||
if (isset($this->data)) {
|
||||
$id = $this->id = $this->data['Unit']['id'];
|
||||
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (isset($id))
|
||||
$this->redirect(array('action'=>'view', $id));
|
||||
|
||||
$this->redirect(array('action'=>'index'));
|
||||
}
|
||||
|
||||
// Figure out which locks the user put on
|
||||
$locks = array();
|
||||
if (isset($this->data['Lock']) && is_array($this->data['Lock'])) {
|
||||
foreach ($this->data['Lock'] AS $lock) {
|
||||
$locks[] = $lock['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// Save the lock and all associated data
|
||||
if (!$this->Unit->lockUnit($id, $locks)) {
|
||||
$this->Session->setFlash("UNIT LOCK FAILED", true);
|
||||
pr("UNIT LOCK FAILED");
|
||||
}
|
||||
|
||||
// If it's no longer locked, change status to OCCUPIED
|
||||
// Could still be liened... but that would be odd.
|
||||
if (count($locks) == 0)
|
||||
$this->status($id, 'OCCUPIED');
|
||||
|
||||
// If we're not liened, we must now just be locked
|
||||
if (!$this->Unit->liened(intval($id)))
|
||||
$this->status($id, 'LOCKED');
|
||||
|
||||
// Otherwise, don't change anything.
|
||||
$this->redirect(array('action' => 'view', $id));
|
||||
}
|
||||
|
||||
if (!$id)
|
||||
$this->INTERNAL_ERROR("$id cannot be NULL");
|
||||
|
||||
// Get all locks on this unit
|
||||
$this->data = $this->Unit->find
|
||||
('first',
|
||||
array('contain' => array('Lock' => array('id')),
|
||||
'fields' => array('id', 'name'),
|
||||
'conditions' => array('Unit.id' => $id)
|
||||
));
|
||||
|
||||
$locks = $this->Unit->Lock->lockList();
|
||||
/* $locksold = $locks; */
|
||||
/* foreach ($locksold AS $name) { */
|
||||
/* $locks[$name] = $name; */
|
||||
/* } */
|
||||
$this->set(compact('locks'));
|
||||
|
||||
// Prepare to render.
|
||||
//pr($this->data);
|
||||
$this->set(compact('title'));
|
||||
// $this->render('lock');
|
||||
}
|
||||
|
||||
|
||||
function unlock($id) { $this->lock($id); }
|
||||
function lien($id) { $this->status($id, 'LIENED'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: overview
|
||||
* - Displays overview information for all units
|
||||
*/
|
||||
function overview() {
|
||||
$result = $this->Unit->find
|
||||
('all',
|
||||
array('link' => array('UnitSize' => array('fields' => array(), 'UnitType' => array('fields' => array('name')))),
|
||||
'fields' => array('status', 'COUNT(Unit.id) AS cnt', 'SUM(Unit.rent) AS rents'),
|
||||
//'conditions' => array('
|
||||
'group' => array('UnitType.id', 'Unit.status'),
|
||||
'order' => array('UnitType.name', 'Unit.status')
|
||||
));
|
||||
|
||||
$overview = array('types' => array(), 'count' => 0, 'rents' => 0);
|
||||
foreach ($result AS $row) {
|
||||
$utname = $row['UnitType']['name'];
|
||||
if (empty($overview['types'][$utname]))
|
||||
$overview['types'][$utname] = array('name' => $utname,
|
||||
'subs' => array(),
|
||||
'count' => 0,
|
||||
'rents' => 0,
|
||||
'phys_pct' => 0,
|
||||
'econ_pct' => 0);
|
||||
$type = &$overview['types'][$utname];
|
||||
$type['subs'][] = array('name' => $row['Unit']['status'],
|
||||
'count' => $row[0]['cnt'],
|
||||
'rents' => $row[0]['rents'],
|
||||
'phys_subpct' => 0,
|
||||
'phys_totpct' => 0,
|
||||
'econ_subpct' => 0,
|
||||
'econ_totpct' => 0);
|
||||
|
||||
|
||||
$type['count'] += $row[0]['cnt'];
|
||||
$type['rents'] += $row[0]['rents'];
|
||||
|
||||
$overview['count'] += $row[0]['cnt'];
|
||||
$overview['rents'] += $row[0]['rents'];
|
||||
}
|
||||
|
||||
foreach ($overview['types'] AS &$type) {
|
||||
foreach ($type['subs'] AS &$sub) {
|
||||
$sub['phys_subpct'] = $sub['count'] / $type['count'];
|
||||
$sub['econ_subpct'] = $sub['rents'] / $type['rents'];
|
||||
$sub['phys_totpct'] = $sub['count'] / $overview['count'];
|
||||
$sub['econ_totpct'] = $sub['rents'] / $overview['rents'];
|
||||
}
|
||||
$type['phys_pct'] = $type['count'] / $overview['count'];
|
||||
$type['econ_pct'] = $type['rents'] / $overview['rents'];
|
||||
}
|
||||
|
||||
// Enable the Reports menu section
|
||||
$this->sideMenuAreaActivate('REPORT');
|
||||
|
||||
// Prepare to render.
|
||||
$this->set('title', 'Unit Overview');
|
||||
$this->set(compact('overview'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* 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',
|
||||
'Lock',
|
||||
'Lease' => array('Customer'),
|
||||
'CurrentLease' => array('Customer')
|
||||
),
|
||||
'conditions' => array('Unit.id' => $id),
|
||||
));
|
||||
|
||||
// Get the balance on each lease.
|
||||
foreach ($unit['Lease'] AS &$lease) {
|
||||
$stats = $this->Unit->Lease->stats($lease['id']);
|
||||
$lease['balance'] = $stats['balance'];
|
||||
}
|
||||
|
||||
$outstanding_balance = 0;
|
||||
$outstanding_deposit = 0;
|
||||
if (isset($unit['CurrentLease']['id'])) {
|
||||
// Figure out the outstanding balance of the current lease.
|
||||
$stats = $this->Unit->stats($id);
|
||||
$outstanding_balance =
|
||||
$stats['CurrentLease']['balance'];
|
||||
|
||||
// Figure out the total security deposit for the current lease.
|
||||
$deposits = $this->Unit->Lease->securityDeposits($unit['CurrentLease']['id']);
|
||||
$outstanding_deposit = $this->Unit->Lease->securityDepositBalance($unit['CurrentLease']['id']);
|
||||
}
|
||||
|
||||
// Add a mechanism to lock ANY unit, regardless of status
|
||||
$this->addSideMenuLink($this->Unit->lockCount($id) == 0 ? 'Lock' : 'Relock/Unlock',
|
||||
array('action' => 'lock', $id), null,
|
||||
'ACTION');
|
||||
|
||||
// If the unit is locked, but not liened, give option to lien.
|
||||
if ($this->Unit->locked($unit['Unit']['status']) &&
|
||||
!$this->Unit->liened($unit['Unit']['status']))
|
||||
$this->addSideMenuLink('Lien',
|
||||
array('action' => 'lien', $id), null,
|
||||
'ACTION');
|
||||
|
||||
// If there is a current lease on this unit, then provide
|
||||
// a link to move the tenant out. Current lease for a unit
|
||||
// has a bit different definition than a current lease for
|
||||
// a customer, since a lease stays with a customer until it
|
||||
// is finally closed. A lease, however, only stays with a
|
||||
// unit while occupied (since a unit is not responsible for
|
||||
// any lingering financial obligations, like a customer is).
|
||||
// Of course, if there is no current lease, provide a link
|
||||
// to move a new tenant in (if the unit is available).
|
||||
if (isset($unit['CurrentLease']['id'])) {
|
||||
$this->addSideMenuLink('Move-Out',
|
||||
array('action' => 'move_out', $id), null,
|
||||
'ACTION');
|
||||
} elseif ($this->Unit->available($unit['Unit']['status'])) {
|
||||
$this->addSideMenuLink('Move-In',
|
||||
array('action' => 'move_in', $id), null,
|
||||
'ACTION');
|
||||
} else {
|
||||
// Unit is unavailable (dirty, damaged, reserved, business-use, etc)
|
||||
}
|
||||
|
||||
// If there is a current lease, allow new charges to
|
||||
// be added, and payments to be made.
|
||||
if (isset($unit['CurrentLease']['id'])) {
|
||||
$this->addSideMenuLink('New Invoice',
|
||||
array('controller' => 'leases',
|
||||
'action' => 'invoice',
|
||||
$unit['CurrentLease']['id']), null,
|
||||
'ACTION');
|
||||
$this->addSideMenuLink('New Receipt',
|
||||
array('controller' => 'customers',
|
||||
'action' => 'receipt',
|
||||
$unit['CurrentLease']['customer_id']), null,
|
||||
'ACTION');
|
||||
}
|
||||
|
||||
// Always allow the unit to be edited.
|
||||
$this->addSideMenuLink('Edit',
|
||||
array('action' => 'edit', $id), null,
|
||||
'ACTION');
|
||||
|
||||
// Prepare to render.
|
||||
$title = 'Unit ' . $unit['Unit']['name'];
|
||||
$this->set(compact('unit', 'title',
|
||||
'outstanding_balance',
|
||||
'outstanding_deposit'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: edit
|
||||
* - Edit unit information
|
||||
*/
|
||||
|
||||
function edit($id = null) {
|
||||
if (isset($this->data)) {
|
||||
// Check to see if the operation was cancelled.
|
||||
if (isset($this->params['form']['cancel'])) {
|
||||
if (empty($this->data['Unit']['id']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->data['Unit']['id']));
|
||||
}
|
||||
|
||||
// Make sure we have unit data
|
||||
if (empty($this->data['Unit']))
|
||||
$this->redirect(array('action'=>'index'));
|
||||
|
||||
// Make sure we have a rental rate
|
||||
if (empty($this->data['Unit']['rent']))
|
||||
$this->redirect(array('action'=>'view', $this->data['Unit']['id']));
|
||||
|
||||
// Save the unit and all associated data
|
||||
$this->Unit->create();
|
||||
$this->Unit->id = $this->data['Unit']['id'];
|
||||
if (!$this->Unit->save($this->data, false)) {
|
||||
$this->Session->setFlash("UNIT SAVE FAILED", true);
|
||||
pr("UNIT SAVE FAILED");
|
||||
}
|
||||
|
||||
$this->redirect(array('action'=>'view', $this->Unit->id));
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$this->data = $this->Unit->findById($id);
|
||||
$title = 'Unit ' . $this->data['Unit']['name'] . " : Edit";
|
||||
}
|
||||
else {
|
||||
$title = "Enter New Unit";
|
||||
$this->data = array();
|
||||
}
|
||||
|
||||
$statusEnums = $this->Unit->allowedStatusSet($id);
|
||||
$statusEnums = array_combine(array_keys($statusEnums),
|
||||
array_keys($statusEnums));
|
||||
$this->set(compact('statusEnums'));
|
||||
|
||||
$unit_sizes = $this->Unit->UnitSize->find
|
||||
('list', array('order' => array('unit_type_id', 'width', 'depth', 'id')));
|
||||
$this->set(compact('unit_sizes'));
|
||||
|
||||
// Prepare to render.
|
||||
$this->set(compact('title'));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
class UtilController extends AppController {
|
||||
|
||||
var $uses = array();
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: rebuild_box
|
||||
*/
|
||||
|
||||
function rebuild_box($type) {
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
$this->autoRender = false;
|
||||
Configure::write('debug', '0');
|
||||
|
||||
$usrpass = '--user=perki2_pmgruser --password=pmgrauth';
|
||||
$boxdb = 'perki2_pmgr_' . $type;
|
||||
|
||||
$handle = popen("mysqldump $usrpass --opt perki2_pmgr" .
|
||||
" | mysql $usrpass --database=$boxdb", 'r');
|
||||
while (($read = fread($handle, 2096))) {
|
||||
// Do nothing
|
||||
}
|
||||
pclose($handle);
|
||||
|
||||
$url = $_SERVER['HTTP_REFERER'];
|
||||
if (empty($url) || $url == 'undefined')
|
||||
$url = "/$type";
|
||||
|
||||
$this->redirect($url);
|
||||
}
|
||||
|
||||
function rebuild_sandbox() { $this->rebuild_box('sand'); }
|
||||
function rebuild_devbox() { $this->rebuild_box('dev'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: logmsg
|
||||
* - action to allow posting log message data
|
||||
*/
|
||||
|
||||
function logmsg() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
<?php
|
||||
class Account extends AppModel {
|
||||
|
||||
var $hasOne = array(
|
||||
'CurrentLedger' => array(
|
||||
'className' => 'Ledger',
|
||||
// REVISIT <AP> 20090702:
|
||||
// I would prefer this statement, which has no
|
||||
// engine specific code. However, it doesn't
|
||||
// work with the Linkable behavior. I need to
|
||||
// look into that, just not right now.
|
||||
//'conditions' => array(array('CurrentLedger.close_transaction_id' => null)),
|
||||
'conditions' => array('CurrentLedger.close_transaction_id IS NULL'),
|
||||
),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Ledger',
|
||||
'LedgerEntry',
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* 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 (strtolower($fund) == 'debit')
|
||||
return 'credit';
|
||||
|
||||
return 'debit';
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: name
|
||||
* - Returns the name of this account
|
||||
*/
|
||||
function name($id) {
|
||||
$this->cacheQueries = true;
|
||||
$account = $this->find('first', array
|
||||
('recursive' => -1,
|
||||
'fields' => array('name'),
|
||||
'conditions' => array(array('Account.id' => $id)),
|
||||
));
|
||||
$this->cacheQueries = false;
|
||||
|
||||
return $account['Account']['name'];
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: debitCreditFields
|
||||
* - Returns the fields necessary to determine whether the queried
|
||||
* entries are a debit, or a credit, and also the effect each have
|
||||
* on the overall balance of the account.
|
||||
*/
|
||||
|
||||
function debitCreditFields($sum = false, $balance = true,
|
||||
$entry_name = 'LedgerEntry', $account_name = 'Account') {
|
||||
return $this->LedgerEntry->debitCreditFields
|
||||
($sum, $balance, $entry_name, $account_name);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: Account IDs
|
||||
* - Returns the ID of the desired account
|
||||
*/
|
||||
|
||||
function lookup($name, $check = true) {
|
||||
$id = $this->nameToID($name);
|
||||
if (empty($id) && $check)
|
||||
$this->INTERNAL_ERROR("Missing Account '$name'");
|
||||
return $id;
|
||||
}
|
||||
|
||||
function securityDepositAccountID() { return $this->lookup('Security Deposit'); }
|
||||
function rentAccountID() { return $this->lookup('Rent'); }
|
||||
function lateChargeAccountID() { return $this->lookup('Late Charge'); }
|
||||
function nsfAccountID() { return $this->lookup('NSF'); }
|
||||
function nsfChargeAccountID() { return $this->lookup('NSF Charge'); }
|
||||
function taxAccountID() { return $this->lookup('Tax'); }
|
||||
function accountReceivableAccountID() { return $this->lookup('A/R'); }
|
||||
function accountPayableAccountID() { return $this->lookup('A/P'); }
|
||||
function cashAccountID() { return $this->lookup('Cash'); }
|
||||
function checkAccountID() { return $this->lookup('Check'); }
|
||||
function moneyOrderAccountID() { return $this->lookup('Money Order'); }
|
||||
function achAccountID() { return $this->lookup('ACH'); }
|
||||
function concessionAccountID() { return $this->lookup('Concession'); }
|
||||
function waiverAccountID() { return $this->lookup('Waiver'); }
|
||||
function pettyCashAccountID() { return $this->lookup('Petty Cash'); }
|
||||
function invoiceAccountID() { return $this->lookup('Invoice'); }
|
||||
function receiptAccountID() { return $this->lookup('Receipt'); }
|
||||
function badDebtAccountID() { return $this->lookup('Bad Debt'); }
|
||||
function customerCreditAccountID() { return $this->lookup(
|
||||
// REVISIT <AP>: 20090816
|
||||
// Use of A/R works, and saves an excess of accounts.
|
||||
// However, a dedicated account is nice, since it can
|
||||
// quickly be spotted how much is _really_ due, vs
|
||||
// how much has been pre-paid. Customer credits in
|
||||
// A/R is not as clear, although a report is an
|
||||
// obvious solution.
|
||||
//'A/R'
|
||||
'Credit'
|
||||
); }
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: fundamentalAccounts
|
||||
* - Returns an array of accounts by their fundamental type
|
||||
*/
|
||||
|
||||
function fundamentalAccounts($ftype) {
|
||||
$this->cacheQueries = true;
|
||||
$account = $this->find('all', array
|
||||
('contain' => array('CurrentLedger'),
|
||||
'fields' => array('Account.id', 'Account.type', 'Account.name', 'CurrentLedger.id'),
|
||||
'conditions' => array('Account.type' => strtoupper($ftype))
|
||||
));
|
||||
$this->cacheQueries = false;
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: relatedAccounts
|
||||
* - Returns an array of accounts related by similar attributes
|
||||
*/
|
||||
|
||||
function relatedAccounts($attribute, $extra = null) {
|
||||
$this->cacheQueries = true;
|
||||
$accounts = $this->find('all', array
|
||||
('fields' => array('Account.id', 'Account.name'),
|
||||
'conditions' => array('Account.'.$attribute => true),
|
||||
'order' => array('Account.name'),
|
||||
) + (isset($extra) ? $extra : array())
|
||||
);
|
||||
$this->cacheQueries = false;
|
||||
|
||||
// Rearrange to be of the form (id => name)
|
||||
$rel_accounts = array();
|
||||
foreach ($accounts AS $acct) {
|
||||
$rel_accounts[$acct['Account']['id']] = $acct['Account']['name'];
|
||||
}
|
||||
|
||||
return $rel_accounts;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: xxxAccounts
|
||||
* - Returns an array of accounts suitable for activity xxx
|
||||
*/
|
||||
|
||||
function invoiceAccounts() { return $this->relatedAccounts('invoices'); }
|
||||
function receiptAccounts() { return $this->relatedAccounts('receipts'); }
|
||||
function depositAccounts() { return $this->relatedAccounts('deposits'); }
|
||||
function refundAccounts() { return $this->relatedAccounts('refunds'); }
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: collectableAccounts
|
||||
* - Returns an array of accounts suitable to show income collection
|
||||
*/
|
||||
|
||||
function collectableAccounts() {
|
||||
$accounts = $this->receiptAccounts();
|
||||
|
||||
foreach(array($this->customerCreditAccountID(),
|
||||
$this->securityDepositAccountID(),
|
||||
$this->nsfAccountID(),
|
||||
$this->waiverAccountID(),
|
||||
$this->badDebtAccountID(),
|
||||
//$this->lookup('Closing'),
|
||||
//$this->lookup('Equity'),
|
||||
)
|
||||
AS $account_id) {
|
||||
$accounts[$account_id] = $this->name($account_id);
|
||||
}
|
||||
|
||||
$accounts['all'] = $accounts['default'] = $accounts;
|
||||
|
||||
foreach(array($this->concessionAccountID(),
|
||||
$this->waiverAccountID(),
|
||||
$this->badDebtAccountID(),
|
||||
)
|
||||
AS $account_id) {
|
||||
unset($accounts['default'][$account_id]);
|
||||
}
|
||||
|
||||
return $accounts;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: currentLedgerID
|
||||
* - Returns the current ledger ID of the account
|
||||
*/
|
||||
function currentLedgerID($id) {
|
||||
$this->cacheQueries = true;
|
||||
$item = $this->find('first', array
|
||||
('contain' => 'CurrentLedger',
|
||||
'conditions' => array('Account.id' => $id),
|
||||
));
|
||||
$this->cacheQueries = false;
|
||||
return $item['CurrentLedger']['id'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* 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: closeCurrentLedger
|
||||
* - Closes the current account ledger, and opens a new one
|
||||
* with the old balance carried forward.
|
||||
*/
|
||||
function closeCurrentLedgers($ids = null) {
|
||||
|
||||
$this->cacheQueries = true;
|
||||
$account = $this->find('all', array
|
||||
('contain' => array('CurrentLedger.id'),
|
||||
'fields' => array(),
|
||||
'conditions' => (empty($ids)
|
||||
? array()
|
||||
: array(array('Account.id' => $ids)))
|
||||
));
|
||||
$this->cacheQueries = false;
|
||||
//pr(compact('id', 'account'));
|
||||
|
||||
$ledger_ids = array();
|
||||
foreach ($account AS $acct)
|
||||
$ledger_ids[] = $acct['CurrentLedger']['id'];
|
||||
|
||||
return $this->Ledger->closeLedgers($ledger_ids);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: ledgerEntries
|
||||
* - Returns an array of ledger entries that belong to the given
|
||||
* account, either just from the current ledger, or from all ledgers.
|
||||
*/
|
||||
function ledgerEntries($id, $all = false, $cond = null, $link = null) {
|
||||
$ledgers = $this->ledgers($id, $all);
|
||||
return $this->Ledger->ledgerEntries($ledgers, $cond, $link);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns summary data from the requested account.
|
||||
*/
|
||||
|
||||
function stats($id = null, $all = false, $query = null) {
|
||||
if (!$id)
|
||||
return null;
|
||||
|
||||
$this->queryInit($query);
|
||||
$query['link'] = array('Account' => $query['link']);
|
||||
|
||||
$stats = array();
|
||||
foreach ($this->ledgers($id, $all) AS $ledger)
|
||||
$this->statsMerge($stats['Ledger'],
|
||||
$this->Ledger->stats($ledger, $query));
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,486 +0,0 @@
|
||||
<?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');
|
||||
|
||||
function pr($lev, $mixed) {
|
||||
if ($lev >= 3)
|
||||
return;
|
||||
|
||||
pr($mixed);
|
||||
return;
|
||||
|
||||
$trace = debug_backtrace(false);
|
||||
//array_shift($trace);
|
||||
$calls = array();
|
||||
foreach ($trace AS $call) {
|
||||
$call = array_intersect_key($call,
|
||||
array('file'=>1,
|
||||
'line'=>1,
|
||||
//'class'=>1,
|
||||
'function'=>1,
|
||||
));
|
||||
$calls[] = implode("; ", $call);
|
||||
}
|
||||
pr(array('debug' => $mixed, 'stack' => $calls));
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
if (!isset($query[$this->_key]))
|
||||
return $query;
|
||||
|
||||
if (!isset($query['fields']) || $query['fields'] === true) {
|
||||
$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));
|
||||
|
||||
$reference = array('class' => $Model->alias,
|
||||
'alias' => $Model->alias,
|
||||
);
|
||||
|
||||
$result = array_diff_key($query, array($this->_key => 1));
|
||||
$this->buildQuery($Model, $Model->alias, $Model->alias, $Model->findQueryType,
|
||||
$query[$this->_key], $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
function buildQuery(&$Reference, $referenceClass, $referenceAlias, $query_type, $links, &$result) {
|
||||
if (empty($links))
|
||||
return;
|
||||
|
||||
$this->pr(10,
|
||||
array('begin' => 'Linkable::buildQuery',
|
||||
'args' => compact('referenceClass', 'referenceAlias', 'query_type', 'links'),
|
||||
));
|
||||
|
||||
//$defaults = $this->_defaults;// + array($this->_key => array());
|
||||
//$optionsKeys = $this->_options + array($this->_key => true);
|
||||
|
||||
$links = Set::normalize($links);
|
||||
$this->pr(24,
|
||||
array('checkpoint' => 'Normalized links',
|
||||
compact('links'),
|
||||
));
|
||||
foreach ($links as $alias => $options) {
|
||||
if (is_null($options)) {
|
||||
$options = array();
|
||||
}
|
||||
//$options = array_intersect_key($options, $optionsKeys);
|
||||
//$options = am($this->_defaults, compact('alias'), $options);
|
||||
|
||||
$options += compact('alias');
|
||||
$options += $this->_defaults;
|
||||
|
||||
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;
|
||||
|
||||
if (!isset($options['conditions']))
|
||||
$options['conditions'] = null;
|
||||
elseif (!is_array($options['conditions']))
|
||||
$options['conditions'] = array($options['conditions']);
|
||||
|
||||
$this->pr(20,
|
||||
array('checkpoint' => 'Begin Model Work',
|
||||
compact('referenceAlias', 'alias', 'options'),
|
||||
));
|
||||
|
||||
$modelClass = $options['class'];
|
||||
$modelAlias = $options['alias'];
|
||||
$Model =& ClassRegistry::init($modelClass); // the incoming model to be linked in query
|
||||
|
||||
$this->pr(12,
|
||||
array('checkpoint' => 'Model Established',
|
||||
'Reference' => ($referenceAlias .' : '. $referenceClass .
|
||||
' ('. $Reference->alias .' : '. $Reference->name .')'),
|
||||
'Model' => ($modelAlias .' : '. $modelClass .
|
||||
' ('. $Model->alias .' : '. $Model->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])) {
|
||||
$this->pr(12, array('checkpoint' => "Reference ($referenceClass) defines association to Model ($modelClass)"));
|
||||
$associatedThroughReference = 1;
|
||||
$type = $associations[$Model->alias];
|
||||
$association = $Reference->{$type}[$Model->alias];
|
||||
}
|
||||
elseif (($associations = $Model->getAssociated()) &&
|
||||
isset($associations[$Reference->alias])) {
|
||||
$this->pr(12, array('checkpoint' => "Model ($modelClass) defines association to Reference ($referenceClass)"));
|
||||
$type = $associations[$Reference->alias];
|
||||
$association = $Model->{$type}[$Reference->alias];
|
||||
}
|
||||
else {
|
||||
// No relationship... make our best effort to create one.
|
||||
$this->pr(12, array('checkpoint' => "No assocation between Reference ($referenceClass) and Model ($modelClass)"));
|
||||
$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->pr(30,
|
||||
array('checkpoint' => 'Options/Association pre-merge',
|
||||
compact('association', 'options'),
|
||||
));
|
||||
|
||||
// A couple exceptions before performing a union of
|
||||
// options and association. Namely, most fields result
|
||||
// in either/or, but a couple should include BOTH the
|
||||
// options AND the association settings.
|
||||
foreach (array('fields', 'conditions') AS $fld) {
|
||||
$this->pr(31,
|
||||
array('checkpoint' => 'Options/Associations field original',
|
||||
compact('fld') +
|
||||
array("options[$fld]" =>
|
||||
array('value' => array_key_exists($fld, $options) ? (isset($options[$fld]) ? $options[$fld] : '-null-') : '-unset-',
|
||||
'type' => array_key_exists($fld, $options) ? (isset($options[$fld]) ? gettype($options[$fld]) : '-null-') : '-unset-'),
|
||||
"association[$fld]" =>
|
||||
array('value' => array_key_exists($fld, $association) ? (isset($association[$fld]) ? $association[$fld] : '-null-') : '-unset-',
|
||||
'type' => array_key_exists($fld, $association) ? (isset($association[$fld]) ? gettype($association[$fld]) : '-null-') : '-unset-'),
|
||||
)));
|
||||
|
||||
if (!isset($options[$fld]) ||
|
||||
(empty($options[$fld]) && !is_array($options[$fld])))
|
||||
unset($options[$fld]);
|
||||
elseif (!empty($options[$fld]) && !is_array($options[$fld]))
|
||||
$options[$fld] = array($options[$fld]);
|
||||
|
||||
if (!isset($association[$fld]) ||
|
||||
(empty($association[$fld]) && !is_array($association[$fld])))
|
||||
unset($association[$fld]);
|
||||
elseif (!empty($association[$fld]) && !is_array($association[$fld]))
|
||||
$association[$fld] = array($association[$fld]);
|
||||
|
||||
|
||||
$this->pr(31,
|
||||
array('checkpoint' => 'Options/Associations field normalize',
|
||||
compact('fld') +
|
||||
array("options[$fld]" =>
|
||||
array('value' => array_key_exists($fld, $options) ? (isset($options[$fld]) ? $options[$fld] : '-null-') : '-unset-',
|
||||
'type' => array_key_exists($fld, $options) ? (isset($options[$fld]) ? gettype($options[$fld]) : '-null-') : '-unset-'),
|
||||
"association[$fld]" =>
|
||||
array('value' => array_key_exists($fld, $association) ? (isset($association[$fld]) ? $association[$fld] : '-null-') : '-unset-',
|
||||
'type' => array_key_exists($fld, $association) ? (isset($association[$fld]) ? gettype($association[$fld]) : '-null-') : '-unset-'),
|
||||
)));
|
||||
|
||||
if (isset($options[$fld]) && isset($association[$fld]))
|
||||
$options[$fld] = array_merge($options[$fld],
|
||||
$association[$fld]);
|
||||
|
||||
$this->pr(31,
|
||||
array('checkpoint' => 'Options/Associations field merge complete',
|
||||
compact('fld') +
|
||||
array("options[$fld]" =>
|
||||
array('value' => array_key_exists($fld, $options) ? (isset($options[$fld]) ? $options[$fld] : '-null-') : '-unset-',
|
||||
'type' => array_key_exists($fld, $options) ? (isset($options[$fld]) ? gettype($options[$fld]) : '-null-') : '-unset-'),
|
||||
"association[$fld]" =>
|
||||
array('value' => array_key_exists($fld, $association) ? (isset($association[$fld]) ? $association[$fld] : '-null-') : '-unset-',
|
||||
'type' => array_key_exists($fld, $association) ? (isset($association[$fld]) ? gettype($association[$fld]) : '-null-') : '-unset-'),
|
||||
)));
|
||||
}
|
||||
|
||||
$this->pr(30,
|
||||
array('checkpoint' => 'Options/Association post-merge',
|
||||
compact('association', 'options'),
|
||||
));
|
||||
|
||||
// For any option that's not already set, use
|
||||
// whatever is specified by the assocation.
|
||||
$options += array_intersect_key($association, $this->_options);
|
||||
|
||||
// Replace all instances of the MODEL_ALIAS variable
|
||||
// tag with the correct model alias.
|
||||
$this->recursive_array_replace("%{MODEL_ALIAS}",
|
||||
$associationAlias,
|
||||
$options['conditions']);
|
||||
|
||||
$this->pr(15,
|
||||
array('checkpoint' => 'Models Established - Check Associations',
|
||||
'primaryModel' => $primaryAlias .' : '. $primaryModel->name,
|
||||
'foreignModel' => $foreignAlias .' : '. $foreignModel->name,
|
||||
compact('type', 'association', 'options'),
|
||||
));
|
||||
|
||||
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;
|
||||
|
||||
// foreignKey and associationForeignKey can refer to either
|
||||
// the model or the reference, depending on which class
|
||||
// actually defines the association. Make sure to we're
|
||||
// using the foreign keys to point to the right class.
|
||||
if ($associatedThroughReference) {
|
||||
$modelAFK = 'associationForeignKey';
|
||||
$referenceAFK = 'foreignKey';
|
||||
} else {
|
||||
$modelAFK = 'foreignKey';
|
||||
$referenceAFK = 'associationForeignKey';
|
||||
}
|
||||
|
||||
$this->pr(17,
|
||||
array('checkpoint' => 'Linking HABTM',
|
||||
compact('linkClass', 'linkAlias',
|
||||
'modelAFK', 'referenceAFK'),
|
||||
));
|
||||
|
||||
// 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[$modelAFK], $linkAlias);
|
||||
$referenceLink = $Link->escapeField($association[$referenceAFK], $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);
|
||||
|
||||
$this->pr(21,
|
||||
array('checkpoint' => 'HABTM links/keys',
|
||||
array(compact('modelLink', 'modelKey'),
|
||||
compact('referenceLink', 'referenceKey')),
|
||||
));
|
||||
|
||||
// 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);
|
||||
|
||||
$this->pr(17,
|
||||
array('checkpoint' => 'Linking due to foreignKey',
|
||||
compact('foreignKey', 'primaryKey'),
|
||||
));
|
||||
|
||||
// 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 {
|
||||
$this->pr(17,
|
||||
array('checkpoint' => 'Linking with no logic (expecting user defined)',
|
||||
));
|
||||
|
||||
// No Foreign Key... nothing we can do.
|
||||
}
|
||||
|
||||
$this->pr(19,
|
||||
array('checkpoint' => 'Conditions',
|
||||
array('options[conditions]' => $options['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']);
|
||||
|
||||
// When performing a count query, fields are useless.
|
||||
// For everything else, we need to add them into the set.
|
||||
if ($query_type !== 'count')
|
||||
$result['fields'] = array_merge($result['fields'], $options['fields']);
|
||||
|
||||
$result['joins'][] = array_intersect_key($options,
|
||||
array('type' => true,
|
||||
'alias' => true,
|
||||
'table' => true,
|
||||
'joins' => true,
|
||||
'conditions' => true));
|
||||
|
||||
$sublinks = array_diff_key($options, $this->_options);
|
||||
$this->buildQuery($Model, $modelClass, $modelAlias, $query_type, $sublinks, $result);
|
||||
|
||||
$this->pr(19,
|
||||
array('checkpoint' => 'Model Join Complete',
|
||||
compact('referenceAlias', 'modelAlias', 'options', 'result'),
|
||||
));
|
||||
}
|
||||
|
||||
$this->pr(20,
|
||||
array('return' => 'Linkable::buildQuery',
|
||||
compact('referenceAlias'),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
<?php
|
||||
class Contact extends AppModel {
|
||||
|
||||
var $displayField = 'display_name';
|
||||
|
||||
var $hasMany = array(
|
||||
'ContactsMethod',
|
||||
'ContactsCustomer',
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Customer',
|
||||
'ContactAddress' => array(
|
||||
'joinTable' => 'contacts_methods',
|
||||
'associationForeignKey' => 'method_id',
|
||||
'unique' => true,
|
||||
'conditions' => "method = 'ADDRESS'",
|
||||
),
|
||||
'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'",
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: saveContact
|
||||
* - Saves the contact and related data
|
||||
*/
|
||||
|
||||
function saveContact($id, $data) {
|
||||
|
||||
// Establish a display name if not already given
|
||||
if (!$data['Contact']['display_name'] &&
|
||||
$data['Contact']['first_name'] && $data['Contact']['last_name'])
|
||||
$data['Contact']['display_name'] =
|
||||
$data['Contact']['last_name'] . ', ' . $data['Contact']['first_name'];
|
||||
|
||||
foreach (array('last_name', 'first_name', 'company_name') AS $fld) {
|
||||
if (!$data['Contact']['display_name'] && $data['Contact'][$fld])
|
||||
$data['Contact']['display_name'] = $data['Contact'][$fld];
|
||||
}
|
||||
|
||||
// Save the contact data
|
||||
$this->create();
|
||||
if ($id)
|
||||
$this->id = $id;
|
||||
if (!$this->save($data, false)) {
|
||||
return false;
|
||||
}
|
||||
$id = $this->id;
|
||||
|
||||
// Remove all associated ContactMethods, as it ensures
|
||||
// any entries deleted by the user actually get deleted
|
||||
// in the system. We'll recreate the needed ones anyway.
|
||||
// REVISIT <AP>: 20090706
|
||||
// Appears that $this->save() is already doing the
|
||||
// delete. I would have thought this would only happen
|
||||
// on a saveAll??
|
||||
/* $this->ContactsMethod->deleteAll */
|
||||
/* (array('contact_id' => $id), false); */
|
||||
|
||||
// At this point, since we've saved data to contact,
|
||||
// we'll proceed forward as much as possible, even
|
||||
// if we encounter an error. For now, we'll assume
|
||||
// the operation will succeed.
|
||||
$ret = true;
|
||||
|
||||
// Iterate each type of contact method, adding them into
|
||||
// the database as needed and associating with this contact.
|
||||
foreach (array('phone', 'address', 'email') AS $type) {
|
||||
$class = 'Contact' . ucfirst($type);
|
||||
$enum = strtoupper($type);
|
||||
|
||||
// Nothing to do if this contact method isn't used
|
||||
if (!isset($data[$class]))
|
||||
continue;
|
||||
|
||||
// Go through each entry of this contact method
|
||||
foreach ($data[$class] AS &$item) {
|
||||
|
||||
// If the user has entered all new data, we need to
|
||||
// save that as a brand new entry.
|
||||
if (!isset($item['id']) || $item['source'] == 'new') {
|
||||
$I = new $class();
|
||||
$I->create();
|
||||
if (!$I->save($item, false)) {
|
||||
$ret = false;
|
||||
continue;
|
||||
}
|
||||
$item['id'] = $I->id;
|
||||
}
|
||||
|
||||
// Update the ContactsMethod to reflect the appropriate IDs
|
||||
$item['ContactsMethod']['contact_id'] = $id;
|
||||
$item['ContactsMethod']['method_id'] = $item['id'];
|
||||
$item['ContactsMethod']['method'] = $enum;
|
||||
|
||||
// Save the relationship between contact and phone/email/address
|
||||
$CM = new ContactsMethod();
|
||||
if (!$CM->save($item['ContactsMethod'], false)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function contactList() {
|
||||
return $this->find('list',
|
||||
array('order' =>
|
||||
//array('last_name', 'first_name', 'middle_name'),
|
||||
array('display_name'),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
class ContactAddress extends AppModel {
|
||||
|
||||
var $name = 'ContactAddress';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'postcode' => array('postal')
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'ContactsMethod' => array(
|
||||
'foreignKey' => 'method_id',
|
||||
'conditions' => "method = 'ADDRESS'",
|
||||
)
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Contact' => array(
|
||||
'className' => 'Contact',
|
||||
'joinTable' => 'contacts_methods',
|
||||
'foreignKey' => 'method_id',
|
||||
'associationForeignKey' => 'contact_id',
|
||||
'unique' => true,
|
||||
'conditions' => "method = 'ADDRESS'",
|
||||
)
|
||||
);
|
||||
|
||||
function addressList() {
|
||||
$results = $this->find('all',
|
||||
array('contain' => false,
|
||||
'fields' => array('id', 'address', 'city', 'state', 'postcode'),
|
||||
'order' => array('state', 'city', 'postcode', 'address')));
|
||||
|
||||
$list = array();
|
||||
foreach ($results as $key => $val) {
|
||||
$list[$val['ContactAddress']['id']]
|
||||
= preg_replace("/\n/", ", ", $val['ContactAddress']['address'])
|
||||
. ', ' . $val['ContactAddress']['city']
|
||||
. ', ' . $val['ContactAddress']['state']
|
||||
. ' ' . $val['ContactAddress']['postcode']
|
||||
;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
class ContactPhone extends AppModel {
|
||||
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
//'type' => array('inlist'),
|
||||
'phone' => array('phone'),
|
||||
'ext' => array('numeric')
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'ContactsMethod' => array(
|
||||
'foreignKey' => 'method_id',
|
||||
'conditions' => "method = 'PHONE'",
|
||||
)
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Contact' => array(
|
||||
'className' => 'Contact',
|
||||
'joinTable' => 'contacts_methods',
|
||||
'foreignKey' => 'method_id',
|
||||
'associationForeignKey' => 'contact_id',
|
||||
'unique' => true,
|
||||
'conditions' => "method = 'PHONE'",
|
||||
)
|
||||
);
|
||||
|
||||
function phoneList() {
|
||||
$results = $this->find('all',
|
||||
array('contain' => false,
|
||||
'fields' => array('id', 'phone', 'ext'),
|
||||
'order' => array('phone', 'ext')));
|
||||
|
||||
App::Import('Helper', 'Format');
|
||||
$list = array();
|
||||
foreach ($results as $key => $val) {
|
||||
$list[$val['ContactPhone']['id']]
|
||||
= FormatHelper::phone($val['ContactPhone']['phone'],
|
||||
$val['ContactPhone']['ext']);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
class ContactsCustomer extends AppModel {
|
||||
var $primaryKey = false;
|
||||
|
||||
var $belongsTo = array(
|
||||
'Contact',
|
||||
'Customer',
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
class ContactsMethod extends AppModel {
|
||||
var $primaryKey = false;
|
||||
|
||||
var $belongsTo = array(
|
||||
'Contact',
|
||||
'ContactAddress' => array(
|
||||
'foreignKey' => 'method_id',
|
||||
'conditions' => "method = 'ADDRESS'",
|
||||
//'unique' => true,
|
||||
),
|
||||
'ContactPhone' => array(
|
||||
'foreignKey' => 'method_id',
|
||||
'conditions' => "method = 'PHONE'",
|
||||
//'unique' => true,
|
||||
),
|
||||
'ContactEmail' => array(
|
||||
'foreignKey' => 'method_id',
|
||||
'conditions' => "method = 'EMAIL'",
|
||||
//'unique' => true,
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,506 +0,0 @@
|
||||
<?php
|
||||
class Customer extends AppModel {
|
||||
|
||||
var $name = 'Customer';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
);
|
||||
|
||||
var $belongsTo = array(
|
||||
'PrimaryContact' => array(
|
||||
'className' => 'Contact',
|
||||
),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'CurrentLease' => array(
|
||||
'className' => 'Lease',
|
||||
'conditions' => 'CurrentLease.close_date IS NULL',
|
||||
),
|
||||
'Lease',
|
||||
'StatementEntry',
|
||||
'ContactsCustomer' => array(
|
||||
// It would be nice to claim a dependency here, which would
|
||||
// simplify deletion of a customer. However, for this to work
|
||||
// Cake must have a primaryKey as a single field. This table
|
||||
// makes use of a complex key, so we're out of luck.
|
||||
/* 'dependent' => true, */
|
||||
),
|
||||
|
||||
'Transaction',
|
||||
'Tender',
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Contact' => array(
|
||||
'unique' => true,
|
||||
),
|
||||
);
|
||||
|
||||
//var $default_log_level = 20;
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: accountId
|
||||
* - Returns the account ID for the given customer
|
||||
*/
|
||||
function accountId($id) {
|
||||
$this->cacheQueries = true;
|
||||
$customer = $this->find('first',
|
||||
array('contain' => false,
|
||||
'fields' => array('account_id'),
|
||||
'conditions' => array(array('Customer.id' => $id))));
|
||||
$this->cacheQueries = false;
|
||||
|
||||
return $customer['Customer']['account_id'];
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: leaseIds
|
||||
* - Returns the lease IDs for the given customer
|
||||
*/
|
||||
function leaseIds($id, $current = false) {
|
||||
$Lease = $current ? 'CurrentLease' : 'Lease';
|
||||
|
||||
$this->cacheQueries = true;
|
||||
$customer = $this->find('first',
|
||||
array('contain' =>
|
||||
array($Lease => array('fields' => array('id'))),
|
||||
'fields' => array(),
|
||||
'conditions' => array(array('Customer.id' => $id))));
|
||||
$this->cacheQueries = false;
|
||||
|
||||
$ids = array();
|
||||
foreach ($customer[$Lease] AS $lease)
|
||||
$ids[] = $lease['id'];
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: securityDeposits
|
||||
* - Returns an array of security deposit entries
|
||||
*/
|
||||
function securityDeposits($id, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||
$this->StatementEntry->Account->securityDepositAccountID());
|
||||
|
||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
||||
return $this->prReturn($set);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: securityDepositBalance
|
||||
* - Returns the balance of the customer security deposit(s)
|
||||
*/
|
||||
|
||||
function securityDepositBalance($id, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
$sd_account_id =
|
||||
$this->StatementEntry->Account->securityDepositAccountID();
|
||||
|
||||
$squery = $query;
|
||||
$squery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$squery['conditions'][] = array('StatementEntry.account_id' => $sd_account_id);
|
||||
$stats = $this->StatementEntry->stats(null, $squery);
|
||||
$this->pr(26, compact('squery', 'stats'));
|
||||
|
||||
// OK, we know now how much we charged for a security
|
||||
// deposit, as well as how much we received to pay for it.
|
||||
// Now we need to know if any has been released.
|
||||
// Yes... this sucks.
|
||||
$lquery = $query;
|
||||
$lquery['link'] = array('Transaction' =>
|
||||
array('fields' => array(),
|
||||
'Customer' =>
|
||||
(empty($query['link'])
|
||||
? array('fields' => array())
|
||||
: $query['link'])));
|
||||
$lquery['conditions'][] = array('Transaction.customer_id' => $id);
|
||||
$lquery['conditions'][] = array('LedgerEntry.account_id' => $sd_account_id);
|
||||
$lquery['conditions'][] = array('LedgerEntry.crdr' => 'DEBIT');
|
||||
$lquery['fields'][] = 'SUM(LedgerEntry.amount) AS total';
|
||||
$released = $this->StatementEntry->Transaction->LedgerEntry->find
|
||||
('first', $lquery);
|
||||
$this->pr(26, compact('lquery', 'released'));
|
||||
|
||||
return $this->prReturn($stats['Charge']['disbursement'] - $released[0]['total']);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: unreconciledCharges
|
||||
* - Returns charges have not yet been fully paid
|
||||
*/
|
||||
|
||||
function unreconciledCharges($id, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
|
||||
return $this->prReturn($set);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: saveCustomer
|
||||
* - Saves the customer and related data
|
||||
*/
|
||||
|
||||
function saveCustomer($id, $data, $primary_contact_entry) {
|
||||
|
||||
// Go through each contact, and create new ones as needed
|
||||
foreach ($data['Contact'] AS &$contact) {
|
||||
if (isset($contact['id']))
|
||||
continue;
|
||||
|
||||
$I = new Contact();
|
||||
if (!$I->saveContact(null, array('Contact' => $contact)))
|
||||
return false;
|
||||
$contact['id'] = $I->id;
|
||||
}
|
||||
|
||||
// Set the primary contact ID based on caller selection
|
||||
$data['Customer']['primary_contact_id']
|
||||
= $data['Contact'][$primary_contact_entry]['id'];
|
||||
|
||||
// Provide a default customer name if not specified
|
||||
if (!$data['Customer']['name']) {
|
||||
$this->Contact->recursive = -1;
|
||||
$pcontact = $this->Contact->read(null, $data['Customer']['primary_contact_id']);
|
||||
$data['Customer']['name'] = $pcontact['Contact']['display_name'];
|
||||
}
|
||||
|
||||
// Save the customer data
|
||||
$this->create();
|
||||
if ($id)
|
||||
$this->id = $id;
|
||||
if (!$this->save($data, false)) {
|
||||
return false;
|
||||
}
|
||||
$id = $this->id;
|
||||
|
||||
// Appears that $this->save() "helpfully" choses to add in
|
||||
// any missing data fields, populated with default values.
|
||||
// So, after saving is complete, the fields 'lease_count',
|
||||
// 'past_lease_count', and 'current_lease_count' have all
|
||||
// been reset to zero. Gee, thanks Cake...
|
||||
$this->update($id);
|
||||
|
||||
// Remove all associated Customer Contacts, as it ensures
|
||||
// any entries deleted by the user actually get deleted
|
||||
// in the system. We'll recreate the needed ones anyway.
|
||||
// REVISIT <AP>: 20090706
|
||||
// Appears that $this->save() is already doing the
|
||||
// delete. I would have thought this would only happen
|
||||
// on a saveAll??
|
||||
/* $this->ContactsCustomer->deleteAll */
|
||||
/* (array('customer_id' => $id), false); */
|
||||
|
||||
// At this point, since we've saved data to customer,
|
||||
// we'll proceed forward as much as possible, even
|
||||
// if we encounter an error. For now, we'll assume
|
||||
// the operation will succeed.
|
||||
$ret = true;
|
||||
|
||||
// Go through each entry of this customer method
|
||||
foreach ($data['Contact'] AS &$contact) {
|
||||
// Update the ContactsCustomer to reflect the appropriate IDs
|
||||
$contact['ContactsCustomer']['customer_id'] = $id;
|
||||
$contact['ContactsCustomer']['contact_id'] = $contact['id'];
|
||||
|
||||
// Save the relationship between customer and contact
|
||||
$CM = new ContactsCustomer();
|
||||
if (!$CM->save($contact['ContactsCustomer'], false)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the result
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: update
|
||||
* - Update any cached or calculated fields
|
||||
*/
|
||||
function update($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
if (empty($id)) {
|
||||
$customers = $this->find('all', array('contain' => false, 'fields' => array('id')));
|
||||
foreach ($customers AS $customer) {
|
||||
// This SHOULDN'T happen, but check to be sure
|
||||
// or we'll get infinite recursion.
|
||||
if (empty($customer['Customer']['id']))
|
||||
continue;
|
||||
$this->update($customer['Customer']['id']);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// updateLeaseCount is typically handled directly when needed.
|
||||
// However, this function is used to _ensure_ customer info is
|
||||
// current, so we're obligated to call it anyway.
|
||||
$this->updateLeaseCount($id);
|
||||
|
||||
$current_leases =
|
||||
$this->find('all',
|
||||
// REVISIT <AP>: 20090816
|
||||
// Do we need to update leases other than the current ones?
|
||||
// It may be necessary. For example, a non-current lease
|
||||
// can still be hit with an NSF item. In that case, it
|
||||
// could have stale data if we look only to current leases.
|
||||
//array('link' => array('CurrentLease' => array('type' => 'INNER')),
|
||||
array('link' => array('Lease' => array('type' => 'INNER')),
|
||||
'conditions' => array('Customer.id' => $id)));
|
||||
|
||||
foreach ($current_leases AS $lease) {
|
||||
if (!empty($lease['CurrentLease']['id']))
|
||||
$this->Lease->update($lease['CurrentLease']['id']);
|
||||
if (!empty($lease['Lease']['id']))
|
||||
$this->Lease->update($lease['Lease']['id']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: merge
|
||||
* - Merges two customers into one
|
||||
*/
|
||||
|
||||
function merge($dst_id, $src_id, $contacts) {
|
||||
$this->prEnter(compact('dst_id', 'src_id', 'contacts'));
|
||||
|
||||
// Get the entire list of destination customer contacts
|
||||
$dst_contacts = array();
|
||||
$result = $this->find('all',
|
||||
array('link' => array('ContactsCustomer'),
|
||||
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
|
||||
'conditions' => array(array('id' => $dst_id,
|
||||
'ContactsCustomer.active' => true))));
|
||||
foreach ($result AS $contact) {
|
||||
$dst_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
|
||||
}
|
||||
$this->pr(17, compact('dst_contacts'));
|
||||
|
||||
// Get the entire list of source customer contacts
|
||||
$src_contacts = array();
|
||||
$result = $this->find('all',
|
||||
array('link' => array('ContactsCustomer'),
|
||||
'fields' => array('ContactsCustomer.contact_id', 'ContactsCustomer.type'),
|
||||
'conditions' => array(array('id' => $src_id,
|
||||
'ContactsCustomer.active' => true))));
|
||||
foreach ($result AS $contact) {
|
||||
$src_contacts[$contact['ContactsCustomer']['contact_id']] = $contact['ContactsCustomer'];
|
||||
}
|
||||
$this->pr(17, compact('src_contacts'));
|
||||
|
||||
// Verify the contacts list are all valid source customer contacts
|
||||
foreach ($contacts AS $contact_id) {
|
||||
if (!array_key_exists($contact_id, $src_contacts))
|
||||
return $this->prReturn(false);
|
||||
}
|
||||
|
||||
// Remove any contacts which are already destination customer contacts
|
||||
$new_contacts = array_diff($contacts, array_keys($dst_contacts));
|
||||
$all_contacts = array_merge($new_contacts, array_keys($dst_contacts));
|
||||
$this->pr(17, compact('new_contacts', 'all_contacts'));
|
||||
|
||||
// For now, we'll assume the operation will succeed.
|
||||
$ret = true;
|
||||
|
||||
// Add each desired source customer contact to the destination customer
|
||||
foreach ($new_contacts AS $contact_id) {
|
||||
$CM = new ContactsCustomer();
|
||||
if (!$CM->save(array('customer_id' => $dst_id)
|
||||
+ $src_contacts[$contact_id], false)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->Lease->updateAll
|
||||
(array('Lease.customer_id' => $dst_id),
|
||||
array('Lease.customer_id' => $src_id)
|
||||
);
|
||||
|
||||
$this->Tender->updateAll
|
||||
(array('Tender.customer_id' => $dst_id),
|
||||
array('Tender.customer_id' => $src_id)
|
||||
);
|
||||
|
||||
$this->StatementEntry->updateAll
|
||||
(array('StatementEntry.customer_id' => $dst_id),
|
||||
array('StatementEntry.customer_id' => $src_id)
|
||||
);
|
||||
|
||||
$this->Transaction->updateAll
|
||||
(array('Transaction.customer_id' => $dst_id),
|
||||
array('Transaction.customer_id' => $src_id)
|
||||
);
|
||||
|
||||
// Make sure our lease counts, etc are correct
|
||||
$this->update($dst_id);
|
||||
|
||||
// Delete the old customer
|
||||
$this->pr(12, compact('src_id'), "Delete Customer");
|
||||
$this->delete($src_id);
|
||||
|
||||
// Delete all the orphaned customers
|
||||
foreach (array_diff(array_keys($src_contacts), $all_contacts) AS $contact_id) {
|
||||
// Delete un-used or duplicate contacts
|
||||
// REVISIT <AP> 20100702:
|
||||
// Not sure if we really want to do this.
|
||||
// On the one hand, they're probably really redundant,
|
||||
// and only clutter up the list of all contacts. On the
|
||||
// other hand, it destroys data, not only losing the
|
||||
// history, but making it difficult to recover if the
|
||||
// merge is a mistake. Additionally, we need to do
|
||||
// extra checking to ensure that the contact is not
|
||||
// in use by some other customer.
|
||||
// We need some sort of Contact.deleted field...
|
||||
$this->pr(12, compact('contact_id'), "Delete Contact");
|
||||
$this->Contact->delete($contact_id);
|
||||
}
|
||||
|
||||
// Finally, delete all customer contact relationships
|
||||
$this->ContactsCustomer->deleteAll
|
||||
(array('customer_id' => $src_id), false);
|
||||
|
||||
// Return the result
|
||||
return $this->prReturn($ret);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: updateLeaseCount
|
||||
* - Updates the internal lease count
|
||||
*/
|
||||
|
||||
function updateLeaseCount($id) {
|
||||
$this->id = $id;
|
||||
|
||||
$lease_count =
|
||||
$this->find('count',
|
||||
array('link' => array('Lease' => array('type' => 'INNER')),
|
||||
'conditions' => array('Customer.id' => $id)));
|
||||
$current_count =
|
||||
$this->find('count',
|
||||
array('link' => array('CurrentLease' => array('type' => 'INNER')),
|
||||
'conditions' => array('Customer.id' => $id)));
|
||||
|
||||
$this->saveField('lease_count', $lease_count);
|
||||
$this->saveField('current_lease_count', $current_count);
|
||||
$this->saveField('past_lease_count', $lease_count - $current_count);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: balance
|
||||
* - Returns the balance of money owed on the lease
|
||||
*/
|
||||
|
||||
function balance($id) {
|
||||
$stats = $this->stats($id);
|
||||
return $stats['balance'];
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns summary data from the requested customer.
|
||||
*/
|
||||
|
||||
function stats($id = null, $query = null) {
|
||||
//$this->prFunctionLevel(20);
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
if (!$id)
|
||||
return $this->prExit(null);
|
||||
|
||||
$this->queryInit($query);
|
||||
|
||||
// REVISIT <AP>: 20090725
|
||||
// We'll need to go directly to the statement entries if
|
||||
// transactions are not always associated with the customer.
|
||||
// This could happen if either we remove the customer_id
|
||||
// field from Transaction, or we allow multiple customers
|
||||
// to be part of the same transaction (essentially making
|
||||
// the Transaction.customer_id meaningless).
|
||||
|
||||
/* $stats = $this->StatementEntry->find */
|
||||
/* ('first', array */
|
||||
/* ('contain' => false, */
|
||||
/* 'fields' => $this->StatementEntry->chargeDisbursementFields(true), */
|
||||
/* 'conditions' => array('StatementEntry.customer_id' => $id), */
|
||||
/* )); */
|
||||
|
||||
$find_stats = $this->StatementEntry->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
'fields' => $this->StatementEntry->chargeDisbursementFields(true),
|
||||
'conditions' => array('StatementEntry.customer_id' => $id),
|
||||
));
|
||||
$find_stats = $find_stats[0];
|
||||
$this->pr(17, compact('find_stats'));
|
||||
|
||||
$tquery = $query;
|
||||
$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$statement_stats = $this->StatementEntry->stats(null, $tquery);
|
||||
$statement_stats['balance'] = $statement_stats['Charge']['balance'];
|
||||
$this->pr(17, compact('statement_stats'));
|
||||
|
||||
$tquery = $query;
|
||||
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
||||
$transaction_stats = $this->Transaction->stats(null, $tquery);
|
||||
$transaction_stats += $transaction_stats['StatementEntry'];
|
||||
$this->pr(17, compact('transaction_stats'));
|
||||
|
||||
$tquery = $query;
|
||||
//$tquery['conditions'][] = array('StatementEntry.customer_id' => $id);
|
||||
$tquery['conditions'][] = array('Transaction.customer_id' => $id);
|
||||
$ar_transaction_stats = $this->Transaction->stats(null, $tquery,
|
||||
$this->Transaction->Account->accountReceivableAccountID());
|
||||
$ar_transaction_stats += $ar_transaction_stats['LedgerEntry'];
|
||||
$this->pr(17, compact('ar_transaction_stats'));
|
||||
|
||||
//$stats = $ar_transaction_stats;
|
||||
$stats = $find_stats;
|
||||
return $this->prReturn($stats);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
class DefaultOption extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('OptionValue',
|
||||
);
|
||||
|
||||
|
||||
function values($name = null) {
|
||||
$this->prEnter(compact('name'));
|
||||
|
||||
$query = array();
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['DefaultOption'] = array();
|
||||
$query['link']['DefaultOption']['type'] = 'INNER';
|
||||
$query['link']['DefaultOption']['fields'] = array();
|
||||
return $this->prReturn($this->OptionValue->values($name, $query));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
class DefaultPermission extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('PermissionValue',
|
||||
);
|
||||
|
||||
|
||||
function values($name = null) {
|
||||
$this->prEnter(compact('name'));
|
||||
|
||||
$query = array();
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['DefaultPermission'] = array();
|
||||
$query['link']['DefaultPermission']['type'] = 'INNER';
|
||||
$query['link']['DefaultPermission']['fields'] = array();
|
||||
return $this->prReturn($this->PermissionValue->values($name, $query));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
class DoubleEntry extends AppModel {
|
||||
|
||||
var $belongsTo = array(
|
||||
'DebitEntry' => array(
|
||||
'className' => 'LedgerEntry',
|
||||
),
|
||||
'CreditEntry' => array(
|
||||
'className' => 'LedgerEntry',
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: verifyDoubleEntry
|
||||
* - Verifies consistenty of new double entry data
|
||||
* (not in a pre-existing double entry)
|
||||
*/
|
||||
function verifyDoubleEntry($entry1, $entry2, $entry1_tender = null) {
|
||||
/* pr(array("DoubleEntry::verifyDoubleEntry()" */
|
||||
/* => compact('entry1', 'entry2', 'entry1_tender'))); */
|
||||
|
||||
$LE = new LedgerEntry();
|
||||
if (!$LE->verifyLedgerEntry($entry1, $entry1_tender)) {
|
||||
/* pr(array("DoubleEntry::verifyDoubleEntry()" */
|
||||
/* => "Entry1 verification failed")); */
|
||||
return false;
|
||||
}
|
||||
if (!$LE->verifyLedgerEntry($entry2)) {
|
||||
/* pr(array("DoubleEntry::verifyDoubleEntry()" */
|
||||
/* => "Entry2 verification failed")); */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(($entry1['crdr'] === 'DEBIT' && $entry2['crdr'] === 'CREDIT') ||
|
||||
($entry1['crdr'] === 'CREDIT' && $entry2['crdr'] === 'DEBIT')) ||
|
||||
($entry1['amount'] != $entry2['amount'])) {
|
||||
/* pr(array("DoubleEntry::verifyDoubleEntry()" */
|
||||
/* => "Double Entry verification failed")); */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: addDoubleEntry
|
||||
* - Inserts new Double Entry into the database
|
||||
*/
|
||||
|
||||
function addDoubleEntry($entry1, $entry2, $entry1_tender = null) {
|
||||
//$this->prFunctionLevel(16);
|
||||
$this->prEnter(compact('entry1', 'entry2', 'entry1_tender'));
|
||||
|
||||
$ret = array();
|
||||
if (!$this->verifyDoubleEntry($entry1, $entry2, $entry1_tender))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
// Handle the case where a double entry involves the same
|
||||
// exact ledger. This would not serve any useful purpose.
|
||||
// It is not, however, an error. It is semantically correct
|
||||
// just not really logically correct. To make this easier,
|
||||
// just ensure ledger_id is set for each entry, even though
|
||||
// it would be handled later by the LedgerEntry model.
|
||||
//array($entry1, $entry2) AS &$entry) {
|
||||
for ($i=1; $i <= 2; ++$i) {
|
||||
if (empty(${'entry'.$i}['ledger_id']))
|
||||
${'entry'.$i}['ledger_id'] =
|
||||
$this->DebitEntry->Account->currentLedgerID(${'entry'.$i}['account_id']);
|
||||
}
|
||||
if ($entry1['ledger_id'] == $entry2['ledger_id'])
|
||||
return $this->prReturn(array('error' => false));
|
||||
|
||||
// Since this model only relates to DebitEntry and CreditEntry...
|
||||
$LE = new LedgerEntry();
|
||||
|
||||
// Add the first ledger entry to the database
|
||||
$result = $LE->addLedgerEntry($entry1, $entry1_tender);
|
||||
$ret['Entry1'] = $result;
|
||||
if ($result['error'])
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
// Add the second ledger entry to the database
|
||||
$result = $LE->addLedgerEntry($entry2);
|
||||
$ret['Entry2'] = $result;
|
||||
if ($result['error'])
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
// Now link them as a double entry
|
||||
$double_entry = array();
|
||||
$double_entry['debit_entry_id'] =
|
||||
($entry1['crdr'] === 'DEBIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
|
||||
$double_entry['credit_entry_id'] =
|
||||
($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
|
||||
|
||||
$ret['data'] = $double_entry;
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($double_entry))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
$ret['double_entry_id'] = $this->id;
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
class Group extends AppModel {
|
||||
|
||||
var $hasMany =
|
||||
array('GroupOption',
|
||||
'Membership',
|
||||
);
|
||||
|
||||
var $knows =
|
||||
array('User',
|
||||
'Site',
|
||||
);
|
||||
|
||||
static $current_group_ids;
|
||||
function currentGroupIds() {
|
||||
if (empty(self::$current_group_ids))
|
||||
self::$current_group_ids = $this->groupIds();
|
||||
|
||||
if (empty(self::$current_group_ids))
|
||||
// We must force a stop here, since this is typically
|
||||
// called very early on, and so will cause a recursive
|
||||
// crash as we try to render the internal error and
|
||||
// again stumble on this problem.
|
||||
$this->INTERNAL_ERROR('INVALID MEMBERSHIP', 0, true);
|
||||
|
||||
return self::$current_group_ids;
|
||||
}
|
||||
|
||||
function groupIds($user_id = null, $site_id = null) {
|
||||
if (empty($user_id))
|
||||
$user_id = $this->User->currentUserId();
|
||||
if (empty($site_id))
|
||||
$site_id = $this->Site->currentSiteId();
|
||||
|
||||
return $this->Membership->memberGroups($user_id, $site_id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
class GroupOption extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('Group',
|
||||
'OptionValue',
|
||||
);
|
||||
|
||||
|
||||
function values($ids, $name = null) {
|
||||
$this->prEnter(compact('id', 'name'));
|
||||
|
||||
$query = array();
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['GroupOption'] = array();
|
||||
$query['link']['GroupOption']['fields'] = array();
|
||||
$query['link']['GroupOption']['Group'] = array();
|
||||
$query['link']['GroupOption']['Group']['fields'] = array();
|
||||
$query['conditions'][] = array('Group.id' => $ids);
|
||||
$query['order'][] = 'Group.rank';
|
||||
return $this->prReturn($this->OptionValue->values($name, $query));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
class GroupPermission extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('Group',
|
||||
'PermissionValue',
|
||||
);
|
||||
|
||||
|
||||
function values($ids, $name = null) {
|
||||
$this->prEnter(compact('id', 'name'));
|
||||
|
||||
$query = array();
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['GroupPermission'] = array();
|
||||
$query['link']['GroupPermission']['fields'] = array();
|
||||
$query['link']['GroupPermission']['Group'] = array();
|
||||
$query['link']['GroupPermission']['Group']['fields'] = array();
|
||||
$query['conditions'][] = array('Group.id' => $ids);
|
||||
$query['order'][] = 'Group.rank';
|
||||
return $this->prReturn($this->PermissionValue->values($name, $query));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,900 +0,0 @@
|
||||
<?php
|
||||
class Lease extends AppModel {
|
||||
|
||||
var $belongsTo = array(
|
||||
'LeaseType',
|
||||
'Unit',
|
||||
'Customer',
|
||||
'LateSchedule',
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'StatementEntry',
|
||||
);
|
||||
|
||||
//var $default_log_level = array('log' => 30, 'show' => 30);
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: securityDeposits
|
||||
* - Returns an array of security deposit entries
|
||||
*/
|
||||
function securityDeposits($id, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||
$this->StatementEntry->Account->securityDepositAccountID());
|
||||
|
||||
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, false, true);
|
||||
return $this->prReturn($set);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: securityDepositBalance
|
||||
* - Returns the balance of the lease security deposit(s)
|
||||
*/
|
||||
|
||||
function securityDepositBalance($id, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
// REVISIT <AP>: 20090807
|
||||
// Let's try simplifying the security deposit issue.
|
||||
// Presume that security deposits are NOT used at all,
|
||||
// until the customer moves out of the unit. At that
|
||||
// time, the ENTIRE deposit is converted to customer
|
||||
// credit. Piece of cake.
|
||||
// For more information, see file revision history,
|
||||
// including the revision just before this, r503.
|
||||
|
||||
$this->id = $id;
|
||||
$moveout_date = $this->field('moveout_date');
|
||||
if (!empty($moveout_date))
|
||||
return $this->prReturn(0);
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.lease_id' => $id);
|
||||
$query['conditions'][] = array('StatementEntry.account_id' =>
|
||||
$this->StatementEntry->Account->securityDepositAccountID());
|
||||
|
||||
$stats = $this->StatementEntry->stats(null, $query);
|
||||
return $this->prReturn($stats['Charge']['disbursement']);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: releaseSecurityDeposits
|
||||
* - Releases all security deposits associated with this lease.
|
||||
* That simply makes a disbursement out of them, which can be used
|
||||
* to pay outstanding customer charges, or simply to become
|
||||
* a customer surplus (customer credit).
|
||||
*/
|
||||
function releaseSecurityDeposits($id, $stamp = null, $query = null) {
|
||||
//$this->prFunctionLevel(30);
|
||||
$this->prEnter(compact('id', 'stamp', 'query'));
|
||||
|
||||
$secdeps = $this->securityDeposits($id, $query);
|
||||
$secdeps = $secdeps['entries'];
|
||||
$this->pr(20, compact('secdeps'));
|
||||
|
||||
// If there are no paid security deposits, then
|
||||
// we can consider all security deposits released.
|
||||
if (count($secdeps) == 0)
|
||||
return $this->prReturn(true);
|
||||
|
||||
// Build a transaction
|
||||
$release = array('Transaction' => array(), 'Entry' => array());
|
||||
$release['Transaction']['stamp'] = $stamp;
|
||||
$release['Transaction']['comment'] = "Security Deposit Release";
|
||||
foreach ($secdeps AS $charge) {
|
||||
if ($charge['StatementEntry']['type'] !== 'CHARGE')
|
||||
die("INTERNAL ERROR: SECURITY DEPOSIT IS NOT CHARGE");
|
||||
|
||||
// Since security deposits are being released, this also means
|
||||
// any unpaid (or only partially paid) security deposit should
|
||||
// have the remaining balance reversed.
|
||||
if ($charge['StatementEntry']['balance'] > 0)
|
||||
$this->StatementEntry->reverse($charge['StatementEntry']['id'], true, $stamp);
|
||||
|
||||
$release['Entry'][] =
|
||||
array('amount' => $charge['StatementEntry']['reconciled'],
|
||||
'account_id' => $this->StatementEntry->Account->securityDepositAccountID(),
|
||||
'comment' => "Released Security Deposit",
|
||||
);
|
||||
}
|
||||
|
||||
$customer_id = $secdeps[0]['StatementEntry']['customer_id'];
|
||||
$lease_id = $secdeps[0]['StatementEntry']['lease_id'];
|
||||
|
||||
// Add receipt of the security deposit funds. Do NOT
|
||||
// flag them as part of the lease, as all received funds
|
||||
// are only associated with the customer, for future
|
||||
// (or present) disbursement on any lease.
|
||||
$result = $this->StatementEntry->Transaction->addReceipt
|
||||
($release, $customer_id, null);
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: rentLastCharges
|
||||
* - Returns a list of rent charges from this lease that
|
||||
* do not have sequential followup charges. Under normal
|
||||
* circumstances, there would only be one entry, which is
|
||||
* the most recent rent charge. However, it's possible
|
||||
* that there are several, indicating a problem with lease.
|
||||
*/
|
||||
|
||||
function rentLastCharges($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
|
||||
$entries = $this->find
|
||||
('all',
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'StatementEntry',
|
||||
|
||||
'SEx' =>
|
||||
array('class' => 'StatementEntry',
|
||||
'fields' => array(),
|
||||
'conditions' => array
|
||||
('SEx.lease_id = StatementEntry.lease_id',
|
||||
'SEx.type' => 'CHARGE',
|
||||
'SEx.account_id' => $rent_account_id,
|
||||
'SEx.reverse_transaction_id IS NULL',
|
||||
'SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
||||
'fields' => array(),
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
array('StatementEntry.type' => 'CHARGE'),
|
||||
array('StatementEntry.account_id' => $rent_account_id),
|
||||
array('StatementEntry.reverse_transaction_id IS NULL'),
|
||||
array('SEx.id' => null),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
return $this->prReturn($entries);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: lateCharges
|
||||
* - Returns a list of late charges from this lease
|
||||
*/
|
||||
|
||||
function lateCharges($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$late_account_id = $this->StatementEntry->Account->lateChargeAccountID();
|
||||
$entries = $this->StatementEntry->find
|
||||
('all',
|
||||
array('link' =>
|
||||
array(// Models
|
||||
'Lease',
|
||||
),
|
||||
|
||||
//'fields' => array('id', 'amount', 'effective_date', 'through_date'),
|
||||
'conditions' => array(array('Lease.id' => $id),
|
||||
array('StatementEntry.type' => 'CHARGE'),
|
||||
array('StatementEntry.account_id' => $late_account_id),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
return $this->prReturn($entries);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: rentChargeGaps
|
||||
* - Checks for gaps in rent charges
|
||||
*/
|
||||
|
||||
function rentChargeGaps($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$entries = $this->rentLastCharges($id);
|
||||
if ($entries && count($entries) > 1)
|
||||
return $this->prReturn(true);
|
||||
return $this->prReturn(false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: rentChargeThrough
|
||||
* - Determines the date that rent has been charged through
|
||||
* Returns one of:
|
||||
* null: There are gaps in the charges
|
||||
* false: There are not yet any charges
|
||||
* date: The date rent has been charged through
|
||||
*/
|
||||
|
||||
function rentChargeThrough($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$entries = $this->rentLastCharges($id);
|
||||
if (!$entries)
|
||||
return $this->prReturn(false);
|
||||
if (count($entries) != 1)
|
||||
return $this->prReturn(null);
|
||||
return $this->prReturn($entries[0]['StatementEntry']['through_date']);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: rentPaidThrough
|
||||
* - Determines the date of the first unpaid rent
|
||||
*/
|
||||
|
||||
function rentPaidThrough($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$rent_account_id = $this->StatementEntry->Account->rentAccountID();
|
||||
|
||||
// First, see if we can find any unpaid entries. Of course,
|
||||
// the first unpaid entry gives us a very direct indication
|
||||
// of when the customer is paid up through, which is 1 day
|
||||
// prior to the effective date of that first unpaid charge.
|
||||
$rent = $this->StatementEntry->reconciledSet
|
||||
('CHARGE',
|
||||
array('fields' =>
|
||||
array('StatementEntry.*',
|
||||
'DATE_SUB(StatementEntry.effective_date, INTERVAL 1 DAY) AS paid_through',
|
||||
),
|
||||
|
||||
'conditions' =>
|
||||
array(array('StatementEntry.lease_id' => $id),
|
||||
array('StatementEntry.account_id' => $rent_account_id),
|
||||
array('StatementEntry.reverse_transaction_id IS NULL'),
|
||||
),
|
||||
|
||||
'order' => array('StatementEntry.effective_date'),
|
||||
),
|
||||
true);
|
||||
$this->pr(20, $rent, "Unpaid rent");
|
||||
|
||||
if ($rent['entries'])
|
||||
return $this->prReturn($rent['entries'][0]['StatementEntry']['paid_through']);
|
||||
|
||||
|
||||
// If we don't have any unpaid charges (great!), then the
|
||||
// customer is paid up through the last day of the last
|
||||
// charge. So, search for paid charges, which already
|
||||
// have the paid through date saved as part of the entry.
|
||||
$rent = $this->StatementEntry->reconciledSet
|
||||
('CHARGE',
|
||||
array('conditions' =>
|
||||
array(array('StatementEntry.lease_id' => $id),
|
||||
array('StatementEntry.account_id' => $rent_account_id),
|
||||
array('StatementEntry.reverse_transaction_id IS NULL'),
|
||||
),
|
||||
|
||||
'order' => array('StatementEntry.through_date DESC'),
|
||||
),
|
||||
false);
|
||||
$this->pr(20, $rent, "Paid rent");
|
||||
|
||||
if ($rent['entries'])
|
||||
return $this->prReturn($rent['entries'][0]['StatementEntry']['through_date']);
|
||||
|
||||
|
||||
// After all that, having found that there are no unpaid
|
||||
// charges, and in fact, no paid charges either, we cannot
|
||||
// possibly say when the customer is paid through.
|
||||
return $this->prReturn(null);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyRent
|
||||
* - Charges rent for the month, if not already charged.
|
||||
*/
|
||||
|
||||
function assessMonthlyRent($id, $date = null) {
|
||||
$this->prEnter(compact('id', 'date'));
|
||||
$this->id = $id;
|
||||
|
||||
if (empty($date))
|
||||
$date = time();
|
||||
|
||||
if (is_string($date))
|
||||
$date = strtotime($date);
|
||||
|
||||
// REVISIT <AP>: 20090808
|
||||
// Anniversary Billing not supported
|
||||
$anniversary = 0 && $this->field('anniversary_billing');
|
||||
if (empty($anniversary)) {
|
||||
$date_parts = getdate($date);
|
||||
$date = mktime(0, 0, 0, $date_parts['mon'], 1, $date_parts['year']);
|
||||
}
|
||||
|
||||
// Make sure we're not trying to assess rent on a closed lease
|
||||
$close_date = $this->field('close_date');
|
||||
$this->pr(17, compact('close_date'));
|
||||
if (!empty($close_date))
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Don't assess rent after customer has moved out
|
||||
$moveout_date = $this->field('moveout_date');
|
||||
$this->pr(17, compact('moveout_date'));
|
||||
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine when the customer has already been charged through
|
||||
// and, of course, don't charge them if they've already been.
|
||||
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
||||
$this->pr(17, compact('date', 'charge_through_date')
|
||||
+ array('date_str' => date('Y-m-d', $date),
|
||||
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
|
||||
if (!$charge_through_date)
|
||||
return $this->prReturn(null);
|
||||
if ($charge_through_date >= $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// OK, it seems we're going to go ahead and charge the customer
|
||||
// on this lease. Calculate the new charge through date, which
|
||||
// is 1 day shy of 1 month from $date. For example, if we're
|
||||
// charging for 8/1/09, charge through will be 8/31/09, and
|
||||
// charging for 8/15/09, charge through will be 9/14/09.
|
||||
$date_parts = getdate($date);
|
||||
$charge_through_date = mktime(0, 0, 0,
|
||||
$date_parts['mon']+1,
|
||||
$date_parts['mday']-1,
|
||||
$date_parts['year']);
|
||||
|
||||
// Build the invoice transaction
|
||||
$invoice = array('Transaction' => array(), 'Entry' => array());
|
||||
// REVISIT <AP>: 20090808
|
||||
// Keeping Transaction.stamp until the existing facility
|
||||
// is up to date. Then we want the stamp to be now()
|
||||
// (and so can just delete the next line).
|
||||
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
||||
$invoice['Entry'][] =
|
||||
array('effective_date' => date('Y-m-d', $date),
|
||||
'through_date' => date('Y-m-d', $charge_through_date),
|
||||
'amount' => $this->field('rent'),
|
||||
'account_id' => $this->StatementEntry->Account->rentAccountId(),
|
||||
);
|
||||
|
||||
// Record the invoice and return the result
|
||||
$this->pr(21, compact('invoice'));
|
||||
$result = $this->StatementEntry->Transaction->addInvoice
|
||||
($invoice, null, $id);
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyRentAll
|
||||
* - Ensures rent has been charged on all open leases
|
||||
*/
|
||||
|
||||
function assessMonthlyRentAll($date = null) {
|
||||
$this->prEnter(compact('date'));
|
||||
$leases = $this->find
|
||||
('all', array('contain' => false,
|
||||
'conditions' => array('Lease.close_date' => null),
|
||||
));
|
||||
|
||||
$ret = array('Lease' => array());
|
||||
foreach ($leases AS $lease) {
|
||||
$result = $this->assessMonthlyRent($lease['Lease']['id'], $date);
|
||||
$ret['Lease'][$lease['Lease']['id']] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyLate
|
||||
* - Assess late charges for the month, if not already charged.
|
||||
*/
|
||||
|
||||
function assessMonthlyLate($id, $date = null) {
|
||||
$this->prEnter(compact('id', 'date'));
|
||||
$this->id = $id;
|
||||
|
||||
if (empty($date))
|
||||
$date = time();
|
||||
|
||||
if (is_string($date))
|
||||
$date = strtotime($date);
|
||||
|
||||
// REVISIT <AP>: 20090808
|
||||
// Anniversary Billing not supported
|
||||
$anniversary = 0 && $this->field('anniversary_billing');
|
||||
if (empty($anniversary)) {
|
||||
$date_parts = getdate($date);
|
||||
$date = mktime(0, 0, 0, $date_parts['mon'], 11, $date_parts['year']);
|
||||
}
|
||||
|
||||
// Don't assess a late charge if the late charge date hasn't
|
||||
// even come yet. This is questionable whether we really
|
||||
// should restrict, since the user could know what they're
|
||||
// doing, and/or the server clock could be off (although that
|
||||
// would certainly have much larger ramifications). But, the
|
||||
// fact is that this check likely handles the vast majority
|
||||
// of the expected behavior, and presents an issue for very
|
||||
// few users, if any at all.
|
||||
if ($date > time())
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Make sure we're not trying to assess late charges on a closed lease
|
||||
$close_date = $this->field('close_date');
|
||||
$this->pr(17, compact('close_date'));
|
||||
if (!empty($close_date))
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Don't assess late charges after customer has moved out
|
||||
$moveout_date = $this->field('moveout_date');
|
||||
$this->pr(17, compact('moveout_date'));
|
||||
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine when the customer has been charged through for rent
|
||||
// and don't mark them as late if they haven't even been charged rent
|
||||
$charge_through_date = strtotime($this->rentChargeThrough($id));
|
||||
$this->pr(17, compact('date', 'charge_through_date')
|
||||
+ array('date_str' => date('Y-m-d', $date),
|
||||
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
|
||||
if ($charge_through_date <= $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine if the customer is actually late. This is based on
|
||||
// when they've paid through, plus 10 days before they're late.
|
||||
// REVISIT <AP>: 20090813
|
||||
// Of course, 10 days is a terrible hardcode. This should be
|
||||
// driven from the late schedule, saved as part of the lease
|
||||
// (when finally implemented).
|
||||
$paid_through_date = strtotime($this->rentPaidThrough($id));
|
||||
$this->pr(17, compact('date', 'paid_through_date')
|
||||
+ array('date_str' => date('Y-m-d', $date),
|
||||
'paid_through_date_str' => date('Y-m-d', $paid_through_date)));
|
||||
$date_parts = getdate($paid_through_date);
|
||||
$paid_through_date = mktime(0, 0, 0, $date_parts['mon'], $date_parts['mday']+10, $date_parts['year']);
|
||||
if ($paid_through_date >= $date)
|
||||
return $this->prReturn(null);
|
||||
|
||||
// Determine if the customer has already been charged a late fee
|
||||
// and, of course, don't charge them if they've already been.
|
||||
$late_charges = $this->lateCharges($id);
|
||||
foreach ($late_charges AS $late) {
|
||||
if (strtotime($late['StatementEntry']['effective_date']) == $date)
|
||||
return $this->prReturn(null);
|
||||
}
|
||||
|
||||
// Build the invoice transaction
|
||||
$invoice = array('Transaction' => array(), 'Entry' => array());
|
||||
// REVISIT <AP>: 20090808
|
||||
// Keeping Transaction.stamp until the existing facility
|
||||
// is up to date. Then we want the stamp to be now()
|
||||
// (and so can just delete the next line).
|
||||
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
|
||||
$invoice['Entry'][] =
|
||||
array('effective_date' => date('Y-m-d', $date),
|
||||
'amount' => 10,
|
||||
'account_id' => $this->StatementEntry->Account->lateChargeAccountId(),
|
||||
);
|
||||
|
||||
// Record the invoice and return the result
|
||||
$this->pr(21, compact('invoice'));
|
||||
$result = $this->StatementEntry->Transaction->addInvoice
|
||||
($invoice, null, $id);
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assessMonthlyLateAll
|
||||
* - Ensures rent has been charged on all open leases
|
||||
*/
|
||||
|
||||
function assessMonthlyLateAll($date = null) {
|
||||
$this->prEnter(compact('date'));
|
||||
$leases = $this->find
|
||||
('all', array('contain' => false,
|
||||
'conditions' => array('Lease.close_date' => null),
|
||||
));
|
||||
|
||||
$ret = array('Lease' => array());
|
||||
foreach ($leases AS $lease) {
|
||||
$result = $this->assessMonthlyLate($lease['Lease']['id'], $date);
|
||||
$ret['Lease'][$lease['Lease']['id']] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* functions: delinquency
|
||||
* - SQL fragments to determine whether a lease is delinquent
|
||||
*/
|
||||
|
||||
function conditionDelinquent($table_name = 'Lease') {
|
||||
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
||||
return ("({$t}close_date IS NULL AND" .
|
||||
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 1 DAY))");
|
||||
}
|
||||
|
||||
function delinquentDaysSQL($table_name = 'Lease') {
|
||||
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
|
||||
return ("IF(" . $this->conditionDelinquent($table_name) . "," .
|
||||
" DATEDIFF(NOW(), {$t}paid_through_date)-1," .
|
||||
" NULL)");
|
||||
}
|
||||
|
||||
function delinquentField($table_name = 'Lease') {
|
||||
return ($this->delinquentDaysSQL($table_name) . " AS 'delinquent'");
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: moveIn
|
||||
* - Moves the specified customer into the specified lease
|
||||
*/
|
||||
|
||||
function moveIn($customer_id, $unit_id,
|
||||
$deposit = null, $rent = null,
|
||||
$stamp = null, $comment = null)
|
||||
{
|
||||
$this->prEnter(compact('customer_id', 'unit_id',
|
||||
'deposit', 'rent', 'stamp', 'comment'));
|
||||
|
||||
$lt = $this->LeaseType->find('first',
|
||||
array('conditions' =>
|
||||
array('code' => 'SL')));
|
||||
|
||||
// Use NOW if not given a movein date
|
||||
if (!isset($stamp))
|
||||
$stamp = date('Y-m-d G:i:s');
|
||||
|
||||
if (!$comment)
|
||||
$comment = null;
|
||||
|
||||
if (!isset($deposit) || !isset($rent)) {
|
||||
$rates = $this->Unit->find
|
||||
('first',
|
||||
array('contain' =>
|
||||
array('UnitSize' =>
|
||||
array('deposit', 'rent'),
|
||||
),
|
||||
'fields' => array('deposit', 'rent'),
|
||||
'conditions' => array('Unit.id' => $unit_id),
|
||||
));
|
||||
|
||||
$deposit =
|
||||
(isset($deposit)
|
||||
? $deposit
|
||||
: (isset($rates['Unit']['deposit'])
|
||||
? $rates['Unit']['deposit']
|
||||
: (isset($rates['UnitSize']['deposit'])
|
||||
? $rates['UnitSize']['deposit']
|
||||
: 0)));
|
||||
|
||||
$rent =
|
||||
(isset($rent)
|
||||
? $rent
|
||||
: (isset($rates['Unit']['rent'])
|
||||
? $rates['Unit']['rent']
|
||||
: (isset($rates['UnitSize']['rent'])
|
||||
? $rates['UnitSize']['rent']
|
||||
: 0)));
|
||||
}
|
||||
|
||||
|
||||
// Save this new lease.
|
||||
$this->create();
|
||||
if (!$this->save(array('lease_type_id' => $lt['LeaseType']['id'],
|
||||
'unit_id' => $unit_id,
|
||||
'customer_id' => $customer_id,
|
||||
'lease_date' => $stamp,
|
||||
'movein_date' => $stamp,
|
||||
'deposit' => $deposit,
|
||||
'rent' => $rent,
|
||||
'comment' => $comment), false)) {
|
||||
return $this->prReturn(null);
|
||||
}
|
||||
|
||||
// Set the lease number to be the same as the lease ID
|
||||
$this->id;
|
||||
$this->saveField('number', $this->id);
|
||||
|
||||
// Update the current lease count for the customer
|
||||
$this->Customer->updateLeaseCount($customer_id);
|
||||
|
||||
// Update the unit status
|
||||
$this->Unit->updateStatus($unit_id, 'OCCUPIED');
|
||||
|
||||
// REVISIT <AP>: 20090702
|
||||
// We need to assess the security deposit charge,
|
||||
// and probably rent as well. Rent, however, will
|
||||
// require user parameters to indicate whether it
|
||||
// was waived, pro-rated, etc.
|
||||
|
||||
// Return the new lease ID
|
||||
return $this->prReturn($this->id);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: moveOut
|
||||
* - Moves the customer out of the specified lease
|
||||
*/
|
||||
|
||||
function moveOut($id, $status = 'VACANT',
|
||||
$stamp = null, $close = true)
|
||||
{
|
||||
$this->prEnter(compact('id', 'status', 'stamp', 'close'));
|
||||
|
||||
// Use NOW if not given a moveout date
|
||||
if (!isset($stamp))
|
||||
$stamp = date('Y-m-d G:i:s');
|
||||
|
||||
// Reset the data
|
||||
$this->create();
|
||||
$this->id = $id;
|
||||
|
||||
// Set the customer move-out date
|
||||
$this->data['Lease']['moveout_date'] = $stamp;
|
||||
|
||||
// Save it!
|
||||
$this->save($this->data, false);
|
||||
|
||||
// Release the security deposit(s)
|
||||
$this->releaseSecurityDeposits($id, $stamp);
|
||||
|
||||
// Close the lease, if so requested
|
||||
if ($close)
|
||||
$this->close($id, $stamp);
|
||||
|
||||
// Update the current lease count for the customer
|
||||
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
||||
|
||||
// Finally, update the unit status
|
||||
$this->recursive = -1;
|
||||
$this->read();
|
||||
$this->Unit->updateStatus($this->data['Lease']['unit_id'], $status);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: close
|
||||
* - Closes the lease to further action
|
||||
*/
|
||||
|
||||
function close($id, $stamp = null) {
|
||||
$this->prEnter(compact('id', 'stamp'));
|
||||
|
||||
if (!$this->closeable($id))
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Reset the data
|
||||
$this->create();
|
||||
$this->id = $id;
|
||||
|
||||
// Use NOW if not given a moveout date
|
||||
if (!isset($stamp))
|
||||
$stamp = date('Y-m-d G:i:s');
|
||||
|
||||
// Set the close date
|
||||
$this->data['Lease']['close_date'] = $stamp;
|
||||
|
||||
// Save it!
|
||||
$this->save($this->data, false);
|
||||
|
||||
// Update the current lease count for the customer
|
||||
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reopen
|
||||
* - Re-Opens the lease for further action
|
||||
*/
|
||||
|
||||
function reopen($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
if (!$this->isClosed($id))
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Reset the data
|
||||
$this->create();
|
||||
$this->id = $id;
|
||||
|
||||
// Set the close date
|
||||
$this->data['Lease']['close_date'] = null;
|
||||
|
||||
// Save it!
|
||||
$this->save($this->data, false);
|
||||
|
||||
// Update the current lease count for the customer
|
||||
$this->Customer->updateLeaseCount($this->field('customer_id'));
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: isClosed
|
||||
* - Checks to see if the lease is closed
|
||||
*/
|
||||
|
||||
function isClosed($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
$this->recursive = -1;
|
||||
$this->read(null, $id);
|
||||
|
||||
return $this->prReturn(!empty($this->data['Lease']['close_date']));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: closeable
|
||||
* - Indicates whether or not the lease can be closed
|
||||
*/
|
||||
|
||||
function closeable($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
$this->recursive = -1;
|
||||
$this->read(null, $id);
|
||||
|
||||
// We can't close a lease that's still in use
|
||||
if (!isset($this->data['Lease']['moveout_date']))
|
||||
return $this->prReturn(false);
|
||||
|
||||
// We can't close a lease that's already closed
|
||||
if (isset($this->data['Lease']['close_date']))
|
||||
return $this->prReturn(false);
|
||||
|
||||
// A lease can only be closed if there are no outstanding
|
||||
// security deposits ...
|
||||
if ($this->securityDepositBalance($id) != 0)
|
||||
return $this->prReturn(false);
|
||||
|
||||
// ... and if the account balance is zero.
|
||||
if ($this->balance($id) != 0)
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Apparently this lease meets all the criteria!
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: refund
|
||||
* - Marks any lease balance as payable to the customer.
|
||||
*/
|
||||
|
||||
function refund($id, $stamp = null) {
|
||||
$this->prEnter(compact('id'));
|
||||
$balance = $this->balance($id);
|
||||
|
||||
if ($balance >= 0)
|
||||
return $this->prReturn(array('error' => true));
|
||||
|
||||
$balance *= -1;
|
||||
|
||||
// Build a transaction
|
||||
$refund = array('Transaction' => array(), 'Entry' => array());
|
||||
$refund['Transaction']['stamp'] = $stamp;
|
||||
$refund['Transaction']['comment'] = "Lease Refund";
|
||||
|
||||
$refund['Entry'][] =
|
||||
array('amount' => $balance);
|
||||
|
||||
$result = $this->StatementEntry->Transaction->addRefund
|
||||
($refund, null, $id);
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: update
|
||||
* - Update any cached or calculated fields
|
||||
*/
|
||||
function update($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
$this->id = $id;
|
||||
$this->saveField('charge_through_date', $this->rentChargeThrough($id));
|
||||
$this->saveField('paid_through_date', $this->rentPaidThrough($id));
|
||||
|
||||
$moveout = $this->field('moveout_date');
|
||||
if (empty($moveout))
|
||||
$this->Unit->update($this->field('unit_id'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: balance
|
||||
* - Returns the balance of money owed on the lease
|
||||
*/
|
||||
|
||||
function balance($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
$stats = $this->stats($id);
|
||||
return $this->prReturn($stats['balance']);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns summary data from the requested lease.
|
||||
*/
|
||||
|
||||
function stats($id = null, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
if (!$id)
|
||||
return $this->prReturn(null);
|
||||
|
||||
$find_stats = $this->StatementEntry->find
|
||||
('first', array
|
||||
('contain' => false,
|
||||
'fields' => $this->StatementEntry->chargeDisbursementFields(true),
|
||||
'conditions' => array('StatementEntry.lease_id' => $id),
|
||||
));
|
||||
$find_stats = $find_stats[0];
|
||||
return $this->prReturn($find_stats);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
class LeaseType extends AppModel {
|
||||
|
||||
var $name = 'LeaseType';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty')
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Lease',
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,179 +0,0 @@
|
||||
<?php
|
||||
class Ledger extends AppModel {
|
||||
|
||||
var $belongsTo = array(
|
||||
'Account',
|
||||
'PriorLedger' => array('className' => 'Ledger'),
|
||||
'CloseTransaction' => array('className' => 'Transaction'),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Transaction',
|
||||
'LedgerEntry',
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: accountID
|
||||
* - Returns the account ID for the given ledger
|
||||
*/
|
||||
function accountID($id) {
|
||||
$this->cacheQueries = true;
|
||||
$item = $this->find('first', array
|
||||
('link' => array('Account'),
|
||||
'conditions' => array('Ledger.id' => $id),
|
||||
));
|
||||
$this->cacheQueries = false;
|
||||
//pr(compact('id', 'item'));
|
||||
return $item['Account']['id'];
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: currentLedgerID
|
||||
* - Returns the current ledger ID of the account for the given ledger.
|
||||
*/
|
||||
function currentLedgerID($id) {
|
||||
return $this->Account->currentLedgerID($this->accountID($id));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: closeLedger
|
||||
* - Closes the current ledger, and returns a fresh one
|
||||
*/
|
||||
function closeLedgers($ids) {
|
||||
$ret = array('new_ledger_ids' => array());
|
||||
|
||||
$entries = array();
|
||||
foreach ($ids AS $id) {
|
||||
// Query stats to get the balance forward
|
||||
$stats = $this->stats($id);
|
||||
|
||||
// Populate fields from the current ledger
|
||||
$this->recursive = -1;
|
||||
$this->id = $id;
|
||||
$this->read();
|
||||
|
||||
// Build a new ledger to replace the current one
|
||||
$this->data['Ledger']['id'] = null;
|
||||
$this->data['Ledger']['close_transaction_id'] = null;
|
||||
$this->data['Ledger']['prior_ledger_id'] = $id;
|
||||
$this->data['Ledger']['comment'] = null;
|
||||
++$this->data['Ledger']['sequence'];
|
||||
$this->data['Ledger']['name'] =
|
||||
($this->data['Ledger']['account_id'] .
|
||||
'-' .
|
||||
$this->data['Ledger']['sequence']);
|
||||
|
||||
// Save the new ledger
|
||||
$this->id = null;
|
||||
if (!$this->save($this->data, false))
|
||||
return array('error' => true, 'new_ledger_data' => $this->data) + $ret;
|
||||
$ret['new_ledger_ids'][] = $this->id;
|
||||
|
||||
$entries[] = array('old_ledger_id' => $id,
|
||||
'new_ledger_id' => $this->id,
|
||||
'amount' => $stats['balance']);
|
||||
}
|
||||
|
||||
// Perform the close
|
||||
$result = $this->Transaction->addClose(array('Transaction' => array(),
|
||||
'Ledger' => $entries));
|
||||
$ret['Transaction'] = $result;
|
||||
if ($result['error'])
|
||||
return array('error' => true) + $ret;
|
||||
|
||||
return $ret + array('error' => false);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: debitCreditFields
|
||||
* - Returns the fields necessary to determine whether the queried
|
||||
* entries are a debit, or a credit, and also the effect each have
|
||||
* on the overall balance of the ledger.
|
||||
*/
|
||||
function debitCreditFields($sum = false, $balance = true,
|
||||
$entry_name = 'LedgerEntry', $account_name = 'Account') {
|
||||
return $this->LedgerEntry->debitCreditFields
|
||||
($sum, $balance, $entry_name, $account_name);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: ledgerEntries
|
||||
* - Returns an array of ledger entries that belong to a given
|
||||
* ledger. There is extra work done to establish debit/credit
|
||||
*/
|
||||
function ledgerEntries($ids, $query = null) {
|
||||
if (empty($ids))
|
||||
return null;
|
||||
|
||||
$entries = $this->LedgerEntry->find
|
||||
('all', array
|
||||
('link' => array('Ledger' => array('Account')),
|
||||
'fields' => array_merge(array("LedgerEntry.*"),
|
||||
$this->LedgerEntry->debitCreditFields()),
|
||||
'conditions' => array('LedgerEntry.ledger_id' => $ids),
|
||||
));
|
||||
|
||||
//pr(compact('entries'));
|
||||
return $entries;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns summary data from the requested ledger.
|
||||
*/
|
||||
function stats($id, $query = null) {
|
||||
if (!$id)
|
||||
return null;
|
||||
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['Account']))
|
||||
$query['link']['Account'] = array();
|
||||
if (!isset($query['link']['Account']['fields']))
|
||||
$query['link']['Account']['fields'] = array();
|
||||
if (!isset($query['fields']))
|
||||
$query['fields'] = array();
|
||||
|
||||
$query['fields'] = array_merge($query['fields'],
|
||||
$this->debitCreditFields(true));
|
||||
|
||||
$query['conditions'][] = array('LedgerEntry.ledger_id' => $id);
|
||||
$query['group'][] = 'LedgerEntry.ledger_id';
|
||||
|
||||
$stats = $this->LedgerEntry->find('first', $query);
|
||||
|
||||
// The fields are all tucked into the [0] index,
|
||||
// and the rest of the array is useless (empty).
|
||||
$stats = $stats[0];
|
||||
|
||||
// Make sure we have a member for debit/credit
|
||||
foreach(array('debits', 'credits') AS $crdr)
|
||||
if (!isset($stats[$crdr]))
|
||||
$stats[$crdr] = null;
|
||||
|
||||
// Make sure we have a non-null balance
|
||||
if (!isset($stats['balance']))
|
||||
$stats['balance'] = 0;
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,177 +0,0 @@
|
||||
<?php
|
||||
class LedgerEntry extends AppModel {
|
||||
|
||||
var $belongsTo = array(
|
||||
'Transaction',
|
||||
'Account',
|
||||
'Ledger',
|
||||
);
|
||||
|
||||
var $hasOne = array(
|
||||
'Tender' => array(
|
||||
'dependent' => true,
|
||||
),
|
||||
'DebitDoubleEntry' => array(
|
||||
'className' => 'DoubleEntry',
|
||||
'foreignKey' => 'debit_entry_id',
|
||||
'dependent' => true,
|
||||
),
|
||||
'CreditDoubleEntry' => array(
|
||||
'className' => 'DoubleEntry',
|
||||
'foreignKey' => 'credit_entry_id',
|
||||
'dependent' => true,
|
||||
),
|
||||
'DoubleEntry' => array(
|
||||
'foreignKey' => false,
|
||||
),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
// The Debit half of the double entry matching THIS Credit (if it is one)
|
||||
'DebitEntry' => array(
|
||||
'className' => 'LedgerEntry',
|
||||
'joinTable' => 'double_entries',
|
||||
'linkalias' => 'DDE',
|
||||
'foreignKey' => 'credit_entry_id',
|
||||
'associationForeignKey' => 'debit_entry_id',
|
||||
),
|
||||
|
||||
// The Credit half of the double entry matching THIS Debit (if it is one)
|
||||
'CreditEntry' => array(
|
||||
'className' => 'LedgerEntry',
|
||||
'joinTable' => 'double_entries',
|
||||
'linkalias' => 'CDE',
|
||||
'foreignKey' => 'debit_entry_id',
|
||||
'associationForeignKey' => 'credit_entry_id',
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: debitCreditFields
|
||||
* - Returns the fields necessary to determine whether the queried
|
||||
* entries are a debit, or a credit, and also the effect each have
|
||||
* on the overall balance of the account/ledger.
|
||||
*/
|
||||
|
||||
function debitCreditFields($sum = false, $balance = true,
|
||||
$entry_name = 'LedgerEntry', $account_name = 'Account') {
|
||||
$fields = array
|
||||
(
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.crdr = 'DEBIT'," .
|
||||
" {$entry_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS debit' . ($sum ? 's' : ''),
|
||||
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.crdr = 'CREDIT'," .
|
||||
" {$entry_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS credit' . ($sum ? 's' : ''),
|
||||
);
|
||||
|
||||
if ($balance)
|
||||
$fields[] =
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF(${account_name}.type IN ('ASSET', 'EXPENSE')," .
|
||||
" IF({$entry_name}.crdr = 'DEBIT', 1, -1)," .
|
||||
" IF({$entry_name}.crdr = 'CREDIT', 1, -1))" .
|
||||
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
|
||||
($sum ? ')' : '') . ' AS balance';
|
||||
|
||||
if ($sum)
|
||||
$fields[] = "COUNT({$entry_name}.id) AS entries";
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: verifyLedgerEntry
|
||||
* - Verifies consistenty of new ledger entry data
|
||||
* (not in a pre-existing ledger entry)
|
||||
*/
|
||||
function verifyLedgerEntry($entry, $tender = null) {
|
||||
/* pr(array("LedgerEntry::verifyLedgerEntry()" */
|
||||
/* => compact('entry', 'tender'))); */
|
||||
|
||||
if (empty($entry['account_id']) ||
|
||||
empty($entry['crdr']) ||
|
||||
empty($entry['amount'])
|
||||
) {
|
||||
/* pr(array("LedgerEntry::verifyLedgerEntry()" */
|
||||
/* => "Entry verification failed")); */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($tender) && !$this->Tender->verifyTender($tender)) {
|
||||
/* pr(array("LedgerEntry::verifyLedgerEntry()" */
|
||||
/* => "Tender verification failed")); */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: addLedgerEntry
|
||||
* - Inserts new Ledger Entry into the database
|
||||
*/
|
||||
function addLedgerEntry($entry, $tender = null) {
|
||||
//$this->prFunctionLevel(16);
|
||||
$this->prEnter(compact('entry', 'tender'));
|
||||
|
||||
$ret = array('data' => $entry);
|
||||
if (!$this->verifyLedgerEntry($entry, $tender))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
if (empty($entry['ledger_id']))
|
||||
$entry['ledger_id'] =
|
||||
$this->Account->currentLedgerID($entry['account_id']);
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($entry))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
$ret['ledger_entry_id'] = $this->id;
|
||||
|
||||
if (isset($tender)) {
|
||||
$tender['account_id'] = $entry['account_id'];
|
||||
$tender['ledger_entry_id'] = $ret['ledger_entry_id'];
|
||||
$result = $this->Tender->addTender($tender);
|
||||
$ret['Tender'] = $result;
|
||||
if ($result['error'])
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
}
|
||||
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns summary data from the requested ledger entry
|
||||
*/
|
||||
function stats($id = null, $query = null, $set = null) {
|
||||
$this->queryInit($query);
|
||||
|
||||
// REVISIT <AP>: 20090816
|
||||
// This function appeared to be dramatically broken,
|
||||
// a throwback to an earlier time. I deleted its
|
||||
// contents and added this error to ensure it does
|
||||
// not get used.
|
||||
$this->INTERNAL_ERROR('This function should not be used');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
class Lock extends AppModel {
|
||||
|
||||
var $name = 'Lock';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
'key' => array('notempty')
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'LocksUnits'
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Unit'
|
||||
);
|
||||
|
||||
var $default_log_level = array('log' => 30, 'show' => 15);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: saveLock
|
||||
* - save data about a new or existing lock
|
||||
*/
|
||||
|
||||
function saveLock($data) {
|
||||
$this->prEnter(compact('data'));
|
||||
$id = $data['Lock']['id'];
|
||||
|
||||
if ($id) {
|
||||
$this->id = $id;
|
||||
|
||||
// Save the old key
|
||||
$oldkey = $this->field('key');
|
||||
$this->pr(5, compact('oldkey'));
|
||||
|
||||
if ($this->field('key') != $data['Lock']['key']) {
|
||||
$data['Lock']['key_last'] = $this->field('key');
|
||||
$data['Lock']['key_ts'] = date('Y-m-d G:i:s');
|
||||
}
|
||||
|
||||
/* // Find the number of outstanding locks in use */
|
||||
/* $locks = $this->find('first', */
|
||||
/* array('link' => array('Unit' => array('fields' => array('Unit.id'))), */
|
||||
/* 'fields' => 'SUM(Unit.id) AS inuse', */
|
||||
/* 'conditions' => array('Lock.id' => $id), */
|
||||
/* )); */
|
||||
/* $this->pr(5, compact('locks')); */
|
||||
|
||||
/* // Can't reduce the locks if there are all in use */
|
||||
/* if ($locks[0]['inuse'] > $data['Lock']['qty']) */
|
||||
/* return $this->prReturn(false); */
|
||||
}
|
||||
else {
|
||||
// Brand new lock
|
||||
}
|
||||
|
||||
if (!$data['Lock']['qty'])
|
||||
$data['Lock']['qty'] = 1;
|
||||
|
||||
// Everything looks good... save it!
|
||||
return $this->prReturn($this->save($data, false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: destroy
|
||||
* - destroys a lock
|
||||
*/
|
||||
|
||||
function destroy($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
// Can't delete a lock that's in use... check.
|
||||
$this->id = $id;
|
||||
$lock = $this->find
|
||||
('first', array
|
||||
('contain' => array('Unit'),
|
||||
));
|
||||
|
||||
// If it's in use, bail with error
|
||||
$this->pr(1, $lock);
|
||||
if (isset($lock['Unit']) && count($lock['Unit']) > 0)
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Otherwise, attempt to delete the lock from the database
|
||||
return $this->prReturn($this->delete());
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: lockList
|
||||
* - list of all locks in the system
|
||||
*/
|
||||
|
||||
function lockList() {
|
||||
return $this->find('list',
|
||||
array('order' =>
|
||||
array('name'),
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<?php
|
||||
class LocksUnit extends AppModel {
|
||||
var $primaryKey = false;
|
||||
|
||||
var $belongsTo = array(
|
||||
'Lock',
|
||||
'Unit',
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
class Map extends AppModel {
|
||||
|
||||
var $name = 'Map';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'site_id' => array('numeric'),
|
||||
'site_area_id' => array('numeric'),
|
||||
'name' => array('notempty'),
|
||||
'width' => array('numeric'),
|
||||
'depth' => array('numeric')
|
||||
);
|
||||
|
||||
var $belongsTo = array(
|
||||
'SiteArea',
|
||||
);
|
||||
|
||||
var $hasAndBelongsToMany = array(
|
||||
'Unit',
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
class Membership extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('User',
|
||||
'Site',
|
||||
'Group'
|
||||
);
|
||||
|
||||
function memberGroups($user_id, $site_id) {
|
||||
$this->prEnter(compact('user_id', 'site_id'));
|
||||
|
||||
$this->cacheQueries = true;
|
||||
$groups = $this->find('all', array
|
||||
('recursive' => -1,
|
||||
'fields' => array('group_id'),
|
||||
'conditions' => array(array('user_id' => $user_id),
|
||||
array('site_id' => $site_id)),
|
||||
));
|
||||
$this->cacheQueries = false;
|
||||
|
||||
if (empty($groups))
|
||||
return $this->prReturn(null);
|
||||
|
||||
$group_ids = array();
|
||||
foreach ($groups AS $group)
|
||||
$group_ids[] = $group['Membership']['group_id'];
|
||||
|
||||
return $this->prReturn($group_ids);
|
||||
}
|
||||
|
||||
function memberOf($user_id, $site_id) {
|
||||
$groups = $this->memberGroups($user_id, $site_id);
|
||||
return (!empty($groups));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
class Option extends AppModel {
|
||||
|
||||
var $hasMany =
|
||||
array('OptionValue',
|
||||
);
|
||||
|
||||
var $knows =
|
||||
array('User', 'Site', 'Group');
|
||||
|
||||
|
||||
static $option_set = array();
|
||||
|
||||
function getAll($name, $force = false) {
|
||||
/* $this->prClassLevel(30); */
|
||||
/* //$this->OptionValue->prClassLevel(30); */
|
||||
/* $this->Group->Membership->prClassLevel(30); */
|
||||
/* $this->OptionValue->SiteOption->prClassLevel(30); */
|
||||
/* $this->OptionValue->UserOption->prClassLevel(30); */
|
||||
/* $this->OptionValue->GroupOption->prClassLevel(30); */
|
||||
/* $this->OptionValue->DefaultOption->prClassLevel(30); */
|
||||
$this->prEnter(compact('name'));
|
||||
|
||||
if (!empty(self::$option_set[$name]) && !$force)
|
||||
return $this->prReturn(self::$option_set[$name]);
|
||||
|
||||
self::$option_set[$name] = array();
|
||||
|
||||
$site_id = $this->Site->currentSiteId();
|
||||
$user_id = $this->User->currentUserId();
|
||||
$group_ids = $this->Group->currentGroupIds();
|
||||
|
||||
/* $site_id = 2; */
|
||||
/* $user_id = 4; */
|
||||
/* $group_ids = $this->Group->groupIds($user_id, $site_id); */
|
||||
|
||||
if (!empty($site_id))
|
||||
self::$option_set[$name] =
|
||||
array_merge(self::$option_set[$name],
|
||||
$this->OptionValue->SiteOption->values($site_id, $name));
|
||||
|
||||
if (!empty($user_id))
|
||||
self::$option_set[$name] =
|
||||
array_merge(self::$option_set[$name],
|
||||
$this->OptionValue->UserOption->values($user_id, $name));
|
||||
|
||||
if (!empty($group_ids))
|
||||
self::$option_set[$name] =
|
||||
array_merge(self::$option_set[$name],
|
||||
$this->OptionValue->GroupOption->values($group_ids, $name));
|
||||
|
||||
self::$option_set[$name] =
|
||||
array_merge(self::$option_set[$name],
|
||||
$this->OptionValue->DefaultOption->values($name));
|
||||
|
||||
return $this->prReturn(self::$option_set[$name]);
|
||||
}
|
||||
|
||||
function get($name) {
|
||||
$this->prEnter(compact('name'));
|
||||
$values = $this->getAll($name);
|
||||
if (empty($values))
|
||||
return null;
|
||||
return $this->prReturn($values[0]);
|
||||
}
|
||||
|
||||
function enabled($name) {
|
||||
$val = $this->get($name);
|
||||
return (!empty($val));
|
||||
}
|
||||
|
||||
function disabled($name) {
|
||||
return (!$this->enabled($name));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
class OptionValue extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('Option',
|
||||
);
|
||||
|
||||
var $hasMany =
|
||||
array('UserOption',
|
||||
'SiteOption',
|
||||
'GroupOption',
|
||||
'DefaultOption',
|
||||
);
|
||||
|
||||
function values($name = null, $query = null) {
|
||||
$this->prEnter(compact('name', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['Option'] = array();
|
||||
|
||||
if (!empty($name)) {
|
||||
$query['conditions'][] = array('Option.name' => $name);
|
||||
$query['link']['Option']['fields'] = array();
|
||||
}
|
||||
|
||||
$this->cacheQueries = true;
|
||||
$values = array();
|
||||
foreach ($this->find('all', $query) AS $result)
|
||||
$values[] = $result['OptionValue']['value'];
|
||||
$this->cacheQueries = false;
|
||||
|
||||
return $this->prReturn($values);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
class Permission extends AppModel {
|
||||
|
||||
var $hasMany =
|
||||
array('PermissionValue',
|
||||
);
|
||||
|
||||
var $knows =
|
||||
array('User', 'Site', 'Group');
|
||||
|
||||
static $permission_set = array();
|
||||
|
||||
function getAll($name, $force = false) {
|
||||
/* $this->prClassLevel(30); */
|
||||
/* $this->PermissionValue->prClassLevel(30); */
|
||||
/* $this->Group->Membership->prClassLevel(30); */
|
||||
/* $this->PermissionValue->SitePermission->prClassLevel(30); */
|
||||
/* $this->PermissionValue->UserPermission->prClassLevel(30); */
|
||||
/* $this->PermissionValue->GroupPermission->prClassLevel(30); */
|
||||
/* $this->PermissionValue->DefaultPermission->prClassLevel(30); */
|
||||
$this->prEnter(compact('name'));
|
||||
|
||||
if (!empty(self::$permission_set[$name]) && !$force)
|
||||
return $this->prReturn(self::$permission_set[$name]);
|
||||
|
||||
self::$permission_set[$name] = array();
|
||||
|
||||
$site_id = $this->Site->currentSiteId();
|
||||
$user_id = $this->User->currentUserId();
|
||||
$group_ids = $this->Group->currentGroupIds();
|
||||
|
||||
/* $site_id = 1; */
|
||||
/* $user_id = 2; */
|
||||
/* $group_ids = $this->Group->groupIds($user_id, $site_id); */
|
||||
|
||||
if (empty($group_ids)) {
|
||||
self::$permission_set[$name][$name][] = array('access' => 'DENY', 'level' => null);
|
||||
$site_id = null;
|
||||
$user_id = null;
|
||||
}
|
||||
|
||||
if (!empty($site_id))
|
||||
self::$permission_set[$name] =
|
||||
array_merge(self::$permission_set[$name],
|
||||
$this->PermissionValue->SitePermission->values($site_id, $name));
|
||||
|
||||
if (!empty($user_id))
|
||||
self::$permission_set[$name] =
|
||||
array_merge(self::$permission_set[$name],
|
||||
$this->PermissionValue->UserPermission->values($user_id, $name));
|
||||
|
||||
if (!empty($group_ids)) {
|
||||
self::$permission_set[$name] =
|
||||
array_merge(self::$permission_set[$name],
|
||||
$this->PermissionValue->GroupPermission->values($group_ids, $name));
|
||||
|
||||
self::$permission_set[$name] =
|
||||
array_merge(self::$permission_set[$name],
|
||||
$this->PermissionValue->DefaultPermission->values($name));
|
||||
|
||||
self::$permission_set[$name][] = array('access' => 'ALLOW', 'level' => null);
|
||||
}
|
||||
|
||||
return $this->prReturn(self::$permission_set[$name]);
|
||||
}
|
||||
|
||||
function get($name) {
|
||||
$this->prEnter(compact('name'));
|
||||
|
||||
// REVISIT <AP>: 20090827
|
||||
// This is a pretty crappy algorithm. How do we decide whether DENY really
|
||||
// means DENY, or whether an ALLOW has priority.
|
||||
// Oh well, it works for now...
|
||||
|
||||
$values = $this->getAll($name);
|
||||
$result = array_shift($values);
|
||||
|
||||
foreach ($values AS $value)
|
||||
if (empty($result['level']) || (!empty($value['level']) && $value['level'] < $result['level']))
|
||||
$result['level'] = $value['level'];
|
||||
|
||||
if ($result['access'] !== 'ALLOW')
|
||||
$result['level'] = 9999999;
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
function allow($name) {
|
||||
$this->prEnter(compact('name'));
|
||||
$result = $this->get($name);
|
||||
return $this->prReturn($result['access'] === 'ALLOW');
|
||||
}
|
||||
|
||||
function deny($name) {
|
||||
$this->prEnter(compact('name'));
|
||||
return $this->prReturn(!$this->allow($name));
|
||||
}
|
||||
|
||||
function level($name) {
|
||||
$this->prEnter(compact('name'));
|
||||
$result = $this->get($name);
|
||||
return $this->prReturn($result['level']);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
class PermissionValue extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('Permission',
|
||||
);
|
||||
|
||||
var $hasMany =
|
||||
array('UserPermission',
|
||||
'SitePermission',
|
||||
'GroupPermission',
|
||||
'DefaultPermission',
|
||||
);
|
||||
|
||||
function values($name = null, $query = null) {
|
||||
$this->prEnter(compact('name', 'query'));
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['Permission'] = array();
|
||||
|
||||
if (!empty($name)) {
|
||||
$query['conditions'][] = array('Permission.name' => $name);
|
||||
$query['link']['Permission']['fields'] = array();
|
||||
}
|
||||
|
||||
$this->cacheQueries = true;
|
||||
$values = array();
|
||||
foreach ($this->find('all', $query) AS $result)
|
||||
$values[] = array('access' => $result['PermissionValue']['access'],
|
||||
'level' => $result['PermissionValue']['level']);
|
||||
$this->cacheQueries = false;
|
||||
|
||||
return $this->prReturn($values);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
class Site extends AppModel {
|
||||
|
||||
var $hasMany =
|
||||
array('SiteArea',
|
||||
'SiteOption',
|
||||
'Membership',
|
||||
);
|
||||
|
||||
static $current_site_id;
|
||||
|
||||
function currentSiteId() {
|
||||
if (!empty(self::$current_site_id))
|
||||
return self::$current_site_id;
|
||||
|
||||
// REVISIT <AP>: 20090827
|
||||
// Must get the actual site
|
||||
$code = 'VSS';
|
||||
|
||||
$site = $this->find
|
||||
('first',
|
||||
array('recursive' => -1,
|
||||
'conditions' => compact('code')));
|
||||
|
||||
if (!empty($site['Site']['id']))
|
||||
self::$current_site_id = $site['Site']['id'];
|
||||
else
|
||||
// We must force a stop here, since this is typically
|
||||
// called very early on, and so will cause a recursive
|
||||
// crash as we try to render the internal error and
|
||||
// again stumble on this problem.
|
||||
$this->INTERNAL_ERROR('UNKNOWN SITE', 0, true);
|
||||
|
||||
return self::$current_site_id;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
class SiteArea extends AppModel {
|
||||
|
||||
var $name = 'SiteArea';
|
||||
var $validate = array(
|
||||
'id' => array('numeric'),
|
||||
'site_id' => array('numeric'),
|
||||
'name' => array('notempty')
|
||||
);
|
||||
|
||||
var $belongsTo = array(
|
||||
'Site',
|
||||
);
|
||||
|
||||
var $hasOne = array(
|
||||
'Map',
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
class SiteOption extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('Site',
|
||||
'OptionValue',
|
||||
);
|
||||
|
||||
|
||||
function values($id, $name = null) {
|
||||
$this->prEnter(compact('id', 'name'));
|
||||
|
||||
$query = array();
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['SiteOption'] = array();
|
||||
$query['link']['SiteOption']['fields'] = array();
|
||||
$query['link']['SiteOption']['Site'] = array();
|
||||
$query['link']['SiteOption']['Site']['fields'] = array();
|
||||
$query['conditions'][] = array('Site.id' => $id);
|
||||
return $this->prReturn($this->OptionValue->values($name, $query));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
class SitePermission extends AppModel {
|
||||
|
||||
var $belongsTo =
|
||||
array('Site',
|
||||
'PermissionValue',
|
||||
);
|
||||
|
||||
|
||||
function values($id, $name = null) {
|
||||
$this->prEnter(compact('id', 'name'));
|
||||
|
||||
$query = array();
|
||||
$this->queryInit($query);
|
||||
|
||||
$query['link']['SitePermission'] = array();
|
||||
$query['link']['SitePermission']['fields'] = array();
|
||||
$query['link']['SitePermission']['Site'] = array();
|
||||
$query['link']['SitePermission']['Site']['fields'] = array();
|
||||
$query['conditions'][] = array('Site.id' => $id);
|
||||
return $this->prReturn($this->PermissionValue->values($name, $query));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,784 +0,0 @@
|
||||
<?php
|
||||
class StatementEntry extends AppModel {
|
||||
|
||||
var $belongsTo = array(
|
||||
'Transaction',
|
||||
'Customer',
|
||||
'Lease',
|
||||
'Account',
|
||||
|
||||
// The charge to which this disbursement applies (if it is one)
|
||||
'ChargeEntry' => array(
|
||||
'className' => 'StatementEntry',
|
||||
),
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
// The disbursements that apply to this charge (if it is one)
|
||||
'DisbursementEntry' => array(
|
||||
'className' => 'StatementEntry',
|
||||
'foreignKey' => 'charge_entry_id',
|
||||
'dependent' => true,
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
//var $default_log_level = array('log' => 30, 'show' => 15);
|
||||
var $max_log_level = 19;
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: debit/creditTypes
|
||||
*/
|
||||
|
||||
function debitTypes() {
|
||||
return array('CHARGE', 'PAYMENT', 'REFUND');
|
||||
}
|
||||
|
||||
function creditTypes() {
|
||||
return array('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS');
|
||||
}
|
||||
|
||||
function voidTypes() {
|
||||
return array('VOID');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: chargeDisbursementFields
|
||||
*/
|
||||
|
||||
function chargeDisbursementFields($sum = false, $entry_name = 'StatementEntry') {
|
||||
$debits = $this->debitTypes();
|
||||
$credits = $this->creditTypes();
|
||||
$voids = $this->voidTypes();
|
||||
|
||||
foreach ($debits AS &$enum)
|
||||
$enum = "'" . $enum . "'";
|
||||
foreach ($credits AS &$enum)
|
||||
$enum = "'" . $enum . "'";
|
||||
foreach ($voids AS &$enum)
|
||||
$enum = "'" . $enum . "'";
|
||||
|
||||
$debit_set = implode(", ", $debits);
|
||||
$credit_set = implode(", ", $credits);
|
||||
$void_set = implode(", ", $voids);
|
||||
|
||||
$fields = array
|
||||
(
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.type IN ({$debit_set})," .
|
||||
" {$entry_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS charge' . ($sum ? 's' : ''),
|
||||
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.type IN({$credit_set})," .
|
||||
" {$entry_name}.amount, NULL)" .
|
||||
($sum ? ')' : '') . ' AS disbursement' . ($sum ? 's' : ''),
|
||||
|
||||
($sum ? 'SUM(' : '') .
|
||||
"IF({$entry_name}.type IN ({$debit_set}), 1," .
|
||||
" IF({$entry_name}.type IN ({$credit_set}), -1, 0))" .
|
||||
" * IF({$entry_name}.amount, {$entry_name}.amount, 0)" .
|
||||
($sum ? ')' : '') . ' AS balance',
|
||||
);
|
||||
|
||||
if ($sum)
|
||||
$fields[] = "COUNT({$entry_name}.id) AS entries";
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: verifyStatementEntry
|
||||
* - Verifies consistenty of new statement entry data
|
||||
* (not in a pre-existing statement entry)
|
||||
*/
|
||||
function verifyStatementEntry($entry) {
|
||||
$this->prFunctionLevel(10);
|
||||
$this->prEnter(compact('entry'));
|
||||
|
||||
if (empty($entry['type']) ||
|
||||
//empty($entry['effective_date']) ||
|
||||
empty($entry['account_id']) ||
|
||||
empty($entry['amount'])
|
||||
) {
|
||||
return $this->prReturn(false);
|
||||
}
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: addStatementEntry
|
||||
* - Inserts new Statement Entry into the database
|
||||
*/
|
||||
function addStatementEntry($entry) {
|
||||
$this->prEnter(compact('entry'));
|
||||
|
||||
$ret = array('data' => $entry);
|
||||
if (!$this->verifyStatementEntry($entry))
|
||||
return $this->prReturn(array('error' => true, 'verify_data' => $entry) + $ret);
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($entry))
|
||||
return $this->prReturn(array('error' => true, 'save_data' => $entry) + $ret);
|
||||
|
||||
$ret['statement_entry_id'] = $this->id;
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: waive
|
||||
* - Waives the charge balance
|
||||
*
|
||||
*/
|
||||
function waive($id, $stamp = null) {
|
||||
$this->prEnter(compact('id', 'stamp'));
|
||||
|
||||
// Get the basic information about the entry to be waived.
|
||||
$this->recursive = -1;
|
||||
$charge = $this->read(null, $id);
|
||||
$charge = $charge['StatementEntry'];
|
||||
|
||||
if ($charge['type'] !== 'CHARGE')
|
||||
$this->INTERNAL_ERROR("Waiver item is not CHARGE.");
|
||||
|
||||
// Query the stats to get the remaining balance
|
||||
$stats = $this->stats($id);
|
||||
|
||||
// Build a transaction
|
||||
$waiver = array('Transaction' => array(), 'Entry' => array());
|
||||
$waiver['Transaction']['stamp'] = $stamp;
|
||||
$waiver['Transaction']['comment'] = "Charge Waiver";
|
||||
|
||||
// Add the charge waiver
|
||||
$waiver['Entry'][] =
|
||||
array('amount' => $stats['Charge']['balance'],
|
||||
'comment' => null,
|
||||
);
|
||||
|
||||
// Record the waiver transaction
|
||||
return $this->prReturn($this->Transaction->addWaiver
|
||||
($waiver, $id, $charge['customer_id'], $charge['lease_id']));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reversable
|
||||
* - Returns true if the charge can be reversed; false otherwise
|
||||
*/
|
||||
function reversable($id) {
|
||||
$this->prEnter(compact('id'));
|
||||
|
||||
if (empty($id))
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Verify the item is an actual charge
|
||||
$this->id = $id;
|
||||
$charge_type = $this->field('type');
|
||||
if ($charge_type !== 'CHARGE')
|
||||
return $this->prReturn(false);
|
||||
|
||||
// Determine anything reconciled against the charge
|
||||
$reverse_transaction_id = $this->field('reverse_transaction_id');
|
||||
if (!empty($reverse_transaction_id))
|
||||
return $this->prReturn(false);
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reverse
|
||||
* - Reverses the charges
|
||||
*/
|
||||
function reverse($id, $stamp = null, $comment) {
|
||||
$this->prEnter(compact('id', 'stamp'));
|
||||
|
||||
// Verify the item can be reversed
|
||||
if (!$this->reversable($id))
|
||||
$this->INTERNAL_ERROR("Item is not reversable.");
|
||||
|
||||
// Get the basic information about this charge
|
||||
$charge = $this->find('first', array('contain' => true));
|
||||
//$charge = $charge['StatementEntry'];
|
||||
|
||||
// Query the stats to get the remaining balance
|
||||
$stats = $this->stats($id);
|
||||
$charge['paid'] = $stats['Charge']['disbursement'];
|
||||
|
||||
// Record the reversal transaction
|
||||
$result = $this->Transaction->addReversal
|
||||
($charge, $stamp, $comment ? $comment : 'Charge Reversal');
|
||||
|
||||
if (empty($result['error'])) {
|
||||
// Mark the charge as reversed
|
||||
$this->id = $id;
|
||||
$this->saveField('reverse_transaction_id', $result['transaction_id']);
|
||||
}
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reconciledSet
|
||||
* - Returns the set of entries satisfying the given conditions,
|
||||
* along with any entries that they reconcile
|
||||
*/
|
||||
function reconciledSetQuery($set, $query) {
|
||||
$this->queryInit($query);
|
||||
|
||||
if (in_array($set, $this->debitTypes()))
|
||||
$query['link']['DisbursementEntry'] = array('fields' => array("SUM(DisbursementEntry.amount) AS reconciled"));
|
||||
elseif (in_array($set, $this->creditTypes()))
|
||||
$query['link']['ChargeEntry'] = array('fields' => array("SUM(ChargeEntry.amount) AS reconciled"));
|
||||
else
|
||||
die("INVALID RECONCILE SET");
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.type' => $set);
|
||||
$query['group'] = 'StatementEntry.id';
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
function reconciledSet($set, $query = null, $unrec = false, $if_rec_include_partial = false) {
|
||||
//$this->prFunctionLevel(array('log' => 16, 'show' => 10));
|
||||
$this->prEnter(compact('set', 'query', 'unrec', 'if_rec_include_partial'));
|
||||
$lquery = $this->reconciledSetQuery($set, $query);
|
||||
$result = $this->find('all', $lquery);
|
||||
|
||||
$this->pr(20, compact('lquery', 'result'));
|
||||
|
||||
$resultset = array();
|
||||
foreach ($result AS $i => $entry) {
|
||||
$this->pr(25, compact('entry'));
|
||||
if (!empty($entry[0]))
|
||||
$entry['StatementEntry'] = $entry[0] + $entry['StatementEntry'];
|
||||
unset($entry[0]);
|
||||
|
||||
$entry['StatementEntry']['balance'] =
|
||||
$entry['StatementEntry']['amount'] - $entry['StatementEntry']['reconciled'];
|
||||
|
||||
// Since HAVING isn't a builtin feature of CakePHP,
|
||||
// we'll have to post-process to get the desired entries
|
||||
|
||||
if ($entry['StatementEntry']['balance'] == 0)
|
||||
$reconciled = true;
|
||||
elseif ($entry['StatementEntry']['reconciled'] == 0)
|
||||
$reconciled = false;
|
||||
else // Partial disbursement; depends on unrec
|
||||
$reconciled = (!$unrec && $if_rec_include_partial);
|
||||
|
||||
// Add to the set, if it's been requested
|
||||
if ($reconciled == !$unrec)
|
||||
$resultset[] = $entry;
|
||||
}
|
||||
|
||||
return $this->prReturn(array('entries' => $resultset,
|
||||
'summary' => $this->stats(null, $query)));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: reconciledEntries
|
||||
* - Returns a list of entries that reconcile against the given entry.
|
||||
* (such as disbursements towards a charge).
|
||||
*/
|
||||
function reconciledEntriesQuery($id, $query = null) {
|
||||
$this->queryInit($query, false);
|
||||
|
||||
$this->id = $id;
|
||||
$this->recursive = -1;
|
||||
$this->read();
|
||||
|
||||
$query['conditions'][] = array('StatementEntry.id' => $id);
|
||||
|
||||
if (in_array($this->data['StatementEntry']['type'], $this->debitTypes())) {
|
||||
$query['link']['DisbursementEntry'] = array();
|
||||
$query['conditions'][] = array('DisbursementEntry.id !=' => null);
|
||||
}
|
||||
if (in_array($this->data['StatementEntry']['type'], $this->creditTypes())) {
|
||||
$query['link']['ChargeEntry'] = array();
|
||||
$query['conditions'][] = array('ChargeEntry.id !=' => null);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
function reconciledEntries($id, $query = null) {
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
$lquery = $this->reconciledEntriesQuery($id, $query);
|
||||
|
||||
$result = $this->find('all', $lquery);
|
||||
foreach (array_keys($result) AS $i)
|
||||
unset($result[$i]['StatementEntry']);
|
||||
|
||||
return $this->prReturn(array('entries' => $result));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: outstandingDebits
|
||||
* - Determines all debit types that have not yet been resolved.
|
||||
* The name is a bit dumb, but it means any statement entry type
|
||||
* that a positive customer balance could be used to offset. In
|
||||
* other words, entries that are still in need of matching
|
||||
* disbursements. Most notably, this means charges but could
|
||||
* also mean things like refunds as well.
|
||||
*/
|
||||
|
||||
function outstandingDebits($query = null, $customer_id = null,
|
||||
$lease_id = null, $debit_types = null)
|
||||
{
|
||||
$this->prEnter(compact('query', 'lease_id',
|
||||
'customer_id', 'charge_ids',
|
||||
'debit_types'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (empty($debit_types))
|
||||
$debit_types = $this->debitTypes();
|
||||
|
||||
if (!empty($customer_id))
|
||||
$query['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
|
||||
|
||||
if (!empty($lease_id))
|
||||
$query['conditions'][] = array('StatementEntry.lease_id' => $lease_id);
|
||||
|
||||
/* if (isset($charge_ids)) { */
|
||||
/* // REVISIT <AP> 20100330: */
|
||||
/* // Not using $query here, as this code was extracted from its */
|
||||
/* // original location in assignCredits, and so I'm keeping the */
|
||||
/* // logic consistent. It does seem, however, that we shouldn't */
|
||||
/* // be ignoring $query if passed in. I'm sure this won't be */
|
||||
/* // looked at until someone _does_ pass $query in (and it break), */
|
||||
/* // so hopefully at that time, we can understand what needs to */
|
||||
/* // happen in that case (requirements are not clear at present). */
|
||||
/* $lquery = array('contain' => false, */
|
||||
/* 'conditions' => array('StatementEntry.id' => $charge_ids)); */
|
||||
/* } else { */
|
||||
/* $lquery = $query; */
|
||||
/* // If we're working with a specific lease, then limit charges to it */
|
||||
/* if (!empty($lease_id)) */
|
||||
/* $lquery['conditions'][] = array('StatementEntry.lease_id' => $lease_id); */
|
||||
/* } */
|
||||
|
||||
if (empty($query['order']))
|
||||
$query['order'] = 'StatementEntry.effective_date ASC';
|
||||
|
||||
$debits = array();
|
||||
foreach ($debit_types AS $dtype) {
|
||||
$rset = $this->reconciledSet($dtype, $query, true);
|
||||
$entries = $rset['entries'];
|
||||
$debits = array_merge($debits, $entries);
|
||||
$this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries");
|
||||
}
|
||||
|
||||
return $this->prReturn($debits);
|
||||
}
|
||||
|
||||
function outstandingCharges($query = null, $customer_id = null, $lease_id = null) {
|
||||
return $this->outstandingDebits($query, $customer_id, $lease_id, array('CHARGE'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: assignCredits
|
||||
* - Assigns all credits to existing charges
|
||||
*
|
||||
* REVISIT <AP>: 20090726
|
||||
* This algorithm shouldn't be hardcoded. We need to allow
|
||||
* the user to specify how disbursements should be applied.
|
||||
*
|
||||
*/
|
||||
function assignCredits($query = null, $receipt_id = null,
|
||||
$charge_ids = null, $disbursement_type = null,
|
||||
$customer_id = null, $lease_id = null)
|
||||
{
|
||||
//$this->prFunctionLevel(25);
|
||||
$this->prEnter(compact('query', 'receipt_id',
|
||||
'charge_ids', 'disbursement_type',
|
||||
'customer_id', 'lease_id'));
|
||||
$this->queryInit($query);
|
||||
|
||||
if (empty($disbursement_type))
|
||||
$disbursement_type = 'DISBURSEMENT';
|
||||
|
||||
$ret = array();
|
||||
|
||||
// First, find all known credits, unless this call is to make
|
||||
// credit adjustments to a specific charge
|
||||
if (empty($receipt_id)) {
|
||||
|
||||
if (!empty($charge_ids))
|
||||
$this->INTERNAL_ERROR("Charge IDs, yet no corresponding receipt");
|
||||
|
||||
$lquery = $query;
|
||||
if (!empty($customer_id))
|
||||
$lquery['conditions'][] = array('StatementEntry.customer_id' => $customer_id);
|
||||
|
||||
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
|
||||
// REVISIT <AP>: 20090804
|
||||
// We need to ensure that we're using surplus credits ONLY from either
|
||||
// the given lease, or those that do not apply to any specific lease.
|
||||
// However, by doing this, it forces any lease surplus amounts to
|
||||
// remain frozen with that lease until either there is a lease charge,
|
||||
// we refund the money, or we "promote" that surplus to the customer
|
||||
// level and out of the leases direct control.
|
||||
// That seems like a pain. Perhaps we should allow any customer
|
||||
// surplus to be used on any customer charge.
|
||||
$lquery['conditions'][] =
|
||||
array('OR' =>
|
||||
array(array('StatementEntry.lease_id' => null),
|
||||
(!empty($lease_id)
|
||||
? array('StatementEntry.lease_id' => $lease_id)
|
||||
: array()),
|
||||
));
|
||||
$lquery['order'][] = 'StatementEntry.effective_date ASC';
|
||||
$credits = $this->find('all', $lquery);
|
||||
$this->pr(18, compact('credits'),
|
||||
"Credits Established");
|
||||
}
|
||||
else {
|
||||
// Establish credit from the (newly added) receipt
|
||||
$lquery =
|
||||
array('link' =>
|
||||
array('StatementEntry',
|
||||
'LedgerEntry' =>
|
||||
array('conditions' =>
|
||||
array('LedgerEntry.account_id <> Transaction.account_id')
|
||||
),
|
||||
),
|
||||
'conditions' => array('Transaction.id' => $receipt_id),
|
||||
'fields' => array('Transaction.id', 'Transaction.stamp', 'Transaction.amount'),
|
||||
);
|
||||
$receipt_credit = $this->Transaction->find('first', $lquery);
|
||||
if (!$receipt_credit)
|
||||
$this->INTERNAL_ERROR("Unable to locate receipt.");
|
||||
|
||||
$stats = $this->Transaction->stats($receipt_id);
|
||||
$receipt_credit['balance'] = $stats['undisbursed'];
|
||||
|
||||
$receipt_credit['receipt'] = true;
|
||||
$credits = array($receipt_credit);
|
||||
$this->pr(18, compact('credits'),
|
||||
"Receipt Credit Added");
|
||||
}
|
||||
|
||||
// Now find all unpaid charges, using either the specific set
|
||||
// of charges given, or all outstanding charges based on the
|
||||
// query, customer and/or lease
|
||||
if (!empty($charge_ids)) {
|
||||
$this->INTERNAL_ERROR("PERHAPS IMPLEMENTED - THOUGH NEVER TESTED");
|
||||
$lquery = $query;
|
||||
$lquery['conditions'][] = array('StatementEntry.id' => $charge_ids);
|
||||
$charges = $this->reconciledSet('CHARGE', $query, true);
|
||||
} else {
|
||||
$charges = $this->outstandingDebits($query, $customer_id, $lease_id);
|
||||
}
|
||||
|
||||
// Work through all unpaid charges, applying disbursements as we go
|
||||
foreach ($charges AS $charge) {
|
||||
$this->pr(20, compact('charge'),
|
||||
'Process Charge');
|
||||
|
||||
$charge['balance'] = $charge['StatementEntry']['balance'];
|
||||
|
||||
// Use explicit credits before using the new receipt credit
|
||||
foreach ($credits AS &$credit) {
|
||||
if (empty($charge['balance']))
|
||||
break;
|
||||
if ($charge['balance'] < 0)
|
||||
$this->INTERNAL_ERROR("Negative Charge Balance");
|
||||
|
||||
if (!isset($credit['balance']))
|
||||
$credit['balance'] = $credit['StatementEntry']['amount'];
|
||||
|
||||
if (empty($credit['balance']))
|
||||
continue;
|
||||
if ($credit['balance'] < 0)
|
||||
$this->INTERNAL_ERROR("Negative Credit Balance");
|
||||
|
||||
$this->pr(20, compact('charge'),
|
||||
'Attempt Charge Reconciliation');
|
||||
|
||||
if (empty($credit['receipt']))
|
||||
$disbursement_account_id = $credit['StatementEntry']['account_id'];
|
||||
else
|
||||
$disbursement_account_id = $credit['LedgerEntry']['account_id'];
|
||||
|
||||
// REVISIT <AP>: 20090811
|
||||
// Need to come up with a better strategy for handling
|
||||
// concessions. For now, just restricting concessions
|
||||
// to apply only towards rent will resolve the most
|
||||
// predominant (or only) needed usage case.
|
||||
if ($disbursement_account_id == $this->Account->concessionAccountID() &&
|
||||
$charge['StatementEntry']['account_id'] != $this->Account->rentAccountID())
|
||||
continue;
|
||||
|
||||
// Set the disbursement amount to the maximum amount
|
||||
// possible without exceeding the charge or credit balance
|
||||
$disbursement_amount = round(min($charge['balance'], $credit['balance']), 2);
|
||||
if (!isset($credit['applied']))
|
||||
$credit['applied'] = 0;
|
||||
|
||||
$credit['applied'] = round($credit['applied'] + $disbursement_amount, 2);
|
||||
$credit['balance'] = round($credit['balance'] - $disbursement_amount, 2);
|
||||
|
||||
$this->pr(20, compact('credit', 'disbursement_amount'),
|
||||
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
|
||||
(empty($credit['receipt']) ? ' Credit' : ' Receipt'));
|
||||
|
||||
if (strtotime($charge['StatementEntry']['effective_date']) >
|
||||
strtotime($credit['StatementEntry']['effective_date']))
|
||||
$disbursement_edate = $charge['StatementEntry']['effective_date'];
|
||||
else
|
||||
$disbursement_edate = $credit['StatementEntry']['effective_date'];
|
||||
|
||||
if (empty($credit['receipt'])) {
|
||||
// Explicit Credit
|
||||
$result = $this->Transaction->addTransactionEntries
|
||||
(array('include_ledger_entry' => true,
|
||||
'include_statement_entry' => true),
|
||||
array('type' => 'INVOICE',
|
||||
'id' => $credit['StatementEntry']['transaction_id'],
|
||||
'account_id' => $this->Account->accountReceivableAccountID(),
|
||||
'crdr' => 'CREDIT',
|
||||
'customer_id' => $charge['StatementEntry']['customer_id'],
|
||||
'lease_id' => $charge['StatementEntry']['lease_id'],
|
||||
),
|
||||
array
|
||||
(array('type' => $disbursement_type,
|
||||
'effective_date' => $disbursement_edate,
|
||||
'account_id' => $credit['StatementEntry']['account_id'],
|
||||
'amount' => $disbursement_amount,
|
||||
'charge_entry_id' => $charge['StatementEntry']['id'],
|
||||
),
|
||||
));
|
||||
|
||||
$ret['Disbursement'][] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
else {
|
||||
// Receipt Credit
|
||||
|
||||
if (strtotime($charge['StatementEntry']['effective_date']) >
|
||||
strtotime($credit['Transaction']['stamp']))
|
||||
$disbursement_edate = $charge['StatementEntry']['effective_date'];
|
||||
else
|
||||
$disbursement_edate = $credit['Transaction']['stamp'];
|
||||
|
||||
// Add a disbursement that uses the available credit to pay the charge
|
||||
$disbursement =
|
||||
array('type' => $disbursement_type,
|
||||
'effective_date' => $disbursement_edate,
|
||||
'amount' => $disbursement_amount,
|
||||
'account_id' => $credit['LedgerEntry']['account_id'],
|
||||
'transaction_id' => $credit['Transaction']['id'],
|
||||
'customer_id' => $charge['StatementEntry']['customer_id'],
|
||||
'lease_id' => $charge['StatementEntry']['lease_id'],
|
||||
'charge_entry_id' => $charge['StatementEntry']['id'],
|
||||
'comment' => null,
|
||||
);
|
||||
|
||||
$this->pr(20, compact('disbursement'), 'New Disbursement Entry');
|
||||
$result = $this->addStatementEntry($disbursement);
|
||||
$ret['Disbursement'][] = $result;
|
||||
if ($result['error'])
|
||||
$ret['error'] = true;
|
||||
}
|
||||
|
||||
// Adjust the charge balance to reflect the new disbursement
|
||||
$charge['balance'] = round($charge['balance'] - $disbursement_amount, 2);
|
||||
$this->pr(20, compact('charge', 'disbursement_amount'),
|
||||
($charge['balance'] > 0 ? 'Unfinished' : 'Fully Paid') . ' Charge');
|
||||
|
||||
if ($charge['balance'] < 0)
|
||||
die("HOW DID WE GET A NEGATIVE CHARGE AMOUNT?");
|
||||
}
|
||||
// Break the $credit reference to avoid future problems
|
||||
unset($credit);
|
||||
}
|
||||
|
||||
$this->pr(18, compact('credits'),
|
||||
'Disbursements complete');
|
||||
|
||||
// Clean up any explicit credits that have been used
|
||||
foreach ($credits AS $credit) {
|
||||
if (!empty($credit['receipt']))
|
||||
continue;
|
||||
|
||||
if (empty($credit['applied']))
|
||||
continue;
|
||||
|
||||
if ($credit['balance'] > 0) {
|
||||
$this->pr(20, compact('credit'),
|
||||
'Update Credit Entry');
|
||||
|
||||
$this->id = $credit['StatementEntry']['id'];
|
||||
$this->saveField('amount', $credit['balance']);
|
||||
}
|
||||
else {
|
||||
$this->pr(20, compact('credit'),
|
||||
'Delete Exhausted Credit Entry');
|
||||
|
||||
$this->delete($credit['StatementEntry']['id'], false);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for any implicit receipt credits, converting
|
||||
// into explicit credits if there is a remaining balance.
|
||||
foreach ($credits AS $credit) {
|
||||
if (empty($credit['receipt']))
|
||||
continue;
|
||||
|
||||
if (empty($credit['balance']))
|
||||
continue;
|
||||
|
||||
// See if there is an existing explicit credit
|
||||
// for this transaction.
|
||||
$explicit_credit = $this->find
|
||||
('first', array('contain' => false,
|
||||
'conditions' =>
|
||||
array(array('transaction_id' => $credit['Transaction']['id']),
|
||||
array('type' => 'SURPLUS')),
|
||||
));
|
||||
|
||||
if (!empty($explicit_credit)) {
|
||||
// REVISIT <AP>: 20090815
|
||||
// Testing whether or not this case occurs
|
||||
$this->INTERNAL_ERROR('Existing explicit credit unexpected');
|
||||
|
||||
// Since there IS an existing explicit credit, we must update
|
||||
// its balance instead of creating a new one, since it has
|
||||
// already been incorporated in the overall credit balance.
|
||||
// If we were to create a new one, we would erroneously create
|
||||
// an excess of credit available.
|
||||
$this->pr(18, compact('explicit_credit', 'credit'),
|
||||
'Update existing explicit credit');
|
||||
$EC = new StatementEntry();
|
||||
$EC->id = $explicit_credit['StatementEntry']['id'];
|
||||
$EC->saveField('amount', $credit['balance']);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($ret['receipt_balance']))
|
||||
$this->INTERNAL_ERROR('Only one receipt expected in assignCredits');
|
||||
|
||||
// Give caller the information necessary to create an explicit
|
||||
// credit from the passed receipt, which we've not exhausted.
|
||||
$this->pr(18, compact('credit'), 'Convert to explicit credit');
|
||||
$ret['receipt_balance'] = $credit['balance'];
|
||||
}
|
||||
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns summary data from the requested statement entry
|
||||
*/
|
||||
function stats($id = null, $query = null) {
|
||||
//$this->prFunctionLevel(array('log' => 16, 'show' => 10));
|
||||
$this->prEnter(compact('id', 'query'));
|
||||
|
||||
$this->queryInit($query);
|
||||
unset($query['group']);
|
||||
|
||||
$stats = array();
|
||||
if (isset($id))
|
||||
$query['conditions'][] = array('StatementEntry.id' => $id);
|
||||
|
||||
$types = array('Charge', 'Disbursement');
|
||||
foreach ($types AS $type_index => $this_name) {
|
||||
$that_name = $types[($type_index + 1) % 2];
|
||||
if ($this_name === 'Charge') {
|
||||
$this_types = $this->debitTypes();
|
||||
$that_types = $this->creditTypes();
|
||||
} else {
|
||||
$this_types = $this->creditTypes();
|
||||
$that_types = $this->debitTypes();
|
||||
}
|
||||
|
||||
$this_query = $query;
|
||||
$this_query['fields'] = array();
|
||||
$this_query['fields'][] = "SUM(StatementEntry.amount) AS total";
|
||||
$this_query['conditions'][] = array('StatementEntry.type' => $this_types);
|
||||
$result = $this->find('first', $this_query);
|
||||
$stats[$this_name] = $result[0];
|
||||
|
||||
$this->pr(17, compact('this_query', 'result'), $this_name.'s');
|
||||
|
||||
// Tally the different types that result in credits towards the charges
|
||||
$stats[$this_name]['reconciled'] = 0;
|
||||
foreach ($that_types AS $that_type) {
|
||||
$lc_that_type = strtolower($that_type);
|
||||
$that_query = $this_query;
|
||||
$that_query['link']["{$that_name}Entry"] = array('fields' => array());
|
||||
$that_query['fields'] = array();
|
||||
if ($this_name == 'Charge')
|
||||
$that_query['fields'][] = "COALESCE(SUM(${that_name}Entry.amount),0) AS $lc_that_type";
|
||||
else
|
||||
$that_query['fields'][] = "COALESCE(SUM(StatementEntry.amount), 0) AS $lc_that_type";
|
||||
$that_query['conditions'][] = array("{$that_name}Entry.type" => $that_type);
|
||||
$result = $this->find('first', $that_query);
|
||||
$stats[$this_name] += $result[0];
|
||||
|
||||
$this->pr(17, compact('that_query', 'result'), "{$this_name}s: $that_type");
|
||||
$stats[$this_name]['reconciled'] += $stats[$this_name][$lc_that_type];
|
||||
}
|
||||
|
||||
// Compute balance information for charges
|
||||
$stats[$this_name]['balance'] =
|
||||
$stats[$this_name]['total'] - $stats[$this_name]['reconciled'];
|
||||
if (!isset($stats[$this_name]['balance']))
|
||||
$stats[$this_name]['balance'] = 0;
|
||||
}
|
||||
|
||||
// 'balance' is simply the difference between
|
||||
// the balances of charges and disbursements
|
||||
$stats['balance'] = $stats['Charge']['balance'] - $stats['Disbursement']['balance'];
|
||||
if (!isset($stats['balance']))
|
||||
$stats['balance'] = 0;
|
||||
|
||||
// 'account_balance' is really only relevant to
|
||||
// callers that have requested charge and disbursement
|
||||
// stats with respect to a particular account.
|
||||
// It represents the difference between inflow
|
||||
// and outflow from that account.
|
||||
$stats['account_balance'] = $stats['Charge']['reconciled'] - $stats['Disbursement']['total'];
|
||||
if (!isset($stats['account_balance']))
|
||||
$stats['account_balance'] = 0;
|
||||
|
||||
return $this->prReturn($stats);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
<?php
|
||||
class Tender extends AppModel {
|
||||
|
||||
var $belongsTo = array(
|
||||
'TenderType',
|
||||
'Customer',
|
||||
'LedgerEntry',
|
||||
'DepositTransaction' => array(
|
||||
'className' => 'Transaction',
|
||||
),
|
||||
'DepositLedgerEntry' => array(
|
||||
'className' => 'LedgerEntry',
|
||||
),
|
||||
'NsfTransaction' => array(
|
||||
'className' => 'Transaction',
|
||||
'dependent' => true,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: afterSave
|
||||
* - Performs any work needed after the save occurs
|
||||
*/
|
||||
|
||||
function afterSave($created) {
|
||||
// Come up with a (not necessarily unique) name for the tender.
|
||||
// For checks & money orders, this will be based on the check
|
||||
// number. For other types of tender, we'll just use the
|
||||
// generic name of the tender type, and the tender ID
|
||||
|
||||
// Determine our tender type, and set the ID of that model
|
||||
$this->TenderType->id = $this->field('tender_type_id');
|
||||
|
||||
// REVISIT <AP>: 20090810
|
||||
// The only tender expected to have no tender type
|
||||
// is our special "Closing" tender.
|
||||
if (empty($this->TenderType->id))
|
||||
$newname = 'Closing';
|
||||
else {
|
||||
$newname = $this->TenderType->field('name');
|
||||
$naming_field = $this->TenderType->field('naming_field');
|
||||
if (!empty($naming_field))
|
||||
$newname .= ' #' . $this->field($naming_field);
|
||||
}
|
||||
|
||||
if ($newname !== $this->field('name'))
|
||||
$this->saveField('name', $newname);
|
||||
|
||||
return parent::afterSave($created);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: beforeDelete
|
||||
* - Performs any work needed before the delete occurs
|
||||
*/
|
||||
|
||||
function beforeDelete($cascade = true) {
|
||||
// REVISIT <AP>: 20090814
|
||||
// Experimental, and incomplete mechanism to protect
|
||||
// against trying to delete data that shouldn't be deleted.
|
||||
|
||||
$deposit_id = $this->field('deposit_transaction_id');
|
||||
pr(compact('deposit_id'));
|
||||
// If this tender has already been deposited, it would
|
||||
// be a rats nest to figure out how to delete this tender.
|
||||
if (!empty($deposit_id))
|
||||
return false;
|
||||
|
||||
return parent::beforeDelete($cascade);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: verifyTender
|
||||
* - Verifies consistenty of new tender data
|
||||
* (not in a pre-existing tender)
|
||||
*/
|
||||
function verifyTender($tender) {
|
||||
$this->prFunctionLevel(10);
|
||||
$this->prEnter(compact('tender'));
|
||||
|
||||
if (empty($tender['tender_type_id'])) {
|
||||
return $this->prReturn(false);
|
||||
}
|
||||
|
||||
return $this->prReturn(true);
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: addTender
|
||||
* - Inserts new Tender into the database
|
||||
*/
|
||||
|
||||
function addTender($tender) {
|
||||
$this->prEnter(compact('tender'));
|
||||
|
||||
$ret = array('data' => $tender);
|
||||
if (!$this->verifyTender($tender))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
$this->create();
|
||||
if (!$this->save($tender))
|
||||
return $this->prReturn(array('error' => true) + $ret);
|
||||
|
||||
$ret['tender_id'] = $this->id;
|
||||
return $this->prReturn($ret + array('error' => false));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: nsf
|
||||
* - Flags the ledger entry as having insufficient funds
|
||||
*/
|
||||
|
||||
function nsf($id, $stamp = null, $comment = null) {
|
||||
$this->prEnter(compact('id', 'stamp', 'comment'));
|
||||
|
||||
// Get information about this NSF item.
|
||||
$this->id = $id;
|
||||
$tender = $this->find
|
||||
('first', array
|
||||
('contain' =>
|
||||
array('LedgerEntry',
|
||||
'DepositTransaction',
|
||||
'DepositLedgerEntry',
|
||||
'NsfTransaction'),
|
||||
));
|
||||
$this->pr(20, compact('tender'));
|
||||
|
||||
if (!empty($tender['NsfTransaction']['id']))
|
||||
die("Item has already been set as NSF");
|
||||
|
||||
if (empty($tender['DepositTransaction']['id']))
|
||||
die("Item has not been deposited yet");
|
||||
|
||||
$tender['Transaction'] = $tender['DepositTransaction'];
|
||||
unset($tender['DepositTransaction']);
|
||||
unset($tender['NsfTransaction']);
|
||||
|
||||
$T = new Transaction();
|
||||
$result = $T->addNsf($tender, $stamp, $comment);
|
||||
if (empty($result['error'])) {
|
||||
// Flag the tender as NSF, using the items created from addNsf
|
||||
$this->id = $id;
|
||||
$this->saveField('nsf_transaction_id', $result['nsf_transaction_id']);
|
||||
$this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']);
|
||||
}
|
||||
|
||||
return $this->prReturn($result);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
class TenderType extends AppModel {
|
||||
|
||||
var $belongsTo = array(
|
||||
'Account',
|
||||
);
|
||||
|
||||
var $hasMany = array(
|
||||
'Tender',
|
||||
);
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: accountID
|
||||
* - Returns the intended account ID for receipt of the given tender
|
||||
*/
|
||||
|
||||
function accountID($id) {
|
||||
$this->cacheQueries = true;
|
||||
$item = $this->find('first', array
|
||||
('contain' => false,
|
||||
'conditions' => array('TenderType.id' => $id),
|
||||
));
|
||||
$this->cacheQueries = false;
|
||||
return $item['TenderType']['account_id'];
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: paymentTypes
|
||||
* - Returns an array of types that can be used for payments
|
||||
*/
|
||||
|
||||
function paymentTypes($query = null) {
|
||||
$this->queryInit($query);
|
||||
$query['order'][] = 'name';
|
||||
|
||||
$this->cacheQueries = true;
|
||||
$types = $this->find('all', $query);
|
||||
$this->cacheQueries = false;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: paymentTypes
|
||||
* - Returns an array of types that can be deposited
|
||||
*/
|
||||
|
||||
function depositTypes($query = null) {
|
||||
$this->queryInit($query);
|
||||
$query['order'][] = 'name';
|
||||
$query['conditions'][] = array('tillable' => true);
|
||||
|
||||
$this->cacheQueries = true;
|
||||
$types = $this->find('all', $query);
|
||||
$this->cacheQueries = false;
|
||||
|
||||
// Rearrange to be of the form (id => name)
|
||||
$result = array();
|
||||
foreach ($types AS $type)
|
||||
$result[$type['TenderType']['id']] = $type['TenderType']['name'];
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: defaultPaymentType
|
||||
* - Returns the ID of the default payment type
|
||||
*/
|
||||
|
||||
function defaultPaymentType() {
|
||||
return $this->nameToID('Check');
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* function: stats
|
||||
* - Returns the stats for the given tender type
|
||||
*/
|
||||
|
||||
function stats($id = null, $query = null) {
|
||||
if (!$id)
|
||||
return null;
|
||||
|
||||
$this->queryInit($query);
|
||||
|
||||
if (!isset($query['link']['Tender']))
|
||||
$query['link']['Tender'] = array('fields' => array());
|
||||
if (!isset($query['link']['Tender']['LedgerEntry']))
|
||||
$query['link']['Tender']['LedgerEntry'] = array('fields' => array());
|
||||
|
||||
$query['fields'][] = "SUM(COALESCE(LedgerEntry.amount,0)) AS 'total'";
|
||||
$query['fields'][] = "SUM(IF(deposit_transaction_id IS NULL, COALESCE(LedgerEntry.amount,0), 0)) AS 'undeposited'";
|
||||
$query['fields'][] = "SUM(IF(deposit_transaction_id IS NULL, 0, COALESCE(LedgerEntry.amount,0))) AS 'deposited'";
|
||||
$query['fields'][] = "SUM(IF(nsf_transaction_id IS NULL, 0, COALESCE(LedgerEntry.amount,0))) AS 'nsf'";
|
||||
|
||||
$this->id = $id;
|
||||
$stats = $this->find('first', $query);
|
||||
return $stats[0];
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user