Compare commits

..

2 Commits

509 changed files with 29404 additions and 8342 deletions

View File

@@ -1,51 +0,0 @@
Book Keeping Challenges / Issues
- Chart of Accounts is not sufficient
- One payment can go towards more than one charge
- One charge can be paid for by more than one payment
- Need to know: how much money does customer owe?
- Need to know: how much money has customer been charged for "Rent"?
- Need to know: how much money has customer paid towards "Rent" (nothing else)?
- Reverse a charge
To make charge reversal work, I'm presently issuing a credit note
(transaction) that has 3 ledger entries:
Debit charged account - Credit A/R
Debit A/R - Credit "Credit" account
Debit "Credit" account - Credit A/R
And 3 statement entries:
Reversal on charged account
Negative Disbursement on "Credit" account
Positive Disbursement on "Credit" account
Obviously, the two "Credit" account ledger entries cancel each other
out. However, the monies need to be reversed in the A/R account, and a
previous transaction will have already performed an A/R credit and so
the two A/R credits will create an imbalance in A/R unless we move
those funds to our "Credit" account. The "Credit" account statement
entries are needed to undo any previous disbursement to the charge
being reversed, and then to re-disburse those funds to a different
charge (or possibly just a Surplus entry if no other charges exist.)
Question
- What should be recorded with this charge reversal?
Charge of $5 for "Parking"
Charge of $6 for "Rent"
Payment of $6
Reverse the $5 "Parking" charge
- What should be recorded with this charge reversal?
Charge of $5 for "Parking"
Charge of $6 for "Rent"
Charge of $7 for "Pets"
Payment of $13
Reverse the $5 "Parking" charge
- What should be recorded with this charge reversal?
Charge of $5 for "Parking"
Charge of $6 for "Rent"
Charge of $7 for "Pets"
Payment of $18
Reverse the $5 "Parking" charge

View File

@@ -1,3 +1,3 @@
@echo off
mysql --user=pmgr --password=pmgruser < %~dp0\db\property_manager.sql
%~dp0\scripts\sitelink2pmgr.pl %~dp0\db\schema.sql %~dp0db\vss.mdb %*
echo Done!

View File

@@ -1 +0,0 @@
Please see previous revisions on /tags/v0.1.0

View File

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

View File

@@ -1,578 +0,0 @@
-- Delete bad transaction(s)
DELETE M
FROM
pmgr_ledger_entries LE,
pmgr_tenders M
WHERE
M.ledger_entry_id = LE.id AND
LE.transaction_id
IN (467);
DELETE LE
FROM
pmgr_ledger_entries LE
WHERE
LE.transaction_id
IN (467);
DELETE SE
FROM
pmgr_statement_entries SE
WHERE
SE.transaction_id
IN (467);
DELETE T
FROM
pmgr_transactions T
WHERE
T.id
IN (467);
-- Delete bad transaction, one variable setting
SET @tid = 467;
DELETE M FROM pmgr_ledger_entries LE, pmgr_tenders M
WHERE M.ledger_entry_id = LE.id AND LE.transaction_id = @tid;
DELETE LE FROM pmgr_ledger_entries LE
WHERE LE.transaction_id = @tid;
DELETE SE FROM pmgr_statement_entries SE
WHERE SE.transaction_id = @tid;
DELETE T FROM pmgr_transactions T
WHERE T.id = @tid;
-- Delete all but one customer
SET @cid = 6;
-- DELETE T FROM pmgr_transactions T
-- LEFT JOIN pmgr_customers C ON C.id = T.customer_id
-- WHERE C.id IS NOT NULL AND C.id <> @cid;
DELETE C FROM pmgr_customers C
WHERE C.id <> @cid;
DELETE L FROM pmgr_leases L
LEFT JOIN pmgr_customers C ON C.id = L.customer_id
WHERE C.id IS NULL;
DELETE T FROM pmgr_transactions T
LEFT JOIN pmgr_customers C ON C.id = T.customer_id
WHERE C.id IS NULL;
DELETE SE FROM pmgr_statement_entries SE
LEFT JOIN pmgr_customers C ON C.id = SE.customer_id
WHERE C.id IS NULL;
DELETE LE FROM pmgr_ledger_entries LE
LEFT JOIN pmgr_transactions T ON T.id = LE.transaction_id
WHERE T.id IS NULL;
DELETE M FROM pmgr_tenders M
LEFT JOIN pmgr_ledger_entries LE ON M.ledger_entry_id = LE.id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
WHERE LE.id IS NULL;
UPDATE pmgr_ledger_entries LE, pmgr_ledgers L, pmgr_accounts A
SET LE.ledger_id = L.id
WHERE A.id = LE.account_id AND L.account_id = A.id AND L.sequence = 1;
DELETE FROM pmgr_ledgers WHERE sequence > 1;
UPDATE pmgr_ledgers SET prior_ledger_id = NULL, close_transaction_id = NULL;
-- Delete a ledger entry, associated double entry, and matching ledger_entry
SET @leid = 1365;
DELETE FROM pmgr_ledger_entries WHERE id = @leid;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.debit_entry_id
WHERE LE.id IS NULL;
DELETE DE FROM pmgr_double_entries DE
LEFT JOIN pmgr_ledger_entries LE ON LE.id = DE.credit_entry_id
WHERE LE.id IS NULL;
DELETE LE FROM pmgr_ledger_entries LE
LEFT JOIN pmgr_double_entries DE
ON DE.credit_entry_id = LE.id OR DE.debit_entry_id = LE.id
WHERE DE.id IS NULL;
-- Add and update every Tender.ledger_entry_id (for rolling up old databases)
-- Takes a while to complete (~30s at time of writing)
ALTER TABLE `pmgr_tenders`
ADD `deposit_ledger_entry_id` INT UNSIGNED DEFAULT NULL
AFTER `nsf_ledger_entry_id`;
UPDATE
pmgr_tenders Tnd
JOIN pmgr_tender_types TndT ON TndT.id = Tnd.tender_type_id
JOIN pmgr_transactions T ON T.id = Tnd.deposit_transaction_id
JOIN pmgr_ledger_entries LE ON LE.transaction_id = T.id AND LE.account_id = TndT.account_id
JOIN pmgr_double_entries DE ON DE.debit_entry_id = LE.id OR DE.credit_entry_id = LE.id
JOIN pmgr_ledger_entries LEd ON (DE.debit_entry_id = LEd.id OR DE.credit_entry_id = LEd.id)
AND LEd.id <> LE.id
SET Tnd.deposit_ledger_entry_id = LEd.id;
-- Add auto_deposit and deposit_account_id to tenders
ALTER TABLE `pmgr_tender_types`
ADD `auto_deposit` TINYINT(1) UNSIGNED DEFAULT '0' NOT NULL
AFTER `tillable`;
ALTER TABLE `pmgr_tender_types`
ADD `deposit_account_id` INTEGER(10) UNSIGNED DEFAULT NULL
AFTER `account_id`;
-- Determine economic conditions
SELECT `status`, COUNT(id), SUM(rent) FROM pmgr_units
GROUP BY `status` WITH ROLLUP;
-- Check that transaction totals add up correctly
SELECT T.id, T.type, T.amount,
-- T.type, A.type, E.crdr,
SUM(IF(E.account_id = T.account_id,
IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1),0)
*E.amount) AS Tamt,
SUM(IF(E.account_id = T.account_id,
0,IF(A.type IN ('ASSET','EXPENSE') XOR E.crdr='DEBIT',-1,1))
*E.amount) AS Oamt,
COUNT(E.id) AS Ecnt
FROM pmgr_transactions T
-- LEFT JOIN pmgr_statement_entries E ON E.transaction_id = T.id
LEFT JOIN pmgr_ledger_entries E ON E.transaction_id = T.id
LEFT JOIN pmgr_accounts A ON A.id = T.account_id -- E.account_id
-- WHERE
-- E.account_id != T.account_id
GROUP BY T.id
HAVING
(T.type = 'INVOICE' AND Tamt <> T.amount)
OR
(T.type <> 'INVOICE' AND Oamt <> T.amount)
OR
(Tamt * -1 <> Oamt)
-- Verify that statement entries all have the correct type
SELECT SE.id, SE.type, T.id, T.type
FROM pmgr_statement_entries SE
LEFT JOIN pmgr_transactions T ON T.id = SE.transaction_id
WHERE
((T.type = 'RECEIPT' OR T.type = 'CREDIT_NOTE') AND
SE.type NOT IN ('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS')
)
OR
((T.type = 'INVOICE' OR T.type = 'PAYMENT') AND
SE.type NOT IN ('CHARGE', 'PAYMENT', 'REFUND')
)
-- catch other types not considered in this query
OR T.type NOT IN ('RECEIPT', 'CREDIT_NOTE', 'INVOICE', 'PAYMENT')
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- #################################################################
-- ## USER / GROUP
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
VALUES('Owner', 'Owner Group', 25);
SET @o_gid = LAST_INSERT_ID();
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
VALUES('Admin', 'Admin Group', 50);
SET @a_gid = LAST_INSERT_ID();
INSERT INTO pmgr_groups (`code`, `name`, `rank`)
VALUES('Manager', 'Manager Group', 75);
SET @m_gid = LAST_INSERT_ID();
INSERT INTO pmgr_groups (`code`, `name`)
VALUES('Temp', 'Temporary Help');
SET @t_gid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('AP', 'abijah', 0);
SET @a_uid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('SK', 'shirley', 0);
SET @s_uid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('DE', 'dan', 0);
SET @d_uid = LAST_INSERT_ID();
INSERT INTO pmgr_users (`code`, `login`, `contact_id`)
VALUES('KD', 'kevin', 0);
SET @k_uid = LAST_INSERT_ID();
INSERT INTO pmgr_sites (`code`, `name`)
VALUES('VSS', 'Valley Storage');
SET @v_sid = LAST_INSERT_ID();
INSERT INTO pmgr_sites (`code`, `name`)
VALUES('FAKE', 'Fake Site');
SET @f_sid = LAST_INSERT_ID();
-- Site Membership
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @a_uid, @o_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @a_uid, @a_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @a_uid, @m_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @s_uid, @m_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@v_sid, @d_uid, @t_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @s_uid, @a_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @s_uid, @m_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @k_uid, @o_gid);
INSERT INTO pmgr_site_memberships (`site_id`, `user_id`, `group_id`)
VALUES(@f_sid, @d_uid, @t_gid);
-- Options
INSERT INTO pmgr_options (`name`) VALUES ('theme');
SET @t_oid = LAST_INSERT_ID();
INSERT INTO pmgr_options (`name`) VALUES ('menu');
SET @m_oid = LAST_INSERT_ID();
-- Default Option Values
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'blue');
INSERT INTO pmgr_default_options (`option_value_id`) VALUES(LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'basic');
INSERT INTO pmgr_default_options (`option_value_id`) VALUES(LAST_INSERT_ID());
-- Group options
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'gold');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@o_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'silver');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@a_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'red');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@m_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'advanced');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@o_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'advanced');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@a_gid, LAST_INSERT_ID());
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'restricted');
INSERT INTO pmgr_group_options (`group_id`, `option_value_id`)
VALUES(@t_gid, LAST_INSERT_ID());
-- User Options
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@m_oid, 'special');
INSERT INTO pmgr_user_options (`user_id`, `option_value_id`)
VALUES(@s_uid, LAST_INSERT_ID());
-- Site Options
INSERT INTO pmgr_option_values (`option_id`, `value`) VALUES (@t_oid, 'site-theme');
INSERT INTO pmgr_site_options (`site_id`, `option_value_id`)
VALUES(@f_sid, LAST_INSERT_ID());
-- SELECT U.id, P.name, MAX(P.access)
-- FROM pmgr_users U
-- LEFT JOIN pmgr_site_membership M ON M.user_id = U.id
-- LEFT JOIN pmgr_groups G ON G.id = M.group_id
-- LEFT JOIN pmgr_group_permissions P ON P.group_id = G.id
-- GROUP BY U.id, P.name
-- User access to site
SELECT U.id, U.login, COUNT(G.id) AS 'groups', MIN(G.rank) AS highest_rank
FROM pmgr_users U
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
JOIN pmgr_groups G ON G.id = M.group_id
WHERE S.code = 'VSS'
GROUP BY U.id
-- User Options
SELECT O.id, O.name, O.default,
GROUP_CONCAT(Uopt.value) AS 'value', COUNT(U.id) AS 'count'
FROM pmgr_options O
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
WHERE U.id = 1
GROUP BY O.id
-- Group Options
SELECT O.id, O.name, O.default,
GROUP_CONCAT(Gopt.value) AS 'value', COUNT(G.id) AS 'count'
FROM pmgr_options O
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
WHERE G.id = 1
GROUP BY O.id
-- Site Options
SELECT O.id, O.name, O.default,
GROUP_CONCAT(Sopt.value) AS 'value', COUNT(S.id) AS 'count'
FROM pmgr_options O
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
WHERE S.id = 1
GROUP BY O.id
-- Option value for member & site
SELECT O.id, O.name, O.default,
S.id AS site_id, Sopt.value,
G.id AS group_id, Gopt.value,
U.id AS user_id, Uopt.value
FROM pmgr_options O
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
WHERE O.name = 'theme'
--GROUP BY O.id
-- Option value for member & site
-- 1) User
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, U.id, Uopt.value
FROM pmgr_options O
JOIN pmgr_user_options Uopt ON Uopt.option_id = O.id
JOIN pmgr_users U ON U.id = Uopt.user_id
-- JOIN pmgr_site_memberships M ON M.user_id = U.id
-- JOIN pmgr_groups G ON G.id = M.group_id
-- JOIN pmgr_sites S ON S.id = M.site_id
WHERE -- S.id = @sid AND
U.id = @uid AND O.id = @oid
;
-- 2) Group
SELECT O.name, G.rank, G.id, Gopt.value
FROM pmgr_options O
JOIN pmgr_group_options Gopt ON Gopt.option_id = O.id
JOIN pmgr_groups G ON G.id = Gopt.group_id
JOIN pmgr_site_memberships M ON M.group_id = G.id
JOIN pmgr_users U ON U.id = M.user_id
JOIN pmgr_sites S ON S.id = M.site_id
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY G.rank
;
-- 3) Site
SELECT O.name, S.id, Sopt.value
FROM pmgr_options O
JOIN pmgr_site_options Sopt ON Sopt.option_id = O.id
JOIN pmgr_sites S ON S.id = Sopt.site_id
-- JOIN pmgr_site_memberships M ON M.site_id = S.id
-- JOIN pmgr_groups G ON G.id = M.group_id
-- JOIN pmgr_users U ON U.id = M.user_id
WHERE S.id = @sid
-- AND U.id = @uid
AND O.id = @oid
;
-- 3) Default
SELECT O.name, O.default AS 'value'
FROM pmgr_options O
WHERE O.id = @oid
;
-- User Permissions
-- Group Permissions
-- All option values, in order
SELECT O.name, V.value,
U.id AS uid, G.id AS gid, S.id as sid,
Dopt.id AS did, G.rank
FROM pmgr_option_values V
JOIN pmgr_options O ON O.id = V.option_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
WHERE O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
-- Option values relevant to the user and site, in order
SELECT O.name, V.value,
U.id AS uid, G.id AS gid, S.id as sid,
Dopt.id AS did, G.rank
FROM pmgr_option_values V
JOIN pmgr_options O ON O.id = V.option_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
JOIN pmgr_site_memberships M ON M.user_id = U.id AND M.site_id = S.id
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, V.value,
U.id AS uid,
-- G.id AS gid,
S.id as sid,
Dopt.id AS did
-- G.rank
FROM pmgr_option_values V
JOIN pmgr_options O ON O.id = V.option_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
-- LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
-- LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_default_options Dopt ON Dopt.option_value_id = V.id
-- LEFT JOIN pmgr_groups G ON G.id = Gopt.group_id
LEFT JOIN pmgr_users U ON U.id = Uopt.user_id
LEFT JOIN pmgr_sites S ON S.id = Sopt.site_id
JOIN pmgr_site_memberships M ON M.user_id = U.id -- AND M.site_id = S.id
WHERE -- S.id = @sid AND U.id = @uid AND
O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
-- IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4)) -- ) ASC,
-- IF (G.id IS NOT NULL, G.rank, 0) ASC
-- ------------------------------------------------------------
-- ------------------------------------------------------------
-- ------------------------------------------------------------
-- Working version (without defaults)
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
U.id AS uid,
G.id AS gid,
S.id AS sid,
-- Dopt.id AS did
G.rank
FROM pmgr_users U
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
LEFT JOIN pmgr_groups G ON G.id = M.group_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.user_id = U.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.group_id = G.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.site_id = S.id
LEFT JOIN pmgr_option_values V ON (V.id = Uopt.option_value_id OR
V.id = Gopt.option_value_id OR
V.id = Sopt.option_value_id)
JOIN pmgr_options O ON O.id = V.option_id
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
;
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
U.id AS uid,
G.id AS gid,
S.id AS sid,
-- Dopt.id AS did
G.rank
FROM pmgr_options O
LEFT JOIN pmgr_option_values V ON V.option_id = O.id
-- Now have the option and all possible values
LEFT JOIN pmgr_user_options Uopt ON Uopt.option_value_id = V.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.option_value_id = V.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.option_value_id = V.id
-- Now have the user/group/site that each value applies to
LEFT JOIN pmgr_users U U ON Uopt.user_id = U.id OR Uopt.user_id IS NULL
-- Now restricted to our user
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
ON O.id = V.option_id
LEFT JOIN pmgr_groups G ON G.id = M.group_id
LEFT JOIN pmgr_option_values V ON (V.id = Uopt.option_value_id OR
V.id = Gopt.option_value_id OR
V.id = Sopt.option_value_id)
JOIN
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
;
SET @sid = 1;
SET @uid = 1;
SET @oid = 1;
SELECT O.name, O.id AS oid, V.value, V.id AS vid,
U.id AS uid,
G.id AS gid,
S.id AS sid,
-- Dopt.id AS did
G.rank
FROM pmgr_options O LEFT JOIN pmgr_option_values V ON V.option_id = O.id,
pmgr_users U
JOIN pmgr_site_memberships M ON M.user_id = U.id
JOIN pmgr_sites S ON S.id = M.site_id
LEFT JOIN pmgr_groups G ON G.id = M.group_id
LEFT JOIN pmgr_user_options Uopt ON Uopt.user_id = U.id
LEFT JOIN pmgr_group_options Gopt ON Gopt.group_id = G.id
LEFT JOIN pmgr_site_options Sopt ON Sopt.site_id = S.id,
WHERE S.id = @sid AND U.id = @uid AND O.id = @oid
AND (V.id = Uopt.option_value_id OR
V.id = Gopt.option_value_id OR
V.id = Sopt.option_value_id)
ORDER BY IF(U.id IS NOT NULL, 1,
IF (G.id IS NOT NULL, 2,
IF (S.id IS NOT NULL, 3, 4))) ASC,
IF (G.id IS NOT NULL, G.rank, 0) ASC
;

View File

@@ -37,7 +37,7 @@ Operations to be functional
X - Create Customer ID/Account
X - Add Contact information to Customer
X - Move Customer into Unit
X - Enter Rent Concessions given
? - Enter Rent Concessions given
X - Asses Rent Charges
X - Asses Late Charges
X - Asses Security Deposits
@@ -45,11 +45,11 @@ Operations to be functional
X - Receive and record Money Orders
X - Receive and record Cash
X - Receive and record ACH Deposits
X - Reverse rent charges (early moveout on prepaid occupancy)
? - Reverse rent charges (early moveout on prepaid occupancy)
X - Handle NSF checks
X - Assess NSF Fees
X - Determine Lease Paid-Through status
X - Report: List of customers overdue
- Report: List of customers overdue
X - Flag unit as overlocked
X - Flag unit as evicting
X - Flag unit as normal status

1572
scripts/sitelink2pmgr.pl Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -2,24 +2,4 @@
RewriteEngine on
RewriteRule ^$ webroot/ [L]
RewriteRule (.*) webroot/$1 [L]
</IfModule>
# Lets deny everyone -- its a clean slate!
order deny,allow
deny from all
# Now allow local access
# Localhost
# allow from 127.0.0
# Local subnet
# allow from 192.168.7
# Provide a mechanism for user authentication
AuthType Digest
AuthName "Property Manager"
AuthUserFile "D:/Website/auth/pmgr.htpasswd"
Require valid-user
# Instead of satisfy all (too restrictive)
# This allows EITHER local domain OR authenticated user
satisfy any
</IfModule>

View File

@@ -35,397 +35,51 @@
* @subpackage cake.app
*/
class AppController extends Controller {
var $uses = array('Option', 'Permission');
var $helpers = array('Html', 'Form', 'Javascript', 'Format', 'Time', 'Grid');
var $components = array('DebugKit.Toolbar');
var $sidemenu = array('areas' => array('SITE' => false, 'CONTROLLER' => false, 'ACTION' => false, 'SANDBOX' => false));
var $std_area = 10;
var $admin_area = 20;
var $dev_area = 30;
var $op_area = 40;
var $new_area = 50;
function __construct() {
$this->params['dev'] = false;
$this->params['admin'] = false;
parent::__construct();
function sideMenuLinks() {
return array(
array('name' => 'Common', 'header' => true),
array('name' => 'Site Map', 'url' => array('controller' => 'maps', 'action' => 'view', 1)),
array('name' => 'Units', 'url' => array('controller' => 'units', 'action' => 'index')),
array('name' => 'Leases', 'url' => array('controller' => 'leases', 'action' => 'index')),
array('name' => 'Customers', 'url' => array('controller' => 'customers', 'action' => 'index')),
array('name' => 'Accounts', 'url' => array('controller' => 'accounts', 'action' => 'index')),
array('name' => 'Debug', 'header' => true),
array('name' => 'Un-Nuke', 'url' => '#', 'htmlAttributes' =>
array('onclick' => '$(".pr-section").show(); return false;')),
array('name' => 'Contacts', 'url' => array('controller' => 'contacts', 'action' => 'index')),
array('name' => 'Ledgers', 'url' => array('controller' => 'ledgers', 'action' => 'index')),
array('name' => 'New Ledgers', 'url' => array('controller' => 'accounts', 'action' => 'newledger')),
array('name' => 'RESET DATA', 'url' => array('controller' => 'accounts', 'action' => 'reset_data')),
);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuAreaVerify
* - Verifies the validity of the sidemenu area/subarea/priority,
* and ensures the class member is set to appropriately handle it.
*/
function sideMenuAreaVerify(&$area, $subarea, $priority = null) {
$area = strtoupper($area);
if (!array_key_exists($area, $this->sidemenu['areas']))
$this->INTERNAL_ERROR("Sidemenu link '{$area}': Unknown");
if ($area == 'SITE')
$name = 'Navigation';
elseif ($area == 'CONTROLLER')
$name = Inflector::humanize($this->params['controller']);
elseif ($area == 'ACTION')
$name = Inflector::humanize(Inflector::singularize($this->params['controller']));
elseif ($area == 'SANDBOX')
$name = 'Sandbox';
if (empty($this->sidemenu['areas'][$area]))
$this->sidemenu['areas'][$area]
= array('enable' => true, 'name' => $name, 'subareas' => array());
if (empty($subarea))
return;
$subname = $name;
if ($subarea == $this->std_area)
$subname .= '';
elseif ($subarea == $this->op_area)
//$subname .= '-Ops';
$subname = 'Actions';
elseif ($subarea == $this->new_area)
//$subname .= '-New';
$subname = 'Creation';
elseif ($subarea == $this->admin_area)
$subname .= '-Admin';
elseif ($subarea == $this->dev_area)
$subname .= '-Dev';
else
$subname .= '-' . $subarea;
if (empty($this->sidemenu['areas'][$area]['subareas'][$subarea]))
$this->sidemenu['areas'][$area]['subareas'][$subarea]
= array('enable' => true, 'name' => $subname, 'priorities' => array());
if (empty($priority))
return;
if (empty($this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority]))
$this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority]
= array();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuAreaName
* - Sets the name of the sidemenu area/subarea
*/
function sideMenuAreaName($name, $area, $subarea = null) {
$this->sideMenuAreaVerify($area, $subarea);
if (empty($subarea))
$this->sidemenu['areas'][$area]['name'] = $name;
else
$this->sidemenu['areas'][$area]['subareas'][$subarea]['name'] = $name;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuAreaActivate
* - Sets the selected area/subarea to be active when the
* page is first loaded.
*/
function sideMenuAreaActivate($area, $subarea = null) {
$this->sidemenu['active'] = compact('area', 'subarea');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: sideMenuEnable
* - Enables/Disables an area or subarea of the sidemenu
*/
function sideMenuEnable($area, $subarea = null, $enable = true) {
$this->sideMenuAreaVerify($area, $subarea);
if (isset($subarea))
$this->sidemenu['areas'][$area]['subareas'][$subarea]['enable'] = $enable;
else
$this->sidemenu['areas'][$area]['enable'] = $enable;
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addSideMenuLink
* - Adds another link to the sidemenu area/subarea/priority
*/
function addSideMenuLink($name, $url, $extra, $area, $subarea = null, $priority = 10) {
if (empty($subarea))
$subarea = $this->std_area;
$this->sideMenuAreaVerify($area, $subarea);
$this->sidemenu['areas'][$area]['subareas'][$subarea]['priorities'][$priority][]
= array('name' => $name, 'url' => $url) + (empty($extra) ? array() : $extra);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: addDefaultSideMenuLinks
* - Adds the standard links present on all generated pages
*/
function addDefaultSideMenuLinks() {
$this->addSideMenuLink('Site Map',
array('controller' => 'maps', 'action' => 'view', 1), null,
'SITE');
$this->addSideMenuLink('Unit Sizes',
array('controller' => 'unit_sizes', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Units',
array('controller' => 'units', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Leases',
array('controller' => 'leases', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Customers',
array('controller' => 'customers', 'action' => 'index'), null,
'SITE');
$this->addSideMenuLink('Deposits',
array('controller' => 'transactions', 'action' => 'deposit'), null,
'SITE');
$this->addSideMenuLink('Accounts',
array('controller' => 'accounts', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Contacts',
array('controller' => 'contacts', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Ledgers',
array('controller' => 'ledgers', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Tenders',
array('controller' => 'tenders', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Transactions',
array('controller' => 'transactions', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Ldgr Entries',
array('controller' => 'ledger_entries', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Stmt Entries',
array('controller' => 'statement_entries', 'action' => 'index'), null,
'SITE', $this->admin_area);
$this->addSideMenuLink('Un-Nuke',
'#', array('htmlAttributes' =>
array('onclick' => '$(".pr-section").show(); return false;')),
'SITE', $this->dev_area);
$this->addSideMenuLink('New Ledgers',
array('controller' => 'accounts', 'action' => 'newledger'), null,
'SITE', $this->dev_area);
//array('name' => 'RESET DATA', array('controller' => 'accounts', 'action' => 'reset_data'));
$this->addSideMenuLink('New Receipt',
array('controller' => 'customers', 'action' => 'receipt'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('New Invoice',
array('controller' => 'leases', 'action' => 'invoice'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('Move-In',
array('controller' => 'customers', 'action' => 'move_in'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('Move-Out',
array('controller' => 'leases', 'action' => 'move_out'), null,
'SITE', $this->op_area);
$this->addSideMenuLink('New Deposit',
array('controller' => 'tenders', 'action' => 'deposit'), null,
'SITE', $this->op_area);
if (!empty($this->params['admin']))
$this->addSideMenuLink('Assess Charges',
array('controller' => 'leases', 'action' => 'assess_all'), null,
'SITE', $this->op_area);
$url_components = array('plugin', 'controller', 'action', 'named');
if (devbox()) {
/* $sources = ConnectionManager::sourceList(); */
/* $db = ConnectionManager::getDataSource($sources[0])->config['database']; */
/* $this->sideMenuAreaName($db, 'SANDBOX', $this->std_area); */
$this->sideMenuAreaName('DevBox', 'SANDBOX', $this->std_area);
$this->addSideMenuLink('Rebuild DevBox',
array('controller' => 'util', 'action' => 'rebuild_devbox'), null,
'SANDBOX');
}
elseif (sandbox()) {
$this->addSideMenuLink('Rebuild Sandbox',
array('controller' => 'util', 'action' => 'rebuild_sandbox'), null,
'SANDBOX');
$this->addSideMenuLink('Leave Sandbox',
array('sand_route' => false)
+ array_intersect_key($this->params, array_flip($url_components))
+ $this->params['pass'],
null, 'SANDBOX');
}
else {
$this->addSideMenuLink('Enter Sandbox',
array('sand_route' => true)
+ array_intersect_key($this->params, array_flip($url_components))
+ $this->params['pass'],
null, 'SANDBOX');
}
// REVISIT <AP>: 20090824
// Depending on preference, we may put this into the gridView
// function, making the links available only when navigating.
$this->addGridViewSideMenuLinks();
}
/**************************************************************************
**************************************************************************
**************************************************************************
* virtual: addGridViewSideMenuLinks
* - Adds the grid view specific navigation links, if overridden.
*/
function addGridViewSideMenuLinks() {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* hook: beforeFilter
* - Called just before the action function
*/
function beforeFilter() {
$this->params['user'] = $this->Permission->User->currentUser();
$this->params['admin'] = $this->Option->enabled('admin');
$this->params['dev'] = devbox();
if ($this->params['dev'] && !$this->Option->enabled('dev'))
$this->redirect("/");
if (!$this->params['dev'])
Configure::write('debug', '0');
$this->addDefaultSideMenuLinks();
//$this->sideMenuEnable('SITE', $this->op_area, false);
foreach ($this->sidemenu['areas'] AS $area_name => $area) {
if (empty($this->params['dev']))
$this->sideMenuEnable($area_name, $this->dev_area, false);
if (empty($this->params['admin']))
$this->sideMenuEnable($area_name, $this->admin_area, false);
}
$this->authorize("controller.{$this->params['controller']}");
$this->authorize("action.{$this->params['controller']}.{$this->params['action']}");
$this->log('----------------------------------------------------------------------', 'request');
$this->log('----------------------------------------------------------------------', 'request');
$this->log($this->params, 'request');
}
/**************************************************************************
**************************************************************************
**************************************************************************
* hook: beforeRender
* - Called just before rendering the page
*/
function beforeRender() {
// Stupid Cake... our constructor sets admin/dev,
// but cake stomps it somewhere along the way
// after constructing the CakeError controller.
if ($this->name === 'CakeError') {
$this->params['dev'] = false;
$this->params['admin'] = false;
}
foreach ($this->sidemenu['areas'] AS $aname => &$area) {
if (empty($area['enable']))
$area = array();
if (empty($area['subareas']))
continue;
ksort($area['subareas']);
foreach ($area['subareas'] AS $sname => &$subarea) {
if (empty($subarea['enable']))
$subarea = array();
if (empty($subarea['priorities']))
continue;
ksort($subarea['priorities']);
foreach ($subarea['priorities'] AS $pname => &$priority) {
if (empty($priority))
unset($subarea['priorities'][$pname]);
}
unset($priority);
if (empty($subarea['priorities']))
unset($area['subareas'][$sname]);
}
unset($subarea);
if (empty($area['subareas']))
unset($this->sidemenu['areas'][$aname]);
}
unset($area);
// Activate a default section (unless already specified)
foreach (array_reverse(array_diff_key($this->sidemenu['areas'], array('SANDBOX'=>1))) AS $area_name => $area) {
if (empty($area))
continue;
if (empty($this->sidemenu['active']) ||
empty($this->sidemenu['areas'][$this->sidemenu['active']['area']]))
$this->sideMenuAreaActivate($area_name);
}
//pr($this->sidemenu);
$this->set('sidemenu', $this->sidemenu);
$this->set('sidemenu', $this->sideMenuLinks());
}
/**************************************************************************
**************************************************************************
**************************************************************************
* override: redirect
*/
function redirect($url, $status = null, $exit = true) {
// OK, since the controller will not be able to
// utilize our overriden url function in AppHelper,
// we'll have to do it manually here.
App::import('Helper', 'Html');
$url = HtmlHelper::url($url, true);
if (headers_sent()) {
// If we've already sent the headers, it's because
// we're debugging, and our debug output has gotten
// out before the redirect. That's probably a good
// thing, as we don't typically want pages to be
// jerked out from under us while trying to read
// the debug output. So, since we can't redirect
// anyway, we may as well go with the flow and just
// render this page instead, using an empty template
$this->set('message',
("Intended redirect:<P><BR>" .
'<A HREF="'.$url.'">'.$url.'</A>'));
echo $this->render('/empty');
if ($exit)
$this->_stop();
function reset_data() {
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
$script = $_SERVER['DOCUMENT_ROOT'] . '/pmgr/build.cmd';
echo "<P>" . date('r') . "\n";
//echo "<P>Script: $script" . "\n";
$db = & $this->Account->getDataSource();
$script .= ' "' . $db->config['database'] . '"';
$script .= ' "' . $db->config['login'] . '"';
$script .= ' "' . $db->config['password'] . '"';
$handle = popen($script . ' 2>&1', 'r');
//echo "<P>Handle: $handle; " . gettype($handle) . "\n";
echo "<P><PRE>\n";
while (($read = fread($handle, 2096))) {
echo $read;
}
return parent::redirect($url, $status, $exit);
echo "</PRE>\n";
pclose($handle);
}
@@ -435,14 +89,8 @@ class AppController extends Controller {
* helper: gridView
* - called by derived controllers to create an index listing
*/
function index() {
$names = Inflector::humanize(Inflector::pluralize($this->params['controller']));
$this->gridView('All ' . $names, 'all');
}
function gridView($title, $action = null, $element = null) {
$this->sideMenuEnable('SITE', $this->op_area);
$this->sideMenuAreaActivate('CONTROLLER');
$this->set('title', $title);
// The resulting page will contain a grid, which will
// use ajax to obtain the actual data for this action
@@ -513,10 +161,16 @@ class AppController extends Controller {
}
function gridDataSetup(&$params) {
// Debug only if requested
$params['debug'] = !empty($this->passedArgs['debug']);
// Assume we're debugging.
// The actual grid request will set this to false
$debug = true;
if ($params['debug']) {
if (isset($this->passedArgs['debug']))
$debug = $this->passedArgs['debug'];
$params['debug'] = $debug;
if ($debug) {
ob_start();
}
else {
@@ -579,7 +233,6 @@ class AppController extends Controller {
$xml = preg_replace("/</", "&lt;", $xml);
$xml = preg_replace("/>/", "&gt;", $xml);
echo ("\n<PRE>\n$xml\n</PRE>\n");
$this->render_empty();
}
}
@@ -600,8 +253,8 @@ class AppController extends Controller {
// Grouping (which would not be typical)
$query['group'] = $this->gridDataCountGroup($params, $model);
if ($params['debug'])
$params['count_query'] = $query;
// DEBUG PURPOSES ONLY!
$params['count_query'] = $query;
// Get the number of records prior to pagination
return $this->gridDataCountExecute($params, $model, $query);
@@ -857,8 +510,8 @@ class AppController extends Controller {
isset($params['sidx']) ? $params['sidx'] : null,
isset($params['sord']) ? $params['sord'] : null);
if ($params['debug'])
$params['query'] = $query;
// DEBUG PURPOSES ONLY!
$params['query'] = $query;
return $this->gridDataRecordsExecute($params, $model, $query);
}
@@ -981,7 +634,6 @@ class AppController extends Controller {
$this->gridDataPostProcessLinks($params, $model, $records, array());
// DEBUG PURPOSES ONLY!
//if ($params['debug'])
//$params['records'] = $records;
}
@@ -1000,7 +652,7 @@ class AppController extends Controller {
foreach ($records AS &$record) {
// Add the calculated fields (if any), to the model fields
if (isset($record[0])) {
$record[$model_alias] = $record[0] + $record[$model_alias];
$record[$model_alias] += $record[0];
unset($record[0]);
}
}
@@ -1042,12 +694,9 @@ class AppController extends Controller {
if (isset($params['post']['nolinks']))
return;
App::import('Helper', 'Html');
foreach ($links AS $table => $fields) {
$special = array('controller', 'action', 'id');
$special = array('controller', 'id');
$controller = Inflector::pluralize(Inflector::underscore($table));
$action = 'view';
$id = 'id';
extract(array_intersect_key($fields, array_flip($special)));
foreach ($records AS &$record) {
@@ -1059,13 +708,12 @@ class AppController extends Controller {
continue;
// DEBUG PURPOSES ONLY!
//if ($params['debug'])
//$params['linkrecord'][] = compact('table', 'field', 'id', 'controller', 'record');
$record[$table][$field] =
'<A HREF="' .
HtmlHelper::url(array('controller' => $controller,
'action' => $action,
$record[$table][$id])) .
Router::url(array('controller' => $controller,
'action' => 'view',
$record[$table][$id])) .
'">' .
$record[$table][$field] .
'</A>';
@@ -1090,8 +738,9 @@ class AppController extends Controller {
}
function gridDataOutputHeader(&$params, &$model) {
if (!$params['debug'])
if (!$params['debug']) {
header("Content-type: text/xml;charset=utf-8");
}
}
function gridDataOutputXMLHeader(&$params, &$model) {
@@ -1154,27 +803,5 @@ class AppController extends Controller {
echo " <cell><![CDATA[$data]]></cell>\n";
}
function authorize($name) {
if ($this->Permission->deny($name))
$this->UNAUTHORIZED("Unauthorized: $name");
}
function UNAUTHORIZED($msg) {
//$this->redirect('controller' => '???', 'action' => 'login');
//$this->render('/unauthorized');
$this->set('message', '<H2>' . $msg . '</H2>');
$this->render_empty();
}
function INTERNAL_ERROR($msg, $depth = 0) {
INTERNAL_ERROR($msg, false, $depth+1);
$this->render_empty();
}
function render_empty() {
echo $this->render('/empty');
$this->_stop();
}
}
?>

View File

@@ -37,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);
}
}
?>

View File

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

View File

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

View File

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

View File

@@ -32,41 +32,16 @@
*
*/
function sandbox() {
$r = Router::requestRoute();
return !empty($r[3]['sand_route']);
}
function devbox() {
$r = Router::requestRoute();
return !empty($r[3]['dev_route']);
}
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";
function INTERNAL_ERROR($message) {
echo '<DIV class="internal-error" style="color:#000; background:#c22; padding:0.5em 1.5em 0.5em 1.5em;">';
echo '<H1 style="margin-bottom:0.2em">INTERNAL ERROR:</H1>';
echo '<H2 style="margin-top:0; margin-left:1.5em">' . $message . '</H2>';
echo '<H4>This error was not caused by anything that you did wrong.';
echo '<BR>It is a problem within the application itself and should be reported to the administrator.</H4>';
// 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);
echo "<HR>Stack Trace:<OL>";
$trace = debug_backtrace(false);
for ($i = 0; $i < count($trace); ++$i) {
$bline = $trace[$i]['line'];
$bfile = $trace[$i]['file'];
@@ -81,40 +56,12 @@ function INTERNAL_ERROR($message, $exit = true, $drop = 0) {
$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 =&gt; $v</LI>\n");
}
echo "</UL>\n";
$O->log(str_repeat("-", 30));
$O->log("Server:");
$SRV = array_intersect_key($_SERVER, array_flip(array_filter(array_keys($_SERVER), 'server_request_var')));
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\nServer:\n";
echo '<UL style="margin-top:0.5em; margin-left:0.0em";>' . "\n";
foreach($SRV AS $k => $v) {
if ($k == 'REQUEST_TIME')
$v = date('c', $v);
$O->log(sprintf(" %-20s => %s", $k, $v));
echo("<LI>$k =&gt; $v</LI>\n");
}
echo "</UL>\n";
echo '<HR style="margin-top:1.0em; margin-bottom:0.5em;">' . "\n";
echo date('c') . "<BR>\n";
echo '</OL>';
echo '</DIV>';
if ($exit)
die();
die();
}
/**

View File

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

View File

@@ -10,12 +10,5 @@ class DATABASE_CONFIG {
'database' => 'property_manager',
'prefix' => 'pmgr_',
);
function __construct() {
if (devbox())
$this->default['database'] = 'pmgr_dev';
if (sandbox())
$this->default['database'] = 'pmgr_sand';
}
}
?>

View File

@@ -27,29 +27,11 @@
* @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));
/*
* Route for developement functionality
*/
Router::connect('/dev',
array('dev_route' => true) + $default_path);
Router::connect('/dev/:controller/:action/*',
array('dev_route' => true, 'action' => null));
Router::connect('/', array('controller' => 'maps', 'action' => 'view', '1'));
?>

View File

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

View File

@@ -2,7 +2,19 @@
class ContactsController extends AppController {
var $sidemenu_links = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -23,34 +35,19 @@ class ContactsController extends AppController {
* to jqGrid.
*/
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;
if ($index === 'Contact.last_name') {
$order[] = 'Contact.first_name ' . $direction;
}
if ($index === 'Contact.first_name') {
$order[] = 'Contact.last_name ' . $direction;
}
return $order;
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Contact'] = array('display_name');
$links['Contact'] = array('id');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -81,9 +78,13 @@ class ContactsController extends AppController {
));
// Set up dynamic menu items
$this->addSideMenuLink('Edit',
array('action' => 'edit', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'Edit',
'url' => array('action' => 'edit',
$id));
// Prepare to render.
$title = 'Contact: ' . $contact['Contact']['display_name'];
@@ -125,6 +126,8 @@ class ContactsController extends AppController {
// Now that the work is done, let the user view the updated contact
$this->redirect(array('action'=>'view', $this->data['Contact']['id']));
//$this->render('/empty');
return;
}
if ($id) {

View File

@@ -1,34 +1,28 @@
<?php
class CustomersController extends AppController {
var $sidemenu_links =
array(array('name' => 'Customers', 'header' => true),
array('name' => 'Current', 'url' => array('controller' => 'customers', 'action' => 'current')),
array('name' => 'Past', 'url' => array('controller' => 'customers', 'action' => 'past')),
array('name' => 'All', 'url' => array('controller' => 'customers', 'action' => 'all')),
array('name' => 'Add Customer', 'url' => array('controller' => 'customers', 'action' => 'add')),
);
//var $components = array('RequestHandler');
/**************************************************************************
**************************************************************************
**************************************************************************
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
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); */
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -87,29 +81,19 @@ class CustomersController extends AppController {
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);
$order = array();
$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;
if ($index !== 'PrimaryContact.last_name')
$order[] = parent::gridDataOrder($params, $model,
'PrimaryContact.last_name', $direction);
if ($index !== 'PrimaryContact.first_name')
$order[] = parent::gridDataOrder($params, $model,
'PrimaryContact.first_name', $direction);
if ($index !== 'Customer.id')
$order[] = parent::gridDataOrder($params, $model,
'Customer.id', $direction);
return $order;
}
@@ -127,18 +111,14 @@ class CustomersController extends AppController {
* - Sets up the move-in page for the given customer.
*/
function move_in($id = null, $unit_id = null) {
function move_in($id = null) {
$customer = array();
$unit = array();
if (!empty($id)) {
if (isset($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';
@@ -222,88 +202,52 @@ class CustomersController extends AppController {
));
//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;
$show_moveout = false;
$show_payment = false;
foreach ($customer['Lease'] AS $lease) {
if (!isset($lease['close_date'])) {
if ($show_payment)
$payment_lease_id = null;
else
$payment_lease_id = $lease['id'];
if (!isset($lease['close_date']))
$show_payment = true;
}
if (!isset($lease['moveout_date'])) {
if ($show_moveout)
$moveout_lease_id = null;
else
$moveout_lease_id = $lease['id'];
if (!isset($lease['moveout_date']))
$show_moveout = true;
}
}
// Set up dynamic menu items
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
if ($show_payment || $outstanding_balance > 0)
$this->addSideMenuLink('New Receipt',
array('action' => 'receipt', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Edit',
'url' => array('action' => 'edit',
$id));
$this->sidemenu_links[] =
array('name' => 'Move-In',
'url' => array('action' => 'move_in',
$id));
/* if ($show_moveout) { */
/* $this->sidemenu_links[] = */
/* array('name' => 'Move-Out', */
/* 'url' => array('action' => 'move_out', */
/* $id)); */
/* } */
if ($show_payment) {
/* $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->sidemenu_links[] =
array('name' => 'Payment',
'url' => array('action' => 'receipt',
$id));
}
$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');
$this->sidemenu_links[] =
array('name' => 'Issue Refund',
'url' => array('action' => 'refund', $id));
// Prepare to render.
$title = 'Customer: ' . $customer['Customer']['name'];
@@ -326,20 +270,23 @@ class CustomersController extends AppController {
if (isset($this->params['form']['cancel'])) {
if (isset($this->data['Customer']['id']))
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
$this->redirect(array('action'=>'index'));
else
$this->redirect(array('action'=>'index'));
return;
}
// Make sure we have at least one contact
if (!isset($this->data['Contact']) || count($this->data['Contact']) == 0) {
$this->Session->setFlash("MUST SPECIFY AT LEAST ONE CONTACT", true);
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
return;
}
// Make sure there is a primary contact
if (!isset($this->data['Customer']['primary_contact_entry'])) {
$this->Session->setFlash("MUST SPECIFY A PRIMARY CONTACT", true);
$this->redirect(array('action'=>'view', $this->data['Customer']['id']));
return;
}
// Go through each customer and strip the bogus ID if new
@@ -356,56 +303,21 @@ class CustomersController extends AppController {
pr("CUSTOMER SAVE FAILED");
}
// If existing customer, then view it.
// If existing customer, then view it. Otherwise, since
// this is a new customer, go to the move in screen.
if ($this->data['Customer']['id'])
$this->redirect(array('action'=>'view', $this->Customer->id));
// 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'];
$this->redirect(array('action'=>'move_in', $this->Customer->id));
// ... then redirect
$this->redirect(array('action'=>'move_in',
$this->Customer->id,
$unit_id,
));
// For debugging, only if the redirects above have been
// commented out, otherwise this section isn't reached.
$this->render('/empty');
return;
}
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;
$this->data = $this->Customer->details($id);
$title = 'Customer: ' . $this->data['Customer']['name'] . " : Edit";
}
else {
@@ -434,8 +346,7 @@ class CustomersController extends AppController {
* - Add a new customer
*/
function add($unit_id = null) {
$this->set('movein', array('Unit' => array('id' => $unit_id)));
function add() {
$this->edit();
}
@@ -451,9 +362,20 @@ class CustomersController extends AppController {
$this->Customer->recursive = -1;
$customer = $this->Customer->read(null, $id);
$customer = $customer['Customer'];
$unreconciled = $this->Customer->unreconciledCharges($id);
//pr($unreconciled);
$charges = $unreconciled['entries'];
$stats = $unreconciled['summary']['Charge'];
// Kludge until we update receipt to have the unpaid
// charges grid generated from a dynamic query instead
// of simply pre-providing the list of charge IDs
foreach ($charges AS &$charge)
$charge['id'] = $charge['StatementEntry']['id'];
}
else {
$customer = null;
$charges = array();
$stats = array('balance' => 0);
}
$TT = new TenderType();
@@ -462,7 +384,7 @@ class CustomersController extends AppController {
$this->set(compact('payment_types', 'default_type'));
$title = ($customer['name'] . ': Receipt Entry');
$this->set(compact('customer', 'title'));
$this->set(compact('customer', 'charges', 'stats', 'title'));
}
@@ -473,64 +395,64 @@ class CustomersController extends AppController {
* - Refunds customer charges
*/
function refund($id) {
$customer = $this->Customer->find
('first', array
function refund() {
$entries = $this->Customer->StatementEntry->find
('all', array
('contain' => false,
'conditions' => array(array('Customer.id' => $id),
'conditions' => array('StatementEntry.id' =>
//array(199,200,201)
61
),
));
if (empty($customer)) {
$this->redirect(array('action'=>'view', $id));
}
pr(compact('entries'));
// 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');
$this->Customer->refund($entries);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: bad_debt
* - Sets up the write-off entry page, so that the
* user can write off remaining charges of a customer.
* action: unreconciled
* - returns the list of unreconciled entries
*/
function bad_debt($id) {
$this->Customer->id = $id;
$customer = $this->Customer->find
('first', array
('contain' => false,
));
function unreconciled($id) {
// Make sure we have a valid customer to write off
if (empty($customer))
$this->redirect(array('action' => 'index'));
//$this->layout = 'ajax';
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
header("Content-type: text/xml;charset=utf-8");
// Get the customer balance
$balance = $this->Customer->balance($id);
App::import('Helper', 'Xml');
$xml = new XmlHelper();
// Prepare to render
$title = ($customer['Customer']['name'] . ': Write Off Bad Debt');
$this->set(compact('title', 'customer', 'balance'));
$this->render('/transactions/bad_debt');
// Find the unreconciled entries, then manipulate the structure
// slightly to accomodate the format necessary for XML Helper.
$unreconciled = $this->Customer->unreconciledCharges($id);
foreach ($unreconciled['entries'] AS &$entry)
$entry = array_intersect_key($entry['StatementEntry'],
array('id'=>1));
$unreconciled = array('entries' =>
array('entry' => $unreconciled['entries'],
'balance' => $unreconciled['summary']['balance']));
// XML Helper will dump an empty tag if the array is empty
if (empty($unreconciled['entries']['entry']))
unset($unreconciled['entries']['entry']);
/* pr(compact('unreconciled')); */
/* echo htmlspecialchars($xml->serialize($unreconciled)); */
/* $this->render('/fake'); */
$opts = array();
//$opts['format'] = 'tags';
echo $xml->header();
echo $xml->serialize($unreconciled, $opts);
}
}

View File

@@ -2,7 +2,20 @@
class DoubleEntriesController extends AppController {
var $sidemenu_links = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -23,34 +36,6 @@ class DoubleEntriesController extends AppController {
'conditions' => array('DoubleEntry.id' => $id),
));
$entry += $this->DoubleEntry->DebitEntry->Transaction->find
('first',
array('contain' => false,
'conditions' => array('id' => $entry['DebitEntry']['transaction_id']),
));
$entry += $this->DoubleEntry->DebitEntry->find
('first',
array('contain' => array('Ledger' => array('Account')),
'conditions' => array('DebitEntry.id' => $entry['DebitEntry']['id']),
));
$entry['Ledger']['link'] =
$entry['Ledger']['Account']['level'] >=
$this->Permission->level('controller.accounts');
$entry['DebitLedger'] = $entry['Ledger'];
unset($entry['Ledger']);
$entry += $this->DoubleEntry->CreditEntry->find
('first',
array('contain' => array('Ledger' => array('Account')),
'conditions' => array('CreditEntry.id' => $entry['CreditEntry']['id']),
));
$entry['Ledger']['link'] =
$entry['Ledger']['Account']['level'] >=
$this->Permission->level('controller.accounts');
$entry['CreditLedger'] = $entry['Ledger'];
unset($entry['Ledger']);
// Prepare to render.
$title = "Double Ledger Entry #{$entry['DoubleEntry']['id']}";
$this->set(compact('entry', 'title'));

View File

@@ -2,32 +2,25 @@
class LeasesController extends AppController {
var $sidemenu_links =
array(array('name' => 'Leases', 'header' => true),
array('name' => 'Active', 'url' => array('controller' => 'leases', 'action' => 'active')),
array('name' => 'Closed', 'url' => array('controller' => 'leases', 'action' => 'closed')),
array('name' => 'All', 'url' => array('controller' => 'leases', 'action' => 'all')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
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');
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -35,11 +28,10 @@ class LeasesController extends AppController {
* - 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'); }
function index() { $this->all(); }
function active() { $this->gridView('Active Leases'); }
function closed() { $this->gridView('Closed Leases'); }
function all() { $this->gridView('All Leases', 'all'); }
/**************************************************************************
@@ -71,8 +63,6 @@ class LeasesController extends AppController {
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = ("IF(" . $this->Lease->conditionDelinquent() . "," .
" 'DELINQUENT', 'CURRENT') AS 'status'");
return array_merge($fields,
$this->Lease->StatementEntry->chargeDisbursementFields(true));
}
@@ -83,9 +73,6 @@ class LeasesController extends AppController {
if ($params['action'] === 'active') {
$conditions[] = 'Lease.close_date IS NULL';
}
elseif ($params['action'] === 'delinquent') {
$conditions[] = $this->Lease->conditionDelinquent();
}
elseif ($params['action'] === 'closed') {
$conditions[] = 'Lease.close_date IS NOT NULL';
}
@@ -148,22 +135,21 @@ class LeasesController extends AppController {
// 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'],
null, null,
$this->data['Lease']['movein_date'],
$this->data['Lease']['comment']
);
// Since this is a new lease, go to the invoice
// screen so we can start assessing charges.
$this->redirect(array('action'=>'invoice', $lid, 'move-in'));
$this->redirect(array('action'=>'invoice', $lid));
// For debugging, only if the redirect above have been
// commented out, otherwise this section isn't reached.
$this->render('/empty');
}
/**************************************************************************
@@ -180,46 +166,47 @@ class LeasesController extends AppController {
$this->Lease->moveOut($this->data['Lease']['id'],
'VACANT',
$this->data['Lease']['moveout_date']
$this->data['Lease']['moveout_date'],
//true // Close this lease, if able
false
);
$this->redirect(array('controller' => 'leases',
'action' => 'view',
$this->data['Lease']['id']));
$this->redirect($this->data['redirect']);
}
if (isset($id)) {
$lease = $this->Lease->find
('first', array
('contain' => array
(// Models
'Unit' =>
array('order' => array('sort_order'),
'fields' => array('id', 'name'),
),
if (!isset($id))
die("Oh Nooooo!!");
'Customer' =>
array('fields' => array('id', 'name'),
),
),
$lease = $this->Lease->find
('first', array
('contain' => array
(// Models
'Unit' =>
array('order' => array('sort_order'),
'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']);
'Customer' =>
array('fields' => array('id', 'name'),
),
),
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
$lease['Unit']['name'] . ': ' .
$lease['Customer']['name'] . ': Move-Out');
}
else {
$title = 'Move-Out';
}
'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']);
$this->set(compact('title'));
$redirect = array('controller' => 'leases',
'action' => 'view',
$id);
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
$lease['Unit']['name'] . ': ' .
$lease['Customer']['name'] . ': Prepare Move-Out');
$this->set(compact('title', 'redirect'));
$this->render('/leases/move');
}
@@ -234,6 +221,8 @@ class LeasesController extends AppController {
/* function promote_surplus($id) { */
/* $this->Lease->promoteSurplus($id); */
/* pr("PREVENTING REDIRECT"); */
/* $this->render('fake'); */
/* $this->redirect(array('controller' => 'leases', */
/* 'action' => 'view', */
/* $id)); */
@@ -284,7 +273,6 @@ class LeasesController extends AppController {
$lease['Unit']['name'] . ': ' .
$lease['Customer']['name'] . ': Refund');
$this->set(compact('title', 'lease', 'balance'));
$this->render('/transactions/refund');
}
@@ -297,7 +285,6 @@ class LeasesController extends AppController {
*/
function bad_debt($id) {
$this->Lease->id = $id;
$lease = $this->Lease->find
('first', array
('contain' => array
@@ -305,14 +292,20 @@ class LeasesController extends AppController {
'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),
),
));
// 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);
// Get the lease balance, part of lease stats
$stats = $this->Lease->stats($id);
$balance = $stats['balance'];
// Prepare to render
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
@@ -330,23 +323,9 @@ class LeasesController extends AppController {
* - Closes a lease to any further action
*/
// REVISIT <AP>: 20090809
// While cleaning up the sitelink data, then delete reldep()
function reldep($id) {
$this->Lease->id = $id;
$stamp = $this->Lease->field('moveout_date');
$this->Lease->releaseSecurityDeposits($id, $stamp);
$this->redirect(array('action'=>'view', $id));
}
function close($id) {
// REVISIT <AP>: 20090708
// We should probably seek confirmation first...
if (!$this->Lease->closeable($id)) {
$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));
}
@@ -383,34 +362,13 @@ class LeasesController extends AppController {
$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'));
$this->set(compact('charge_accounts', 'default_account'));
// REVISIT <AP> 20090705:
// Of course, the late charge should come from the late_schedule
$default_rent = $lease['Lease']['rent'];
$default_late = 10;
$this->set(compact('default_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'));
}
$this->set(compact('default_rent', 'default_late'));
$title = ('Lease #' . $lease['Lease']['number'] . ': ' .
$lease['Unit']['name'] . ': ' .
@@ -419,27 +377,6 @@ class LeasesController extends AppController {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -458,65 +395,62 @@ class LeasesController extends AppController {
('first',
array('contain' =>
array(// Models
'LeaseType(id,name)',
'Unit(id,name)',
'Customer(id,name)',
'LeaseType',
'Unit',
'Customer',
),
'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
$lease['Lease']['paid_through'] = $this->Lease->rentPaidThrough($id);
$this->set('charge_gaps', $this->Lease->rentChargeGaps($id));
$this->set('charge_through', $this->Lease->rentChargeThrough($id));
// Figure out the outstanding balances for this lease
$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) {
// Set up dynamic menu items
if (!isset($lease['Lease']['close_date'])) {
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
if (!isset($lease['Lease']['moveout_date']))
$this->addSideMenuLink('Move-Out',
array('action' => 'move_out', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
$id));
if (!isset($lease['Lease']['close_date']))
$this->addSideMenuLink('New Invoice',
array('action' => 'invoice', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Charges', 'url' => array('action' => 'invoice',
$id));
$this->addSideMenuLink('New Receipt',
array('controller' => 'customers',
'action' => 'receipt',
$lease['Customer']['id']), null,
'ACTION');
// REVISIT <AP>:
// Not allowing refund to be issued from the lease, as
// 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.");
$this->sidemenu_links[] =
array('name' => 'Payments', 'url' => array('controller' => 'customers',
'action' => 'receipt',
$lease['Customer']['id']));
/* if ($outstanding_balance < 0) */
/* $this->addSideMenuLink('Issue Refund', */
/* array('action' => 'refund', $id), null, */
/* 'ACTION'); */
/* $this->sidemenu_links[] = */
/* array('name' => 'Transfer Credit to Customer', */
/* 'url' => array('action' => 'promote_surplus', $id)); */
if ($outstanding_balance < 0)
$this->sidemenu_links[] =
array('name' => 'Issue Refund',
'url' => array('action' => 'refund', $id));
if (isset($lease['Lease']['moveout_date']) && $outstanding_balance > 0)
$this->addSideMenuLink('Write-Off',
array('action' => 'bad_debt', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Write-Off', 'url' => array('action' => 'bad_debt',
$id));
if ($this->Lease->closeable($id))
$this->addSideMenuLink('Close',
array('action' => 'close', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Close', 'url' => array('action' => 'close',
$id));
}
// Prepare to render

View File

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

View File

@@ -2,29 +2,25 @@
class LedgersController extends AppController {
var $sidemenu_links =
array(array('name' => 'Ledgers', 'header' => true),
array('name' => 'Current', 'url' => array('controller' => 'ledgers', 'action' => 'current')),
array('name' => 'Closed', 'url' => array('controller' => 'ledgers', 'action' => 'closed')),
array('name' => 'All', 'url' => array('controller' => 'ledgers', 'action' => 'all')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
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');
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -54,21 +50,24 @@ class LedgersController extends AppController {
}
function gridDataCountTables(&$params, &$model) {
// Our count should NOT include anything extra,
// so we need the virtual function to prevent
// the base class from just calling our
// gridDataTables function.
return parent::gridDataTables($params, $model);
}
function gridDataTables(&$params, &$model) {
return array
('link' =>
array(// Models
'Account',
'LedgerEntry',
'CloseTransaction',
),
);
}
function gridDataTables(&$params, &$model) {
$tables = $this->gridDataCountTables($params, $model);
$tables['link'][] = 'LedgerEntry';
$tables['link'][] = 'CloseTransaction';
return $tables;
}
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = 'CONCAT(Account.id, "-", Ledger.sequence) AS id_sequence';
@@ -86,32 +85,28 @@ class LedgersController extends AppController {
$conditions[] = array('Ledger.close_transaction_id !=' => null);
}
$conditions[] = array('Account.level >=' =>
$this->Permission->level('controller.accounts'));
return $conditions;
}
function gridDataOrder(&$params, &$model, $index, $direction) {
$id_sequence = false;
if ($index === 'id_sequence') {
$id_sequence = true;
$index = 'Ledger.account_id';
}
$order = parent::gridDataOrder($params, $model, $index, $direction);
// 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;
if ($id_sequence) {
$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');
}
$links['Ledger'] = array('id_sequence');
$links['Account'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -124,24 +119,22 @@ class LedgersController extends AppController {
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
// Get details about the ledger itself (no entries yet)
$ledger = $this->Ledger->find
('first',
array('contain' =>
array(// Models
'Account',
),
'conditions' => array(array('Ledger.id' => $id),
array('Account.level >=' =>
$this->Permission->level('controller.accounts')),
),
'conditions' => array(array('Ledger.id' => $id)),
)
);
if (empty($ledger)) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
// Get ledger stats for our summary box
$stats = $this->Ledger->stats($id);

View File

@@ -52,7 +52,6 @@ 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 +85,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 +113,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 +132,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,15 +143,11 @@ 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;
}
@@ -188,10 +160,8 @@ 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'));
$status = $this->Map->Unit->activeStatusEnums();
//pr($status);
$rows = 2;
$cols = (int)((count($status) + $rows - 1) / $rows);
@@ -221,7 +191,7 @@ class MapsController extends AppController {
$item_width *= $screen_adjustment_factor;
$item_depth *= $screen_adjustment_factor;
foreach ($status AS $code) {
foreach ($status AS $code => $value) {
$info['units'][] = array('name' => $code,
'status' => $code,
'width' => $item_width,
@@ -271,9 +241,9 @@ class MapsController extends AppController {
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
$info['palate']['unit']['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) {

View File

@@ -2,7 +2,20 @@
class StatementEntriesController extends AppController {
var $sidemenu_links = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -22,7 +35,7 @@ class StatementEntriesController extends AppController {
* to jqGrid.
*/
function gridDataCountTables(&$params, &$model) {
function gridDataTables(&$params, &$model) {
$link =
array(// Models
'Transaction' =>
@@ -45,36 +58,27 @@ class StatementEntriesController extends AppController {
),
);
if (!empty($params['post']['custom']['statement_entry_id'])) {
$link['ChargeEntry'] = array();
// This query actually represents a union...
// Unpaid Charge/Surplus: ChargeID - NULL; DisbursementID - NULL
// Paid Charge/Refund: ChargeID - NULL; DisbursementID - !NULL
// Disbursement/Reversal: ChargeID - !NULL; DisbursementID - NULL
// <EMPTY SET>: ChargeID - !NULL; DisbursementID - !NULL
//
// The query is really slow unless we add the `id` condition to the join.
// A cleaner query would be nice, but we must work within the Cake framework.
$link['DisbursementEntry'] = array('conditions' =>
'`DisbursementEntry`.`id` = '
. $params['post']['custom']['statement_entry_id']);
if (isset($params['post']['custom']['statement_entry_id'])) {
$link['DisbursementEntry'] = array();
$link['ChargeEntry'] = array();
}
/* if ($params['action'] === 'collected') { */
/* $link['DisbursementEntry'] = array('Receipt' => array('class' => 'Transaction')); */
/* $link['ChargeEntry'] = array('Invoice' => array('class' => 'Transaction')); */
/* } */
/* if (count(array_intersect($params['fields'], array('applied'))) == 1) { */
/* $link['DisbursementEntry'] = array(); */
/* $link['ChargeEntry'] = array(); */
/* } */
/* elseif (isset($params['post']['custom']['customer_id']) || isset($params['post']['custom']['lease_id'])) { */
/* $link['DisbursementEntry'] = array(); */
/* } */
return array('link' => $link);
}
function gridDataTables(&$params, &$model) {
$tables = $this->gridDataCountTables($params, $model);
if (in_array('applied', $params['post']['fields'])) {
$tables['link'] +=
array('ChargeEntry' => array(),
'DisbursementEntry' => array());
}
return $tables;
}
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
@@ -83,13 +87,11 @@ class StatementEntriesController extends AppController {
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
" AS 'applied'");
}
if (in_array('unapplied', $params['post']['fields'])) {
$fields[] = ("StatementEntry.amount - (" .
"IF(StatementEntry.type = 'CHARGE'," .
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
") AS 'unapplied'");
") AS 'balance'");
}
$fields = array_merge($fields,
@@ -115,24 +117,10 @@ class StatementEntriesController extends AppController {
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))
if (isset($statement_entry_id)) {
$conditions[] = array('OR' =>
array(array('ChargeEntry.id' => $statement_entry_id),
array('DisbursementEntry.id' => $statement_entry_id)));
if ($params['action'] === 'unreconciled') {
$query = array('conditions' => $conditions);
$set = $this->StatementEntry->reconciledSet('CHARGE', $query, true);
$entries = array();
foreach ($set['entries'] AS $entry)
$entries[] = $entry['StatementEntry']['id'];
$conditions[] = array('StatementEntry.id' => $entries);
$params['userdata']['balance'] = $set['summary']['balance'];
}
return $conditions;
@@ -141,10 +129,7 @@ class StatementEntriesController extends AppController {
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['Account'] = array('name');
$links['Customer'] = array('name');
$links['Lease'] = array('number');
$links['Unit'] = array('name');
@@ -166,26 +151,26 @@ class StatementEntriesController extends AppController {
}
function gridDataRecordsExecute(&$params, &$model, $query) {
/* if ($params['action'] === '???') { */
/* $tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1)); */
/* $tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," . */
/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */
/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */
/* " AS 'applied'", */
if (in_array('applied', $params['post']['fields'])) {
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
$tquery['fields'] = array("IF(StatementEntry.type = 'CHARGE'," .
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
" AS 'applied'",
/* "StatementEntry.amount - (" . */
/* "IF(StatementEntry.type = 'CHARGE'," . */
/* " SUM(COALESCE(DisbursementEntry.amount,0))," . */
/* " SUM(COALESCE(ChargeEntry.amount,0)))" . */
/* ") AS 'balance'", */
/* ); */
"StatementEntry.amount - (" .
"IF(StatementEntry.type = 'CHARGE'," .
" SUM(COALESCE(DisbursementEntry.amount,0))," .
" SUM(COALESCE(ChargeEntry.amount,0)))" .
") AS 'balance'",
);
/* //pr(compact('tquery')); */
/* $total = $model->find('first', $tquery); */
/* $params['userdata']['total'] = $total[0]['applied']; */
/* $params['userdata']['balance'] = $total[0]['balance']; */
/* } */
if ($params['action'] === 'collected') {
//pr(compact('tquery'));
$total = $model->find('first', $tquery);
$params['userdata']['total'] = $total[0]['applied'];
$params['userdata']['balance'] = $total[0]['balance'];
}
else {
$tquery = array_diff_key($query, array('fields'=>1,'group'=>1,'limit'=>1,'order'=>1));
$tquery['fields'] = array("SUM(COALESCE(StatementEntry.amount,0)) AS 'total'");
$total = $model->find('first', $tquery);
@@ -202,42 +187,10 @@ class StatementEntriesController extends AppController {
* 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'));
function reverse($id) {
$this->StatementEntry->reverse($id);
$this->render('/FAKE');
$this->redirect(array('action'=>'view', $id));
}
@@ -261,27 +214,25 @@ class StatementEntriesController extends AppController {
*/
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)) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
}
$entry['Account']['link'] =
$entry['Account']['level'] >=
$this->Permission->level('controller.accounts');
// Get the StatementEntry and related fields
$entry = $this->StatementEntry->find
('first',
array('contain' => array
('Transaction' => array('fields' => array('id', 'type', 'stamp')),
'Account' => array('id', 'name', 'type'),
'Customer' => array('fields' => array('id', 'name')),
'Lease' => array('fields' => array('id')),
),
'conditions' => array('StatementEntry.id' => $id),
));
$reconciled = $this->StatementEntry->reconciledEntries($id);
$stats = $this->StatementEntry->stats($id);
@@ -293,21 +244,34 @@ class StatementEntriesController extends AppController {
if (strtoupper($entry['StatementEntry']['type']) === 'CHARGE') {
$reversal = $this->StatementEntry->find
('first',
array('link' => array('DisbursementEntry'),
'conditions' => array(array('StatementEntry.id' => $id),
array('DisbursementEntry.type' => 'REVERSAL')),
));
// Set up dynamic menu items
if ($this->StatementEntry->reversable($id))
$this->addSideMenuLink('Reverse',
array('action' => 'reverse', $id), null,
'ACTION');
if (empty($reversal) || $stats['balance'] > 0)
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
if (empty($reversal))
$this->sidemenu_links[] =
array('name' => 'Reverse',
'url' => array('action' => 'reverse',
$id));
if ($stats['balance'] > 0)
$this->addSideMenuLink('Waive Balance',
array('action' => 'waive', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Waive Balance',
'url' => array('action' => 'waive',
$id));
}
// Prepare to render.
$title = "Statement Entry #{$entry['StatementEntry']['id']}";
$this->set(compact('entry', 'title', 'stats'));
$this->set(compact('entry', 'title', 'reconciled', 'stats'));
}
}

View File

@@ -2,7 +2,20 @@
class TendersController extends AppController {
var $sidemenu_links = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -62,7 +75,7 @@ class TendersController extends AppController {
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Tender'] = array('name', 'id');
$links['Customer'] = array('name');
//$links['TenderType'] = array('name');
$links['TenderType'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -102,33 +115,15 @@ class TendersController extends AppController {
*/
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'));
$this->Tender->nsf($id);
$this->redirect(array('action'=>'view', $id));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -143,7 +138,6 @@ class TendersController extends AppController {
}
// Get the Tender and related fields
$this->Tender->id = $id;
$tender = $this->Tender->find
('first', array
('contain' => array('TenderType', 'Customer', 'LedgerEntry' => array('Transaction')),
@@ -154,87 +148,20 @@ class TendersController extends AppController {
&& 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']))
&& !empty($tender['TenderType']['data1_name'])
) {
$this->addSideMenuLink('NSF',
array('action' => 'nsf', $id), null,
'ACTION');
// Set up dynamic menu items
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'NSF',
'url' => array('action' => 'nsf',
$id));
}
// Watch out for the special "Closing" entries, which have
// tender_type_id set to NULL. Otherwise, allow editing.
if (!empty($tender['TenderType']['id']))
$this->addSideMenuLink('Edit',
array('action' => 'edit', $id), null,
'ACTION');
// Prepare to render.
$title = "Tender #{$tender['Tender']['id']} : {$tender['Tender']['name']}";
$title = "Tender #{$tender['Tender']['id']}";
$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'));
}
}

View File

@@ -4,38 +4,26 @@ class TransactionsController extends AppController {
var $components = array('RequestHandler');
var $sidemenu_links =
array(array('name' => 'Transactions', 'header' => true),
array('name' => 'All', 'url' => array('controller' => 'transactions', 'action' => 'all')),
array('name' => 'Invoices', 'url' => array('controller' => 'transactions', 'action' => 'invoice')),
array('name' => 'Receipts', 'url' => array('controller' => 'transactions', 'action' => 'receipt')),
array('name' => 'Deposits', 'url' => array('controller' => 'transactions', 'action' => 'deposit')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
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);
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -47,12 +35,7 @@ class TransactionsController extends AppController {
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 deposit() { $this->gridView('Deposits'); }
/**************************************************************************
@@ -65,12 +48,7 @@ class TransactionsController extends AppController {
*/
function gridDataCountTables(&$params, &$model) {
return array
('link' =>
array(// Models
'Account' => array('fields' => array()),
),
);
return parent::gridDataTables($params, $model);
}
function gridDataTables(&$params, &$model) {
@@ -99,8 +77,7 @@ class TransactionsController extends AppController {
}
function gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['Transaction'] = array('id', 'action' => ($params['action'] == 'deposit'
? 'deposit_slip' : 'view'));
$links['Transaction'] = array('id');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
@@ -112,7 +89,7 @@ class TransactionsController extends AppController {
* - handles the creation of a charge invoice
*/
function postInvoice($redirect = true) {
function postInvoice() {
if (!$this->RequestHandler->isPost()) {
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
return;
@@ -127,17 +104,6 @@ class TransactionsController extends AppController {
die("<H1>INVOICE FAILED</H1>");
}
if ($redirect) {
if (!empty($this->data['Customer']['id']))
$this->redirect(array('controller' => 'customers',
'action' => 'receipt',
$this->data['Customer']['id']));
else
$this->redirect(array('controller' => 'leases',
'action' => 'view',
$this->data['Lease']['id']));
}
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
@@ -151,7 +117,7 @@ class TransactionsController extends AppController {
* - handles the creation of a receipt
*/
function postReceipt($redirect = true) {
function postReceipt() {
if (!$this->RequestHandler->isPost()) {
echo('<H2>THIS IS NOT A POST FOR SOME REASON</H2>');
return;
@@ -175,11 +141,6 @@ class TransactionsController extends AppController {
die("<H1>RECEIPT FAILED</H1>");
}
if ($redirect)
$this->redirect(array('controller' => 'customers',
'action' => 'view',
$this->data['Customer']['id']));
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
@@ -292,7 +253,7 @@ class TransactionsController extends AppController {
$this->Session->setFlash(__('Unable to Create Deposit', true));
$this->redirect(array('controller' => 'tenders', 'action'=>'deposit'));
}
// Present the deposit slip to the user
$this->redirect(array('controller' => 'transactions',
'action' => 'deposit_slip',
@@ -314,6 +275,9 @@ class TransactionsController extends AppController {
}
$data = $this->data;
$data['Entry'][0]['account_id'] =
$this->Transaction->Account->badDebtAccountID();
if (empty($data['Customer']['id']))
$data['Customer']['id'] = null;
if (empty($data['Lease']['id']))
@@ -321,9 +285,9 @@ class TransactionsController extends AppController {
pr(compact('data'));
if (!$this->Transaction->addWriteOff($data,
$data['Customer']['id'],
$data['Lease']['id'])) {
if (!$this->Transaction->addReceipt($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,
@@ -331,6 +295,8 @@ class TransactionsController extends AppController {
die("<H1>WRITE-OFF FAILED</H1>");
}
$this->render('/fake');
// Return to viewing the lease/customer
if (empty($data['Lease']['id']))
$this->redirect(array('controller' => 'customers',
@@ -372,6 +338,8 @@ class TransactionsController extends AppController {
die("<H1>REFUND FAILED</H1>");
}
$this->render('/fake');
// Return to viewing the lease/customer
if (empty($data['Lease']['id']))
$this->redirect(array('controller' => 'customers',
@@ -384,23 +352,6 @@ class TransactionsController extends AppController {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: destroy
* - Deletes a transaction and associated entries
* - !!WARNING!! This should be used with EXTREME caution, as it
* irreversibly destroys the data. It is not for normal use.
*/
function destroy($id) {
$this->Transaction->id = $id;
$customer_id = $this->Transaction->field('customer_id');
$this->Transaction->destroy($id);
$this->redirect(array('controller' => 'customers', 'action' => 'view', $customer_id));
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -409,39 +360,34 @@ class TransactionsController extends AppController {
*/
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)) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$transaction['Account']['link'] =
$transaction['Account']['level'] >=
$this->Permission->level('controller.accounts');
$transaction = $this->Transaction->find
('first',
array('contain' =>
array(// Models
'Account' =>
array('fields' => array('Account.id',
'Account.name'),
),
if ($transaction['Transaction']['type'] === 'DEPOSIT')
$this->addSideMenuLink('View Slip',
array('action' => 'deposit_slip', $id), null,
'ACTION');
'Ledger' =>
array('fields' => array('Ledger.id',
'Ledger.name'),
),
),
'conditions' => array('Transaction.id' => $id),
));
$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);
if ($transaction['Transaction']['type'] === 'DEPOSIT') {
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'View Slip', 'url' => array('action' => 'deposit_slip', $id));
}
// OK, prepare to render.
$title = 'Transaction #' . $transaction['Transaction']['id'];
@@ -458,12 +404,15 @@ class TransactionsController extends AppController {
*/
function deposit_slip($id) {
// Find the deposit transaction
$this->Transaction->id = $id;
$deposit = $this->Transaction->find('first', array('contain' => false));
// Build a container for the deposit slip data
$deposit = array('types' => array());
$this->id = $id;
$deposit +=
$this->Transaction->find('first', array('contain' => false));
// Get a summary of all forms of tender in the deposit
$tenders = $this->Transaction->find
$result = $this->Transaction->find
('all',
array('link' => array('DepositTender' =>
array('fields' => array(),
@@ -478,29 +427,32 @@ class TransactionsController extends AppController {
'group' => 'TenderType.id',
));
// Verify the deposit exists, and that something was actually deposited
if (empty($deposit) || empty($tenders)) {
if (empty($result)) {
die();
$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];
foreach ($result AS $type) {
$deposit['types'][$type['TenderType']['id']] =
$type['TenderType'] + $type[0];
}
$deposit_total = 0;
foreach ($deposit['types'] AS $type)
$deposit_total += $type['total'];
// For each form of tender in the deposit, get the deposit items
/* foreach ($deposit['types'] AS $type_id => &$type) { */
/* $type['entries'] = $this->Transaction->DepositTender->find */
/* ('all', */
/* array('contain' => array('Customer', 'LedgerEntry'), */
/* 'conditions' => array(array('DepositTender.deposit_transaction_id' => $id), */
/* array('DepositTender.tender_type_id' => $type_id)), */
/* )); */
/* } */
if ($deposit['Transaction']['amount'] != $deposit_total)
$this->INTERNAL_ERROR("Deposit items do not add up to deposit slip total");
$this->addSideMenuLink('View',
array('action' => 'view', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
$this->sidemenu_links[] =
array('name' => 'View Transaction', 'url' => array('action' => 'view', $id));
$title = 'Deposit Slip';
$this->set(compact('title', 'deposit'));

View File

@@ -1,238 +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 gridDataPostProcessLinks(&$params, &$model, &$records, $links) {
$links['UnitSize'] = array('name');
return parent::gridDataPostProcessLinks($params, $model, $records, $links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: view
* - Displays information about a specific entry
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('controller' => 'accounts', 'action'=>'index'));
}
// Get the UnitSize and related fields
$this->UnitSize->id = $id;
$size = $this->UnitSize->find
('first', array
('contain' => array('UnitType'),
'fields' => array('UnitSize.*', 'UnitType.*',
'ROUND(UnitSize.width/12, 1) AS width',
'ROUND(UnitSize.depth/12, 1) AS depth',
'ROUND(UnitSize.height/12, 1) AS height',
'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft',
'ROUND(UnitSize.width/12 * UnitSize.depth/12 * UnitSize.height/12, 0) AS cuft'),
));
$size['UnitSize'] = $size[0] + $size['UnitSize'];
unset($size[0]);
$this->set(compact('size'));
$this->set('stats', $this->UnitSize->stats($id));
// Prepare to render.
$title = "Unit Size : {$size['UnitSize']['name']}";
$this->set(compact('title'));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: edit
* - Edit unit_size information
*/
function edit($id = null) {
$this->INTERNAL_ERROR('NOT READY');
if (isset($this->data)) {
// Check to see if the operation was cancelled.
if (isset($this->params['form']['cancel'])) {
if (empty($this->data['UnitSize']['id']))
$this->redirect(array('action'=>'index'));
$this->redirect(array('action'=>'view', $this->data['UnitSize']['id']));
}
// Make sure we have unit_size data
if (empty($this->data['UnitSize']) || empty($this->data['UnitSize']['id']))
$this->redirect(array('action'=>'index'));
// Save the unit_size and all associated data
$this->UnitSize->create();
$this->UnitSize->id = $this->data['UnitSize']['id'];
if (!$this->UnitSize->save($this->data, false)) {
$this->Session->setFlash("UNIT_SIZE SAVE FAILED", true);
pr("UNIT_SIZE SAVE FAILED");
}
$this->redirect(array('action'=>'view', $this->UnitSize->id));
}
if ($id) {
$this->data = $this->UnitSize->findById($id);
} else {
$this->redirect(array('action'=>'index'));
}
// Prepare to render.
$title = ('UnitSize ' . $this->data['UnitSize']['name'] .
" : Edit");
$this->set(compact('title'));
}
}

View File

@@ -2,38 +2,26 @@
class UnitsController extends AppController {
var $sidemenu_links =
array(array('name' => 'Units', 'header' => true),
array('name' => 'Occupied', 'url' => array('controller' => 'units', 'action' => 'occupied')),
array('name' => 'Vacant', 'url' => array('controller' => 'units', 'action' => 'vacant')),
array('name' => 'Unavailable', 'url' => array('controller' => 'units', 'action' => 'unavailable')),
array('name' => 'All', 'url' => array('controller' => 'units', 'action' => 'all')),
);
/**************************************************************************
**************************************************************************
**************************************************************************
* override: addGridViewSideMenuLinks
* - Adds grid view navigation side menu links
* override: sideMenuLinks
* - Generates controller specific links for the side menu
*/
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');
function sideMenuLinks() {
return array_merge(parent::sideMenuLinks(), $this->sidemenu_links);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -45,8 +33,6 @@ class UnitsController extends AppController {
function unavailable() { $this->gridView('Unavailable Units'); }
function vacant() { $this->gridView('Vacant Units'); }
function occupied() { $this->gridView('Occupied Units'); }
function locked() { $this->gridView('Overlocked Units'); }
function liened() { $this->gridView('Liened Units'); }
function all() { $this->gridView('All Units', 'all'); }
@@ -95,7 +81,6 @@ class UnitsController extends AppController {
function gridDataFields(&$params, &$model) {
$fields = parent::gridDataFields($params, $model);
$fields[] = 'ROUND(UnitSize.width/12 * UnitSize.depth/12, 0) AS sqft';
return array_merge($fields,
$this->Unit->Lease->StatementEntry->chargeDisbursementFields(true));
}
@@ -115,12 +100,6 @@ class UnitsController extends AppController {
elseif ($params['action'] === 'unoccupied') {
$conditions[] = array('NOT' => array($this->Unit->conditionOccupied()));
}
elseif ($params['action'] === 'locked') {
$conditions[] = $this->Unit->conditionLocked();
}
elseif ($params['action'] === 'liened') {
$conditions[] = $this->Unit->conditionLiened();
}
return $conditions;
}
@@ -160,7 +139,7 @@ class UnitsController extends AppController {
$customer = array();
$unit = array();
if (!empty($id)) {
if (isset($id)) {
$this->Unit->recursive = -1;
$unit = current($this->Unit->read(null, $id));
}
@@ -210,21 +189,6 @@ class UnitsController extends AppController {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: lock/unlock
* - Transitions the unit into / out of the LOCKED state
*/
function status($id, $status) {
$this->Unit->updateStatus($id, $status, true);
$this->redirect(array('action' => 'view', $id));
}
function lock($id) { $this->status($id, 'LOCKED'); }
function unlock($id) { $this->status($id, 'OCCUPIED'); }
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -268,66 +232,37 @@ class UnitsController extends AppController {
$outstanding_deposit = $this->Unit->Lease->securityDepositBalance($unit['CurrentLease']['id']);
}
// If the unit is occupied, but not locked, provide a
// mechanism to do so. This doesn't have to be restricted
// to past due customers. There are times we need to
// overlock customers in good standing, such as if their
// lock breaks, is cut, or missing for any reason.
if ($this->Unit->occupied($unit['Unit']['status']) &&
!$this->Unit->locked($unit['Unit']['status']))
$this->addSideMenuLink('Lock',
array('action' => 'Lock', $id), null,
'ACTION');
// Set up dynamic menu items
$this->sidemenu_links[] =
array('name' => 'Operations', 'header' => true);
// If the unit is locked, provide an option to unlock it,
// unless it's locked due to lien, which is not so simple.
if ($this->Unit->locked($unit['Unit']['status']) &&
!$this->Unit->liened($unit['Unit']['status']))
$this->addSideMenuLink('Unlock',
array('action' => 'unlock', $id), null,
'ACTION');
$this->sidemenu_links[] =
array('name' => 'Edit', 'url' => array('action' => 'edit',
$id));
// If there is a current lease on this unit, then provide
// a link to move the tenant out. Current lease for a unit
// has a bit different definition than a current lease for
// a customer, since a lease stays with a customer until it
// is finally closed. A lease, however, only stays with a
// unit while occupied (since a unit is not responsible for
// any lingering financial obligations, like a customer is).
// Of course, if there is no current lease, provide a link
// to move a new tenant in (if the unit is available).
if (isset($unit['CurrentLease']['id'])) {
$this->addSideMenuLink('Move-Out',
array('action' => 'move_out', $id), null,
'ACTION');
} elseif ($this->Unit->available($unit['Unit']['status'])) {
$this->addSideMenuLink('Move-In',
array('action' => 'move_in', $id), null,
'ACTION');
if (isset($unit['CurrentLease']['id']) &&
!isset($unit['CurrentLease']['moveout_date'])) {
$this->sidemenu_links[] =
array('name' => 'Move-Out', 'url' => array('action' => 'move_out',
$id));
} else {
// Unit is unavailable (dirty, damaged, reserved, business-use, etc)
$this->sidemenu_links[] =
array('name' => 'Move-In', 'url' => array('action' => 'move_in',
$id));
}
// If there is a current lease, allow new charges to
// be added, and payments to be made.
if (isset($unit['CurrentLease']['id'])) {
$this->addSideMenuLink('New Invoice',
array('controller' => 'leases',
'action' => 'invoice',
$unit['CurrentLease']['id']), null,
'ACTION');
$this->addSideMenuLink('New Receipt',
array('controller' => 'customers',
'action' => 'receipt',
$unit['CurrentLease']['customer_id']), null,
'ACTION');
if (isset($unit['CurrentLease']['id']) &&
!isset($unit['CurrentLease']['close_date'])) {
$this->sidemenu_links[] =
array('name' => 'Charge', 'url' => array('controller' => 'leases',
'action' => 'invoice',
$unit['CurrentLease']['id']));
$this->sidemenu_links[] =
array('name' => 'Payment', 'url' => array('controller' => 'customers',
'action' => 'receipt',
$unit['CurrentLease']['customer_id']));
}
// 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',
@@ -370,6 +305,11 @@ class UnitsController extends AppController {
}
$this->redirect(array('action'=>'view', $this->Unit->id));
// For debugging, only if the redirects above have been
// commented out, otherwise this section isn't reached.
$this->render('/fake');
return;
}
if ($id) {
@@ -391,6 +331,7 @@ class UnitsController extends AppController {
$this->set(compact('unit_sizes'));
// Prepare to render.
pr($this->data);
$this->set(compact('title'));
}

View File

@@ -1,76 +0,0 @@
<?php
class UtilController extends AppController {
var $uses = array();
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reset_data
* - Development function. TO BE DELETED
*/
function reset_data() {
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
$script = $_SERVER['DOCUMENT_ROOT'] . '/pmgr/build.cmd';
echo "<P>" . date('r') . "\n";
//echo "<P>Script: $script" . "\n";
$handle = popen($script . ' 2>&1', 'r');
//echo "<P>Handle: $handle; " . gettype($handle) . "\n";
echo "<P><PRE>\n";
while (($read = fread($handle, 2096))) {
echo $read;
}
echo "</PRE>\n";
pclose($handle);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: rebuild_box
*/
function rebuild_box($type) {
$this->layout = null;
$this->autoLayout = false;
$this->autoRender = false;
Configure::write('debug', '0');
$script = preg_replace('%/webroot/index.php$%',
'/build_'.$type.'box.cmd',
$_SERVER['SCRIPT_FILENAME']);
// REVISIT <AP>: 20090828
// Just use system call
$handle = popen($script . ' 2>&1', 'r');
while (($read = fread($handle, 2096))) {
// Do nothing
}
pclose($handle);
$url = $_SERVER['HTTP_REFERER'];
if (empty($url))
$url = "/";
$this->redirect($url);
}
function rebuild_sandbox() { $this->rebuild_box('sand'); }
function rebuild_devbox() { $this->rebuild_box('dev'); }
/**************************************************************************
**************************************************************************
**************************************************************************
* function: logmsg
* - action to allow posting log message data
*/
function logmsg() {
}
}

View File

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

View File

@@ -41,15 +41,14 @@ class Contact extends AppModel {
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'])
if (!$data['Contact']['display_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];
}
(($data['Contact']['first_name'] &&
$data['Contact']['last_name'])
? $data['Contact']['last_name'] . ', ' . $data['Contact']['first_name']
: ($data['Contact']['first_name']
? $data['Contact']['first_name']
: $data['Contact']['last_name']));
// Save the contact data
$this->create();

View File

@@ -54,19 +54,17 @@ class Customer extends AppModel {
* function: leaseIds
* - Returns the lease IDs for the given customer
*/
function leaseIds($id, $current = false) {
$Lease = $current ? 'CurrentLease' : 'Lease';
function leaseIds($id) {
$this->cacheQueries = true;
$customer = $this->find('first',
array('contain' =>
array($Lease => array('fields' => array('id'))),
array('Lease' => array('fields' => array('id'))),
'fields' => array(),
'conditions' => array(array('Customer.id' => $id))));
$this->cacheQueries = false;
$ids = array();
foreach ($customer[$Lease] AS $lease)
foreach ($customer['Lease'] AS $lease)
$ids[] = $lease['id'];
return $ids;
@@ -103,35 +101,12 @@ class Customer extends AppModel {
$this->prEnter(compact('id', 'query'));
$this->queryInit($query);
$sd_account_id =
$this->StatementEntry->Account->securityDepositAccountID();
$query['conditions'][] = array('StatementEntry.customer_id' => $id);
$query['conditions'][] = array('StatementEntry.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']);
$stats = $this->StatementEntry->stats(null, $query);
return $this->prReturn($stats['account_balance']);
}
@@ -167,8 +142,10 @@ class Customer extends AppModel {
continue;
$I = new Contact();
if (!$I->saveContact(null, array('Contact' => $contact)))
$I->create();
if (!$I->save($contact, false)) {
return false;
}
$contact['id'] = $I->id;
}
@@ -226,52 +203,6 @@ class Customer extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
$this->prEnter(compact('id'));
if (empty($id)) {
$customers = $this->find('all', array('contain' => false, 'fields' => array('id')));
foreach ($customers AS $customer) {
// This SHOULDN'T happen, but check to be sure
// or we'll get infinite recursion.
if (empty($customer['Customer']['id']))
continue;
$this->update($customer['Customer']['id']);
}
return;
}
// updateLeaseCount is typically handled directly when needed.
// However, this function is used to _ensure_ customer info is
// current, so we're obligated to call it anyway.
$this->updateLeaseCount($id);
$current_leases =
$this->find('all',
// REVISIT <AP>: 20090816
// Do we need to update leases other than the current ones?
// It may be necessary. For example, a non-current lease
// can still be hit with an NSF item. In that case, it
// could have stale data if we look only to current leases.
//array('link' => array('CurrentLease' => array('type' => 'INNER')),
array('link' => array('Lease' => array('type' => 'INNER')),
'conditions' => array('Customer.id' => $id)));
foreach ($current_leases AS $lease) {
if (!empty($lease['CurrentLease']['id']))
$this->Lease->update($lease['CurrentLease']['id']);
if (!empty($lease['Lease']['id']))
$this->Lease->update($lease['Lease']['id']);
}
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -53,27 +53,12 @@ class DoubleEntry extends AppModel {
*/
function addDoubleEntry($entry1, $entry2, $entry1_tender = null) {
//$this->prFunctionLevel(16);
$this->prEnter(compact('entry1', 'entry2', 'entry1_tender'));
/* pr(array('DoubleEntry::addDoubleEntry' => */
/* 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));
return array('error' => true) + $ret;
// Since this model only relates to DebitEntry and CreditEntry...
$LE = new LedgerEntry();
@@ -82,13 +67,13 @@ class DoubleEntry extends AppModel {
$result = $LE->addLedgerEntry($entry1, $entry1_tender);
$ret['Entry1'] = $result;
if ($result['error'])
return $this->prReturn(array('error' => true) + $ret);
return 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);
return array('error' => true) + $ret;
// Now link them as a double entry
$double_entry = array();
@@ -97,13 +82,15 @@ class DoubleEntry extends AppModel {
$double_entry['credit_entry_id'] =
($entry1['crdr'] === 'CREDIT') ? $ret['Entry1']['ledger_entry_id'] : $ret['Entry2']['ledger_entry_id'];
$ret['data'] = $double_entry;
/* pr(array('DoubleEntry::addDoubleEntry' => */
/* array('checkpoint' => 'Pre-Save') */
/* + compact('double_entry'))); */
$this->create();
if (!$this->save($double_entry))
return $this->prReturn(array('error' => true) + $ret);
return array('error' => true) + $ret;
$ret['double_entry_id'] = $this->id;
return $this->prReturn($ret + array('error' => false));
return $ret + array('error' => false);
}
}

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -12,7 +12,7 @@ class Lease extends AppModel {
'StatementEntry',
);
//var $default_log_level = array('log' => 30, 'show' => 30);
//var $default_log_level = array('log' => 30, 'show' => 15);
/**************************************************************************
**************************************************************************
@@ -44,26 +44,26 @@ class Lease extends AppModel {
$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());
// REVISIT <AP>: 20090804
// Dilemma... how to handle security deposits used to pay
// charges on the lease, yet are not part of the lease
// security deposit(s)? For example, Lease A & Lease B,
// each with $25 Sec. Dep. Move out of Lease A, and
// promote the lease surplus to the customer. A new
// charge on Lease B for $15, which is assigned $15/$25
// from the promoted Lease A surplus. They way this
// function works at present, it will presume the $15 is
// part of the security deposit balance, and will end up
// calculating it as only $10, which is wrong. Perhaps
// the fix is to release security deposits into some sort
// of income account.
$stats = $this->StatementEntry->stats(null, $query);
return $this->prReturn($stats['Charge']['disbursement']);
return $this->prReturn($stats['account_balance']);
}
@@ -113,12 +113,8 @@ class Lease extends AppModel {
$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);
($release, $customer_id, $lease_id);
return $this->prReturn($result);
}
@@ -150,7 +146,6 @@ class Lease extends AppModel {
'conditions' => array
('SEx.effective_date = DATE_ADD(StatementEntry.through_date, INTERVAL 1 day)',
'SEx.lease_id = StatementEntry.lease_id',
'SEx.reverse_transaction_id IS NULL',
),
),
),
@@ -160,7 +155,6 @@ class Lease extends AppModel {
'conditions' => array(array('Lease.id' => $id),
array('StatementEntry.type' => 'CHARGE'),
array('StatementEntry.account_id' => $rent_account_id),
array('StatementEntry.reverse_transaction_id IS NULL'),
array('SEx.id' => null),
),
)
@@ -170,35 +164,6 @@ class Lease extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* 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);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -261,9 +226,7 @@ class Lease extends AppModel {
'conditions' =>
array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id),
array('StatementEntry.reverse_transaction_id IS NULL'),
),
array('StatementEntry.account_id' => $rent_account_id)),
'order' => array('StatementEntry.effective_date'),
),
@@ -282,9 +245,7 @@ class Lease extends AppModel {
('CHARGE',
array('conditions' =>
array(array('StatementEntry.lease_id' => $id),
array('StatementEntry.account_id' => $rent_account_id),
array('StatementEntry.reverse_transaction_id IS NULL'),
),
array('StatementEntry.account_id' => $rent_account_id)),
'order' => array('StatementEntry.through_date DESC'),
),
@@ -302,261 +263,6 @@ class Lease extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: assessMonthlyRent
* - Charges rent for the month, if not already charged.
*/
function assessMonthlyRent($id, $date = null) {
$this->prEnter(compact('id', 'date'));
$this->id = $id;
if (empty($date))
$date = time();
if (is_string($date))
$date = strtotime($date);
// REVISIT <AP>: 20090808
// Anniversary Billing not supported
$anniversary = 0 && $this->field('anniversary_billing');
if (empty($anniversary)) {
$date_parts = getdate($date);
$date = mktime(0, 0, 0, $date_parts['mon'], 1, $date_parts['year']);
}
// Make sure we're not trying to assess rent on a closed lease
$close_date = $this->field('close_date');
$this->pr(17, compact('close_date'));
if (!empty($close_date))
return $this->prReturn(null);
// Don't assess rent after customer has moved out
$moveout_date = $this->field('moveout_date');
$this->pr(17, compact('moveout_date'));
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
return $this->prReturn(null);
// Determine when the customer has already been charged through
// and, of course, don't charge them if they've already been.
$charge_through_date = strtotime($this->rentChargeThrough($id));
$this->pr(17, compact('date', 'charge_through_date')
+ array('date_str' => date('Y-m-d', $date),
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
if ($charge_through_date >= $date)
return $this->prReturn(null);
// OK, it seems we're going to go ahead and charge the customer
// on this lease. Calculate the new charge through date, which
// is 1 day shy of 1 month from $date. For example, if we're
// charging for 8/1/09, charge through will be 8/31/09, and
// charging for 8/15/09, charge through will be 9/14/09.
$date_parts = getdate($date);
$charge_through_date = mktime(0, 0, 0,
$date_parts['mon']+1,
$date_parts['mday']-1,
$date_parts['year']);
// Build the invoice transaction
$invoice = array('Transaction' => array(), 'Entry' => array());
// REVISIT <AP>: 20090808
// Keeping Transaction.stamp until the existing facility
// is up to date. Then we want the stamp to be now()
// (and so can just delete the next line).
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
$invoice['Entry'][] =
array('effective_date' => date('Y-m-d', $date),
'through_date' => date('Y-m-d', $charge_through_date),
'amount' => $this->field('rent'),
'account_id' => $this->StatementEntry->Account->rentAccountId(),
);
// Record the invoice and return the result
$this->pr(21, compact('invoice'));
$result = $this->StatementEntry->Transaction->addInvoice
($invoice, null, $id);
return $this->prReturn($result);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: assessMonthlyRentAll
* - Ensures rent has been charged on all open leases
*/
function assessMonthlyRentAll($date = null) {
$this->prEnter(compact('date'));
$leases = $this->find
('all', array('contain' => false,
'conditions' => array('Lease.close_date' => null),
));
$ret = array('Lease' => array());
foreach ($leases AS $lease) {
$result = $this->assessMonthlyRent($lease['Lease']['id'], $date);
$ret['Lease'][$lease['Lease']['id']] = $result;
if ($result['error'])
$ret['error'] = true;
}
return $this->prReturn($ret + array('error' => false));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: assessMonthlyLate
* - Assess late charges for the month, if not already charged.
*/
function assessMonthlyLate($id, $date = null) {
$this->prEnter(compact('id', 'date'));
$this->id = $id;
if (empty($date))
$date = time();
if (is_string($date))
$date = strtotime($date);
// REVISIT <AP>: 20090808
// Anniversary Billing not supported
$anniversary = 0 && $this->field('anniversary_billing');
if (empty($anniversary)) {
$date_parts = getdate($date);
$date = mktime(0, 0, 0, $date_parts['mon'], 11, $date_parts['year']);
}
// Don't assess a late charge if the late charge date hasn't
// even come yet. This is questionable whether we really
// should restrict, since the user could know what they're
// doing, and/or the server clock could be off (although that
// would certainly have much larger ramifications). But, the
// fact is that this check likely handles the vast majority
// of the expected behavior, and presents an issue for very
// few users, if any at all.
if ($date > time())
return $this->prReturn(null);
// Make sure we're not trying to assess late charges on a closed lease
$close_date = $this->field('close_date');
$this->pr(17, compact('close_date'));
if (!empty($close_date))
return $this->prReturn(null);
// Don't assess late charges after customer has moved out
$moveout_date = $this->field('moveout_date');
$this->pr(17, compact('moveout_date'));
if (!empty($moveout_date) && strtotime($moveout_date) < $date)
return $this->prReturn(null);
// Determine when the customer has been charged through for rent
// and don't mark them as late if they haven't even been charged rent
$charge_through_date = strtotime($this->rentChargeThrough($id));
$this->pr(17, compact('date', 'charge_through_date')
+ array('date_str' => date('Y-m-d', $date),
'charge_through_date_str' => date('Y-m-d', $charge_through_date)));
if ($charge_through_date <= $date)
return $this->prReturn(null);
// Determine if the customer is actually late. This is based on
// when they've paid through, plus 10 days before they're late.
// REVISIT <AP>: 20090813
// Of course, 10 days is a terrible hardcode. This should be
// driven from the late schedule, saved as part of the lease
// (when finally implemented).
$paid_through_date = strtotime($this->rentPaidThrough($id));
$this->pr(17, compact('date', 'paid_through_date')
+ array('date_str' => date('Y-m-d', $date),
'paid_through_date_str' => date('Y-m-d', $paid_through_date)));
$date_parts = getdate($paid_through_date);
$paid_through_date = mktime(0, 0, 0, $date_parts['mon'], $date_parts['mday']+10, $date_parts['year']);
if ($paid_through_date >= $date)
return $this->prReturn(null);
// Determine if the customer has already been charged a late fee
// and, of course, don't charge them if they've already been.
$late_charges = $this->lateCharges($id);
foreach ($late_charges AS $late) {
if (strtotime($late['StatementEntry']['effective_date']) == $date)
return $this->prReturn(null);
}
// Build the invoice transaction
$invoice = array('Transaction' => array(), 'Entry' => array());
// REVISIT <AP>: 20090808
// Keeping Transaction.stamp until the existing facility
// is up to date. Then we want the stamp to be now()
// (and so can just delete the next line).
$invoice['Transaction']['stamp'] = date('Y-m-d', $date);
$invoice['Entry'][] =
array('effective_date' => date('Y-m-d', $date),
'amount' => 10,
'account_id' => $this->StatementEntry->Account->lateChargeAccountId(),
);
// Record the invoice and return the result
$this->pr(21, compact('invoice'));
$result = $this->StatementEntry->Transaction->addInvoice
($invoice, null, $id);
return $this->prReturn($result);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: assessMonthlyLateAll
* - Ensures rent has been charged on all open leases
*/
function assessMonthlyLateAll($date = null) {
$this->prEnter(compact('date'));
$leases = $this->find
('all', array('contain' => false,
'conditions' => array('Lease.close_date' => null),
));
$ret = array('Lease' => array());
foreach ($leases AS $lease) {
$result = $this->assessMonthlyLate($lease['Lease']['id'], $date);
$ret['Lease'][$lease['Lease']['id']] = $result;
if ($result['error'])
$ret['error'] = true;
}
return $this->prReturn($ret + array('error' => false));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* functions: delinquency
* - SQL fragments to determine whether a lease is delinquent
*/
function conditionDelinquent($table_name = 'Lease') {
if (empty($table_name)) $t = ''; else $t = $table_name . '.';
return ("({$t}close_date IS NULL AND" .
" NOW() > DATE_ADD({$t}paid_through_date, INTERVAL 10 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'");
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -655,7 +361,7 @@ class Lease extends AppModel {
*/
function moveOut($id, $status = 'VACANT',
$stamp = null, $close = true)
$stamp = null, $close = false)
{
$this->prEnter(compact('id', 'status', 'stamp', 'close'));
@@ -745,13 +451,12 @@ class Lease extends AppModel {
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);
$deposit_balance = $this->securityDepositBalance($id);
$stats = $this->stats($id);
// ... and if the account balance is zero.
if ($this->balance($id) != 0)
// A lease can only be closed if there are no outstanding
// security deposits, and if the account balance is zero.
if ($deposit_balance != 0)
return $this->prReturn(false);
// Apparently this lease meets all the criteria!
@@ -790,25 +495,6 @@ class Lease extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
$this->prEnter(compact('id'));
$this->id = $id;
$this->saveField('charge_through_date', $this->rentChargeThrough($id));
$this->saveField('paid_through_date', $this->rentPaidThrough($id));
$moveout = $this->field('moveout_date');
if (empty($moveout))
$this->Unit->update($this->field('unit_id'));
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

@@ -8,22 +8,8 @@ class LedgerEntry extends AppModel {
);
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,
),
'Tender',
'DoubleEntry',
);
var $hasMany = array(
@@ -127,20 +113,24 @@ class LedgerEntry extends AppModel {
* - Inserts new Ledger Entry into the database
*/
function addLedgerEntry($entry, $tender = null) {
//$this->prFunctionLevel(16);
$this->prEnter(compact('entry', 'tender'));
/* pr(array('LedgerEntry::addLedgerEntry' => */
/* compact('entry', 'tender'))); */
$ret = array('data' => $entry);
$ret = array();
if (!$this->verifyLedgerEntry($entry, $tender))
return $this->prReturn(array('error' => true) + $ret);
return array('error' => true) + $ret;
if (empty($entry['ledger_id']))
$entry['ledger_id'] =
$this->Account->currentLedgerID($entry['account_id']);
/* pr(array('LedgerEntry::addLedgerEntry' => */
/* array('checkpoint' => 'Pre-Save') */
/* + compact('entry'))); */
$this->create();
if (!$this->save($entry))
return $this->prReturn(array('error' => true) + $ret);
return array('error' => true) + $ret;
$ret['ledger_entry_id'] = $this->id;
@@ -150,10 +140,10 @@ class LedgerEntry extends AppModel {
$result = $this->Tender->addTender($tender);
$ret['Tender'] = $result;
if ($result['error'])
return $this->prReturn(array('error' => true) + $ret);
return array('error' => true) + $ret;
}
return $this->prReturn($ret + array('error' => false));
return $ret + array('error' => false);
}
@@ -165,13 +155,53 @@ class LedgerEntry extends AppModel {
*/
function stats($id = null, $query = null, $set = null) {
$this->queryInit($query);
unset($query['group']);
// 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');
if (!isset($query['link']['DoubleEntry']))
$query['link']['DoubleEntry'] = array();
/* if (!isset($query['link']['DoubleEntry']['fields'])) */
/* $query['link']['DoubleEntry']['fields'] = array(); */
if (isset($id))
$query['conditions'][] = array('Entry.id' => $id);
if (isset($set))
$set = strtoupper($set);
//pr(array('stats()', compact('id', 'query', 'set')));
$rtypes = array('charge', 'disbursement',
// 'debit', 'credit',
);
$stats = array();
foreach($rtypes AS $rtype) {
$Rtype = ucfirst($rtype);
if (($rtype == 'charge' && (!isset($set) || $set == 'DISBURSEMENT')) ||
($rtype == 'disbursement' && (!isset($set) || $set == 'CHARGE'))
) {
$rquery = $query;
$rquery['link'][$Rtype] =
array('fields' => array("SUM(COALESCE(Applied{$Rtype}.amount,0)) AS reconciled"));
$rquery['fields'] = array();
//$rquery['fields'][] = "SUM(DoubleEntry.amount) AS total";
$rquery['fields'][] = "SUM(DoubleEntry.amount) - SUM(COALESCE(Applied{$Rtype}.amount,0)) AS balance";
$rquery['conditions'][] = array("Applied{$Rtype}.id !=" => null);
$result = $this->find('first', $rquery);
//pr(compact('Rtype', 'rquery', 'result'));
$sumfld = $Rtype;
$stats[$sumfld] = $result[0];
/* if (!isset($stats[$sumfld]['applied'])) */
/* $stats[$sumfld]['applied'] = 0; */
}
}
return $stats;
}
}

15
site/models/maps_unit.php Normal file
View File

@@ -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')
);
}
?>

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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']);
}
}

View File

@@ -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);
}
}

View File

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

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -18,13 +18,11 @@ class StatementEntry extends AppModel {
'DisbursementEntry' => array(
'className' => 'StatementEntry',
'foreignKey' => 'charge_entry_id',
'dependent' => true,
),
);
//var $default_log_level = array('log' => 30, 'show' => 15);
var $max_log_level = 19;
var $default_log_level = array('log' => 30, 'show' => 15);
/**************************************************************************
**************************************************************************
@@ -37,7 +35,7 @@ class StatementEntry extends AppModel {
}
function creditTypes() {
return array('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'WRITEOFF', 'SURPLUS');
return array('DISBURSEMENT', 'WAIVER', 'REVERSAL', 'SURPLUS');
}
function voidTypes() {
@@ -125,13 +123,16 @@ class StatementEntry extends AppModel {
function addStatementEntry($entry) {
$this->prEnter(compact('entry'));
$ret = array('data' => $entry);
$ret = array();
if (!$this->verifyStatementEntry($entry))
return $this->prReturn(array('error' => true, 'verify_data' => $entry) + $ret);
return array('error' => true, 'verify_data' => $entry) + $ret;
$this->pr(20, array('checkpoint' => 'Pre-Save')
+ compact('entry'));
$this->create();
if (!$this->save($entry))
return $this->prReturn(array('error' => true, 'save_data' => $entry) + $ret);
return array('error' => true, 'save_data' => $entry) + $ret;
$ret['statement_entry_id'] = $this->id;
return $this->prReturn($ret + array('error' => false));
@@ -154,7 +155,7 @@ class StatementEntry extends AppModel {
$charge = $charge['StatementEntry'];
if ($charge['type'] !== 'CHARGE')
$this->INTERNAL_ERROR("Waiver item is not CHARGE.");
INTERNAL_ERROR("Waiver item is not CHARGE.");
// Query the stats to get the remaining balance
$stats = $this->stats($id);
@@ -167,6 +168,7 @@ class StatementEntry extends AppModel {
// Add the charge waiver
$waiver['Entry'][] =
array('amount' => $stats['Charge']['balance'],
'account_id' => $this->Account->waiverAccountID(),
'comment' => null,
);
@@ -176,64 +178,89 @@ class StatementEntry extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reversable
* - Returns true if the charge can be reversed; false otherwise
*/
function reversable($id) {
$this->prEnter(compact('id'));
if (empty($id))
return $this->prReturn(false);
// Verify the item is an actual charge
$this->id = $id;
$charge_type = $this->field('type');
if ($charge_type !== 'CHARGE')
return $this->prReturn(false);
// Determine anything reconciled against the charge
$reverse_transaction_id = $this->field('reverse_transaction_id');
if (!empty($reverse_transaction_id))
return $this->prReturn(false);
return $this->prReturn(true);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: reverse
* - Reverses the charges
*
*/
function reverse($id, $stamp = null, $comment) {
$this->prEnter(compact('id', 'stamp'));
function reverse($id, $balance = false, $stamp = null) {
$this->prEnter(compact('id', 'balance', 'stamp'));
// Verify the item can be reversed
if (!$this->reversable($id))
$this->INTERNAL_ERROR("Item is not reversable.");
$ret = array();
// Get the basic information about this charge
$charge = $this->find('first', array('contain' => true));
//$charge = $charge['StatementEntry'];
// Get the basic information about the entry to be reversed.
$this->recursive = -1;
$charge = $this->read(null, $id);
$charge = $charge['StatementEntry'];
if ($charge['type'] !== 'CHARGE')
INTERNAL_ERROR("Reversal item is not CHARGE.");
// Build a transaction
$reversal = array('Transaction' => array(), 'Entry' => array());
$reversal['Transaction']['stamp'] = $stamp;
$reversal['Transaction']['comment'] = "Credit Note: Charge Reversal";
$voided_entry_transactions = array();
$reconciled = $this->reconciledEntries($id);
$this->pr(21, compact('reconciled'));
if ($reconciled && !$balance) {
foreach ($reconciled['entries'] AS $entry) {
if ($entry['DisbursementEntry']['type'] === 'REVERSAL')
INTERNAL_ERROR("Charge has already been reversed");
/* $voided_entry_transactions[$entry['DisbursementEntry']['transaction_id']] */
/* = array_intersect_key($entry['DisbursementEntry'], */
/* array('customer_id'=>1, 'lease_id'=>1)); */
/* $reversal['Entry'][] = */
/* array_intersect_key($entry['DisbursementEntry'], */
/* array_flip(array('amount', 'account_id', 'charge_entry_id'))) */
/* + array('type' => 'SURPLUS', */
/* 'comment' => 'Release of funds applied to reversed charge', */
/* ); */
}
/* $this->pr(17, compact('voided_entry_transactions')); */
}
// Query the stats to get the remaining balance
$stats = $this->stats($id);
$charge['paid'] = $stats['Charge']['disbursement'];
// Add the charge reversal
$reversal['Entry'][] =
array('charge_entry_id' => $id,
'amount' => -1 * $stats['Charge'][$balance ? 'balance' : 'total'],
'account_id' => $charge['account_id'],
'comment' => 'Charge Reversal',
);
// Record the reversal transaction
$result = $this->Transaction->addReversal
($charge, $stamp, $comment ? $comment : 'Charge Reversal');
($reversal, $id, $charge['customer_id'], $charge['lease_id']);
$this->pr(21, compact('result'));
$ret['reversal'] = $result;
if ($result['error'])
$ret['error'] = true;
if (empty($result['error'])) {
// Mark the charge as reversed
$this->id = $id;
$this->saveField('reverse_transaction_id', $result['transaction_id']);
foreach ($voided_entry_transactions AS $transaction_id => $tx) {
$result = $this->assignCredits
(null,
$transaction_id,
null,
null,
$tx['customer_id'],
$tx['lease_id']
);
$this->pr(21, compact('result'));
$ret['assigned'][] = $result;
if ($result['error'])
$ret['error'] = true;
}
return $this->prReturn($result);
return $this->prReturn($ret + array('error' => false));
}
@@ -369,11 +396,10 @@ class StatementEntry extends AppModel {
// 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");
// REVISIT <AP>: 20090806
// If the theory below is correct, we should only search for
// explicit credits if we don't have a receipt_id
if (empty($charge_ids)) {
$lquery = $query;
$lquery['conditions'][] = array('StatementEntry.type' => 'SURPLUS');
// REVISIT <AP>: 20090804
@@ -398,13 +424,20 @@ class StatementEntry extends AppModel {
"Credits Established");
}
else {
// Establish credit from the (newly added) receipt
if (empty($receipt_id))
INTERNAL_ERROR("Can't make adjustments to a charge without a receipt ID.");
}
// Next, establish credit from the newly added receipt
$receipt_credit = null;
if (!empty($receipt_id)) {
$lquery =
array('link' =>
array('StatementEntry',
'LedgerEntry' =>
array('conditions' =>
array('LedgerEntry.account_id <> Transaction.account_id')
array('LedgerEntry.account_id !=' =>
$this->Account->accountReceivableAccountID()),
),
),
'conditions' => array('Transaction.id' => $receipt_id),
@@ -412,14 +445,15 @@ class StatementEntry extends AppModel {
);
$receipt_credit = $this->Transaction->find('first', $lquery);
if (!$receipt_credit)
$this->INTERNAL_ERROR("Unable to locate receipt.");
INTERNAL_ERROR("Unable to locate receipt.");
//$reconciled = $this->reconciledEntries($id);
$stats = $this->Transaction->stats($receipt_id);
$receipt_credit['balance'] = $stats['undisbursed'];
$receipt_credit['balance'] =
$receipt_credit['Transaction']['amount'] - $stats['Disbursement']['total'];
$receipt_credit['receipt'] = true;
$credits = array($receipt_credit);
$this->pr(18, compact('credits'),
$this->pr(18, compact('receipt_credit'),
"Receipt Credit Added");
}
@@ -442,44 +476,61 @@ class StatementEntry extends AppModel {
$this->pr(18, compact('dtype', 'entries'), "Outstanding Debit Entries");
}
// Initialize our list of used credits
$used_credits = array();
// REVISIT <AP>: 20090806
// Testing a theory. We should never have
// explicit credits, as well as a new receipt,
// and yet have outstanding charges.
if (!empty($credits) && !empty($receipt_credit) && !empty($charges))
INTERNAL_ERROR("Explicit credits that haven't already been applied.");
// Work through all unpaid charges, applying disbursements as we go
foreach ($charges AS $charge) {
$this->pr(20, compact('charge'),
'Process Charge');
// Check that we have available credits.
// Technically, this isn't necessary, since the loop
// will handle everything just fine. However, this
// just saves extra processing if/when there is no
// means to resolve a charge anyway.
if (empty($credits) && empty($receipt_credit['balance'])) {
$this->pr(17, 'No more available credits');
break;
}
$charge['balance'] = $charge['StatementEntry']['balance'];
// 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");
while ($charge['balance'] > 0 &&
(!empty($credits) || !empty($receipt_credit['balance']))) {
$this->pr(20, compact('charge'),
'Attempt Charge Reconciliation');
if (empty($credit['receipt']))
// Use explicit credits before using implicit credits
// (Not sure it matters though).
if (!empty($credits)) {
// Peel off the first credit available
$credit =& $credits[0];
$disbursement_date = $credit['StatementEntry']['effective_date'];
$disbursement_transaction_id = $credit['StatementEntry']['transaction_id'];
$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;
if (!isset($credit['balance']))
$credit['balance'] = $credit['StatementEntry']['amount'];
}
elseif (!empty($receipt_credit['balance'])) {
// Use our only receipt credit
$credit =& $receipt_credit;
$disbursement_date = $credit['Transaction']['stamp'];
$disbursement_transaction_id = $credit['Transaction']['id'];
$disbursement_account_id = $credit['LedgerEntry']['account_id'];
}
else {
die("HOW DID WE GET HERE WITH NO SURPLUS?");
}
// Set the disbursement amount to the maximum amount
// possible without exceeding the charge or credit balance
@@ -492,67 +543,35 @@ class StatementEntry extends AppModel {
$this->pr(20, compact('credit'),
($credit['balance'] > 0 ? 'Utilized' : 'Exhausted') .
(empty($credit['receipt']) ? ' Credit' : ' Receipt'));
(!empty($credits) ? ' 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 ($credit['balance'] < 0)
die("HOW DID WE END UP WITH NEGATIVE SURPLUS BALANCE?");
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'],
),
));
// If we've exhausted the credit, get it out of the
// available credit pool (but keep track of it for later).
if ($credit['balance'] <= 0 && !empty($credits))
$used_credits[] = array_shift($credits);
$ret['Disbursement'][] = $result;
if ($result['error'])
$ret['error'] = true;
}
else {
// Receipt Credit
// Add a disbursement that uses the available credit to pay the charge
$disbursement = array('type' => $disbursement_type,
'account_id' => $disbursement_account_id,
'amount' => $disbursement_amount,
'effective_date' => $disbursement_date,
'transaction_id' => $disbursement_transaction_id,
'customer_id' => $charge['StatementEntry']['customer_id'],
'lease_id' => $charge['StatementEntry']['lease_id'],
'charge_entry_id' => $charge['StatementEntry']['id'],
'comment' => null,
);
if (strtotime($charge['StatementEntry']['effective_date']) >
strtotime($credit['Transaction']['stamp']))
$disbursement_edate = $charge['StatementEntry']['effective_date'];
else
$disbursement_edate = $credit['Transaction']['stamp'];
$this->pr(20, compact('disbursement'),
'New Disbursement Entry');
// 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;
}
$result = $this->addStatementEntry($disbursement);
$ret['Disbursement'][] = $result;
if ($result['error'])
$ret['error'] = true;
// Adjust the charge balance to reflect the new disbursement
$charge['balance'] -= $disbursement_amount;
@@ -562,47 +581,37 @@ class StatementEntry extends AppModel {
if ($charge['balance'] <= 0)
$this->pr(20, 'Fully Paid Charge');
}
// Break the $credit reference to avoid future problems
unset($credit);
}
$this->pr(18, compact('credits'),
'Disbursements complete');
// Partially used credits must be added to the used list
if (isset($credits[0]['applied']))
$used_credits[] = array_shift($credits);
$this->pr(18, compact('credits', 'used_credits', 'receipt_credit'),
'Disbursements added');
// Clean up any explicit credits that have been used
foreach ($credits AS $credit) {
if (!empty($credit['receipt']))
continue;
if (empty($credit['applied']))
continue;
foreach ($used_credits AS $credit) {
if ($credit['balance'] > 0) {
$this->pr(20, compact('credit'),
'Update Credit Entry');
$this->id = $credit['StatementEntry']['id'];
$this->id = $credit['StatementEntry']['id'];
$this->saveField('amount', $credit['balance']);
}
else {
$this->pr(20, compact('credit'),
'Delete Exhausted Credit Entry');
$this->delete($credit['StatementEntry']['id'], false);
$this->del($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;
// Convert non-exhausted receipt credit to an explicit one
if (!empty($receipt_credit['balance'])) {
$credit =& $receipt_credit;
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' =>
@@ -610,31 +619,30 @@ class StatementEntry extends AppModel {
array('type' => 'SURPLUS')),
));
if (!empty($explicit_credit)) {
// REVISIT <AP>: 20090815
// Testing whether or not this case occurs
$this->INTERNAL_ERROR('Existing explicit credit unexpected');
if (empty($explicit_credit)) {
$this->pr(18, compact('credit'),
'Create Explicit Credit');
// 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.
$result = $this->addStatementEntry
(array('type' => 'SURPLUS',
'account_id' => $credit['LedgerEntry']['account_id'],
'amount' => $credit['balance'],
'effective_date' => $credit['Transaction']['stamp'],
'transaction_id' => $credit['Transaction']['id'],
'customer_id' => $customer_id,
'lease_id' => $lease_id,
));
$ret['Credit'] = $result;
if ($result['error'])
$ret['error'] = true;
}
else {
$this->pr(18, compact('explicit_credit', 'credit'),
'Update existing explicit credit');
'Update 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));
@@ -648,7 +656,7 @@ class StatementEntry extends AppModel {
* - Returns summary data from the requested statement entry
*/
function stats($id = null, $query = null) {
//$this->prFunctionLevel(array('log' => 16, 'show' => 10));
$this->prFunctionLevel(array('log' => 19, 'show' => 10));
$this->prEnter(compact('id', 'query'));
$this->queryInit($query);

View File

@@ -8,73 +8,12 @@ class Tender extends AppModel {
'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);
}
/**************************************************************************
**************************************************************************
**************************************************************************
@@ -104,10 +43,29 @@ class Tender extends AppModel {
function addTender($tender) {
$this->prEnter(compact('tender'));
$ret = array('data' => $tender);
$ret = array();
if (!$this->verifyTender($tender))
return $this->prReturn(array('error' => true) + $ret);
// Come up with a (not necessarily unique) name for the tender.
// For checks & money orders, this will be based on the check
// number. For other types of tender, we'll just use the
// generic name of the monetary account.
// REVISIT <AP>: 20090723
// I would like to have cash named "Cash #1234", where
// the number would correspond to either the Tender ID
// or the LedgerEntry ID.
if (empty($tender['name']) && !empty($tender['account_id'])) {
$tender['name'] = $this->LedgerEntry->Account->name($tender['account_id']);
if ($tender['account_id'] == $this->LedgerEntry->Account->checkAccountID() ||
$tender['account_id'] == $this->LedgerEntry->Account->moneyOrderAccountID()) {
$tender['name'] .= ' #' . $tender['data1'];
}
}
$this->pr(20, array('Tender' => $tender),
'Pre-Save');
$this->create();
if (!$this->save($tender))
return $this->prReturn(array('error' => true) + $ret);
@@ -122,10 +80,31 @@ class Tender extends AppModel {
**************************************************************************
* function: nsf
* - Flags the ledger entry as having insufficient funds
*
* Steps:
* - Get information from Check (C1); for amount $A
* - Find Bank Deposit matching to Tender
* - New Transaction (T1)
* - New Bank Deposit (D1)
* - New Tender (N1); NSF; D1,
* - Add new LedgerEntry (L1a); T1; debit:bank; -$A
* - Add new LedgerEntry (L1b); T1; credit:NSF; -$A
* - Add new LedgerEntry (L2a); T1; debit:NSF; -$A; N1
* - Add new LedgerEntry (L2b); T1; credit:A/R; -$A
* - For Tx associated with LE associated with C1:
* - For each Disbursement SE of Tx:
* - Add new StatementEntry (S1n); T1; DISBURSEMENT; -1*S1n.amount
* - New Transaction (T2) (?????)
* - Add new StatementEntry (S2); T2; CHARGE; NSF; $35
* - Add new LedgerEntry (L3a); T2; credit:NSF-Fee; $35
* - Add new LedgerEntry (L3b); T2; debit:A/R; $35
* - Set C1.nsf_tx = T1
* - Re-Reconcile (customer may have running credit)
*/
function nsf($id, $stamp = null, $comment = null) {
$this->prEnter(compact('id', 'stamp', 'comment'));
function nsf($id, $stamp = null) {
$this->prFunctionLevel(30);
$this->prEnter(compact('id'));
// Get information about this NSF item.
$this->id = $id;
@@ -134,7 +113,6 @@ class Tender extends AppModel {
('contain' =>
array('LedgerEntry',
'DepositTransaction',
'DepositLedgerEntry',
'NsfTransaction'),
));
$this->pr(20, compact('tender'));
@@ -150,15 +128,16 @@ class Tender extends AppModel {
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']);
}
$result = $T->addNsf($tender, $stamp);
if ($result['error'])
return $this->prReturn(false);
return $this->prReturn($result);
// Flag the tender as NSF, using the items created from addNsf
$this->id = $id;
$this->saveField('nsf_transaction_id', $result['nsf_transaction_id']);
$this->saveField('nsf_ledger_entry_id', $result['nsf_ledger_entry_id']);
return $this->prReturn(true);
}

File diff suppressed because it is too large Load Diff

View File

@@ -55,67 +55,10 @@ class Unit extends AppModel {
return $this->statusValue('OCCUPIED');
}
function statusCheck($id_or_enum,
$min = null, $min_strict = false,
$max = null, $max_strict = false)
{
$this->prEnter(compact('id_or_enum', 'min', 'min_strict', 'max', 'max_strict'));
if (is_int($id_or_enum)) {
$this->id = $id_or_enum;
$id_or_enum = $this->field('status');
}
$enum_val = $this->statusValue($id_or_enum);
if (isset($min) && is_string($min))
$min = $this->statusValue($min);
if (isset($max) && is_string($max))
$max = $this->statusValue($max);
$this->pr(17, compact('enum_val', 'min', 'min_strict', 'max', 'max_strict'));
if (isset($min) &&
($enum_val < $min ||
($min_strict && $enum_val == $min)))
return $this->prReturn(false);
if (isset($max) &&
($enum_val > $max ||
($max_strict && $enum_val == $max)))
return $this->prReturn(false);
return $this->prReturn(true);
}
function locked($enum) {
return $this->statusCheck($enum, 'LOCKED', false, null, false);
}
function conditionLocked() {
//return array('Unit.status' => 'LOCKED');
return ('Unit.status >= ' . $this->statusValue('LOCKED'));
}
function liened($enum) {
return $this->statusCheck($enum, 'LIENED', false, null, false);
}
function conditionLiened() {
return ('Unit.status >= ' . $this->statusValue('LIENED'));
}
function occupied($enum) {
return $this->statusCheck($enum, 'OCCUPIED', false, null, false);
}
function conditionOccupied() {
return ('Unit.status >= ' . $this->statusValue('OCCUPIED'));
}
function vacant($enum) {
return $this->statusCheck($enum, 'UNAVAILABLE', true, 'OCCUPIED', true);
}
function conditionVacant() {
return ('Unit.status BETWEEN ' .
($this->statusValue('UNAVAILABLE')+1) .
@@ -123,17 +66,10 @@ class Unit extends AppModel {
($this->statusValue('OCCUPIED')-1));
}
function unavailable($enum) {
return $this->statusCheck($enum, null, false, 'UNAVAILABLE', false);
}
function conditionUnavailable() {
return ('Unit.status <= ' . $this->statusValue('UNAVAILABLE'));
}
function available($enum) { return $this->vacant($enum); }
function conditionAvailable() { return $this->conditionVacant($enum); }
/**************************************************************************
**************************************************************************
@@ -199,16 +135,6 @@ class Unit extends AppModel {
}
/**************************************************************************
**************************************************************************
**************************************************************************
* function: update
* - Update any cached or calculated fields
*/
function update($id) {
}
/**************************************************************************
**************************************************************************
**************************************************************************

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,9 +11,6 @@
* Javascript
*/
// Warnings _really_ screw up javascript
$saved_debug_state = Configure::read('debug');
Configure::write('debug', '0');
?>
<script type="text/javascript"><!--
@@ -26,94 +23,62 @@ Configure::write('debug', '0');
success: showResponse, // post-submit callback
// other available options:
//url: url, // override for form's 'action' attribute
//type: 'get', // 'get' or 'post', override for form's 'method' attribute
//dataType: null, // 'xml', 'script', or 'json' (expected server response type)
//clearForm: true, // clear all form fields after successful submit
//resetForm: true, // reset the form after successful submit
url: "<?php echo $html->url(array('controller' => 'transactions',
'action' => 'postReceipt', 0)); ?>"
// $.ajax options can be used here too, for example:
//timeout: 3000,
};
// bind form using 'ajaxForm'
if ($('#receipt-form').ajaxForm != null)
$('#receipt-form').ajaxForm(options);
else
$('#repeat, label[for=repeat]').remove();
$('#receipt-form').ajaxForm(options);
});
// pre-submit callback
function verifyRequest(formData, jqForm, options) {
//$("#debug").html('');
for (var i = 0; i < formData.length; ++i) {
//$("#debug").append(i + ') ' + dump(formData[i]) + '<BR>');
if (formData[i]['name'] == "data[Customer][id]" &&
!(formData[i]['value'] > 0)) {
//$("#debug").append('<P>Missing Customer ID');
alert("Please select a customer first.");
return false;
}
if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') {
//$("#debug").append('<P>Bad Stamp');
if (formData[i]['value'] != '')
alert(formData[i]['value'] + " is not valid date stamp. Please correct it.");
else
alert("Please enter a valid date stamp first.");
return false;
}
// Terrible way to accomplish this...
for (var j = 0; j < 20; ++j) {
if (formData[i]['name'] == "data[Entry]["+j+"][amount]") {
var val = formData[i]['value'].replace(/\$/,'');
//$("#debug").append('<P>Bad Amount');
if (!(val > 0)) {
if (formData[i]['value'] == '')
alert("Please enter an amount first.");
else
alert('"'+formData[i]['value']+'"' + " is not valid amount. Please correct it.");
return false;
}
}
}
}
//$("#debug").append('OK');
function verifyRequest(formData, jqForm, options) {
// formData is an array; here we use $.param to convert it to a string to display it
// but the form plugin does this for you automatically when it submits the data
//var_dump(formData);
//$('#request-debug').html('<PRE>'+dump(formData)+'</PRE>');
$('#request-debug').html('Ommitted');
//return false;
$('#results').html('Working <BLINK>...</BLINK>');
$('#response-debug').html('Loading <BLINK>...</BLINK>');
$('#output-debug').html('Loading <BLINK>...</BLINK>');
// here we could return false to prevent the form from being submitted;
// returning anything other than false will allow the form submit to continue
return true;
}
// post-submit callback
function showResponse(responseText, statusText) {
// for normal html responses, the first argument to the success callback
// is the XMLHttpRequest object's responseText property
// if the ajaxForm method was passed an Options Object with the dataType
// property set to 'xml' then the first argument to the success callback
// is the XMLHttpRequest object's responseXML property
// if the ajaxForm method was passed an Options Object with the dataType
// property set to 'json' then the first argument to the success callback
// is the json data object returned by the server
if (statusText == 'success') {
var amount = 0;
$("input.payment.amount").each(function(i) {
amount += $(this).val();
});
$('#results').html('<H3>Receipt Saved<BR>' +
$("#receipt-customer-name").html() +
' : ' + fmtCurrency(amount) +
'</H3>');
if (!$("#repeat").attr("checked")) {
window.location.href =
"<?php echo $html->url(array('controller' => 'customers',
'action' => 'view')); ?>"
+ "/" + $("#customer-id").val();
return;
}
// get a clean slate
resetForm();
//resetForm();
// REVISIT <AP>: 20090806 Add to resetForm()
updateCharges($("#customer-id").val());
}
else {
$('#results').html('<H2>Failed to save receipt!</H2>');
alert('Failed to save receipt.');
alert('not successful??');
}
$('#response-debug').html('<PRE>'+dump(statusText)+'</PRE>');
}
// Reset the form
@@ -121,42 +86,30 @@ function resetForm() {
$('#payment-entry-id').val(1);
$('#payments').html('');
addPaymentSource(false);
updateCharges($("#customer-id").val());
}
function updateCharges(id) {
$('#charge-entries-jqGrid').clearGridData();
$("#receipt-balance").html("Calculating...");
$("#receipt-charges-caption").html("Please Wait...");
var custom = new Array();
custom['customer_id'] = id;
var dynamic_post = new Array();
dynamic_post['custom'] = custom;
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#charge-entries-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
var gridstate = $('#charge-entries-jqGrid').getGridParam('gridstate');
if (gridstate == 'hidden')
$('#charge-entries .HeaderButton').click();
}
function onGridLoadComplete() {
var userdata = $('#charge-entries-jqGrid').getGridParam('userData');
$('#receipt-balance').html(fmtCurrency(userdata['balance']));
$("#receipt-customer-id").html("INTERNAL ERROR");
$("#receipt-customer-name").html("INTERNAL ERROR");
$("#receipt-balance").html("INTERNAL ERROR");
$("#receipt-charges-caption").html("Outstanding Charges");
addPaymentSource(false);
datepickerNow('TransactionStamp');
}
function onRowSelect(grid_id, customer_id) {
// Set the customer id that will be returned with the form
$("#customer-id").val(customer_id);
// Set the customer name, so the user knows who the receipt is for
// Get the item names from the grid
//$("#receipt-customer-id").html($(grid_id).getCell(customer_id, 'Customer-id'));
// REVISIT <AP>: 20090708
// This is not intended as a long term solution,
// but I need a way to enter data and then view
// the results. This link will help.
$("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
$(grid_id).getCell(customer_id, 'Customer-id').replace(/^#/,'') +
'">' +
$(grid_id).getCell(customer_id, 'Customer-id') +
'</A>');
$("#receipt-customer-name").html($(grid_id).getCell(customer_id, 'Customer-name'));
// Hide the "no customer" message and show the current customer
@@ -221,7 +174,7 @@ function addPaymentSource(flash) {
'<DIV ID="payment-amount-div-%{id}" CLASS="input text required">' +
' <INPUT TYPE="text" SIZE="20"' +
' NAME="data[Entry][%{id}][amount]"' +
' CLASS="payment amount"' +
' CLASS="payment"' +
' ID="payment-amount-%{id}" />' +
' <LABEL CLASS="payment" FOR="payment-amount-%{id}">Amount</LABEL>' +
'</DIV>' +
@@ -267,20 +220,59 @@ function addPaymentSource(flash) {
}
function switchPaymentType(paymentid_base, paymentid, radioid) {
$("."+paymentid_base+"-"+paymentid).slideUp();
var type_id = $("#"+radioid).val();
$("."+paymentid_base+"-"+paymentid+
":not(" +
"#"+paymentid_base+"-"+paymentid+"-"+type_id +
")").slideUp();
$("#"+paymentid_base+"-"+paymentid+"-"+type_id).slideDown();
}
function updateChargesGrid(idlist) {
var dynamic_post = new Array();
dynamic_post['idlist'] = idlist;
$('#charge-entries-jqGrid').setPostDataItem('dynamic_post_replace', serialize(dynamic_post));
$('#charge-entries-jqGrid')
.setGridParam({ page: 1 })
.trigger("reloadGrid");
}
--></script>
function updateCharges(id) {
var url = '<?php echo ($html->url(array("controller" => $this->params["controller"],
"action" => "unreconciled"))); ?>';
url += '/'+id;
$('#charge-entries-jqGrid').clearGridData();
$("#receipt-balance").html("Calculating...");
$("#receipt-charges-caption").html("Please Wait...");
$.ajax({
type: "GET",
url: url,
dataType: "xml",
success: function(xml) {
var ids = new Array();
$('entry',xml).each(function(i){
ids.push($(this).attr('id'));
});
$('#receipt-balance').html(fmtCurrency($('entries',xml).attr('balance')));
$("#receipt-charges-caption").html("Outstanding Charges");
updateChargesGrid(ids);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
/* alert('ERROR'); */
/* $('#debug').html('<P>request<BR>'+escape(XMLHttpRequest)); */
/* $('#debug').append('<P>status<BR>'+escape(textStatus)); */
/* $('#debug').append('<P>error<BR>'+escape(errorThrown)); */
}
});
}
--></script>
<?php
; // align
// Re-Enable warnings
Configure::write('debug', $saved_debug_state);
//echo '<DIV ID="dialog">' . "\n";
echo $this->element('customers', array
('config' => array
@@ -296,7 +288,6 @@ echo $this->element('customers', array
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'action' => 'current',
'nolinks' => true,
'limit' => 10,
)));
@@ -304,7 +295,8 @@ echo $this->element('customers', array
echo ('<DIV CLASS="receipt grid-selection-text">' .
'<DIV CLASS="customer-selection-valid" style="display:none">' .
'Customer: <SPAN id="receipt-customer-name"></SPAN>' .
'Customer <SPAN id="receipt-customer-id"></SPAN>' .
': <SPAN id="receipt-customer-name"></SPAN>' .
/* '<DIV CLASS="supporting">' . */
/* '<TABLE>' . */
@@ -322,19 +314,17 @@ echo ('<DIV CLASS="receipt grid-selection-text">' .
echo $this->element('statement_entries', array
(// Grid configuration
(// Element configuration
'account_ftype' => 'credit',
'limit' => 8,
// Grid configuration
'config' => array
(
'grid_div_id' => 'charge-entries',
'grid_div_class' => 'text-below',
'grid_events' => array('loadComplete' => 'onGridLoadComplete()'),
'grid_setup' => array('hiddengrid' => true),
'caption' => '<SPAN id="receipt-charges-caption"></SPAN>',
'action' => 'unreconciled',
'exclude' => array('Customer', 'Type', 'Debit', 'Credit'),
'include' => array('Applied', 'Balance'),
'remap' => array('Applied' => 'Paid'),
'limit' => 8,
'rows' => $charges,
),
));
@@ -373,10 +363,6 @@ echo $this->element('form_table',
),
)));
echo "<BR>\n";
echo $form->input('repeat', array('type' => 'checkbox',
'id' => 'repeat',
'label' => 'Enter Multiple Receipts')) . "\n";
echo $form->submit('Generate Receipt') . "\n";
?>
@@ -397,25 +383,29 @@ echo $form->submit('Generate Receipt') . "\n";
<?php /* echo '</DIV>' . "\n"; // End of the dialog DIV */ ?>
<div id="results"></div>
<div id="output-debug" style="display:none"></div>
<?php
// Warnings _really_ screw up javascript
Configure::write('debug', '0');
?>
<div><H4>Request</H4><div id="request-debug"></div></div>
<div><H4>Response</H4><div id="response-debug"></div></div>
<div><H4>Output</H4><div id="output-debug"></div></div>
<script type="text/javascript"><!--
$(document).ready(function(){
datepicker('TransactionStamp');
$("#TransactionStamp")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
$("#customer-id").val(0);
$("#receipt-customer-name").html("INTERNAL ERROR");
$("#receipt-balance").html("INTERNAL ERROR");
$("#receipt-charges-caption").html("Outstanding Charges");
resetForm();
<?php if (isset($customer['id'])): ?>
$("#customer-id").val(<?php echo $customer['id']; ?>);
//$("#receipt-customer-id").html("<?php echo '#'.$customer['id']; ?>");
$("#receipt-customer-id").html('<A HREF="/pmgr/site/customers/view/' +
"<?php echo $customer['id']; ?>" +
'">#' +
"<?php echo $customer['id']; ?>" +
'</A>');
$("#receipt-customer-name").html("<?php echo $customer['name']; ?>");
$("#receipt-balance").html(fmtCurrency("<?php echo $stats['balance']; ?>"));
onGridState(null, 'hidden');
@@ -423,15 +413,37 @@ Configure::write('debug', '0');
onGridState(null, 'visible');
<?php endif; ?>
resetForm();
datepickerNow('TransactionStamp');
<?php if ($this->params['dev']): ?>
$('#output-debug').html('Post Output');
$('#output-debug').show();
<?php endif; ?>
/* $("#dialog").dialog({ */
/* bgiframe: true, */
/* autoOpen: false, */
/* height: 500, */
/* width: 600, */
/* modal: true, */
/* buttons: { */
/* 'Post a Payment': function() { */
/* var bValid = true; */
/* if (bValid) { */
/* $('#debug').append('<H2>POSTED!</H2>'); */
/* $(this).dialog('close'); */
/* } */
/* }, */
/* Cancel: function() { */
/* $(this).dialog('close'); */
/* } */
/* }, */
/* close: function() { */
/* } */
/* }); */
/* $('#post-payment').click(function() { */
/* $('#dialog').dialog('open'); */
/* }); */
});
--></script>
</div>
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>

View File

@@ -11,9 +11,6 @@ echo '<div class="customer view">' . "\n";
$rows = array();
$rows[] = array('Name', $customer['Customer']['name']);
$rows[] = array('Since', FormatHelper::date($since, true));
if (!empty($until))
$rows[] = array('Until', FormatHelper::date($until, true));
$rows[] = array('Comment', $customer['Customer']['comment']);
echo $this->element('table',
@@ -30,9 +27,7 @@ echo $this->element('table',
echo '<div class="infobox">' . "\n";
$rows = array();
$rows[] = array('Security Deposit:', FormatHelper::currency($outstandingDeposit));
//$rows[] = array('Charges:', FormatHelper::currency($stats['charges']));
//$rows[] = array('Payments:', FormatHelper::currency($stats['disbursements']));
$rows[] = array('Balance Owed:', FormatHelper::currency($outstandingBalance));
$rows[] = array('Balance:', FormatHelper::currency($outstandingBalance));
echo $this->element('table',
array('class' => 'summary',
'rows' => $rows,
@@ -61,7 +56,7 @@ echo $this->element('contacts', array
'config' => array
('caption' => 'Customer Contacts',
'filter' => array('Customer.id' => $customer['Customer']['id']),
'include' => array('Relationship'),
'include' => array('Type', 'Active'),
)));
@@ -75,8 +70,6 @@ echo $this->element('leases', array
('caption' => 'Lease History',
'filter' => array('Customer.id' => $customer['Customer']['id']),
'exclude' => array('Customer'),
'sort_column' => 'Move-In',
'sort_order' => 'DESC',
)));
@@ -87,28 +80,39 @@ echo $this->element('leases', array
echo $this->element('statement_entries', array
(// Grid configuration
'config' => array
('caption' => 'Customer Statement',
('caption' => 'Account',
'filter' => array('Customer.id' => $customer['Customer']['id'],
'type !=' => 'VOID'),
'exclude' => array('Customer'),
'sort_column' => 'Effective',
'sort_order' => 'DESC',
)));
/**********************************************************************
* Receipt History
* Customer Ledger History
*/
/*
* REVISIT <AP>: 20090724
* It's not my intention to really include this, as I believe it
* just will confuse folks. However, I've added it at the moment
* to help me see the picture of what's happening. It may prove
* useful with respect to identifying pre-payments, so after using
* it for a while, maybe we can get a feeling for that. I suspect
* it will be MUCH more useful just to add the pre-pay amount to
* the info box, or provide a list of ledger entries that are JUST
* pre-payments. We'll see...
*/
echo $this->element('ledger_entries', array
(// Grid configuration
'config' => array
('caption' => 'Receipts',
('caption' => 'Ledger Entries',
'filter' => array('Customer.id' => $customer['Customer']['id'],
'Transaction.type' => 'RECEIPT',
'Tender.id !=' => null,
//'Account.id !=' => '-AR-'
),
'include' => array('Transaction'),
'exclude' => array('Entry', 'Account', 'Cr/Dr'),
'Account.id !=' => '-AR-'),
'exclude' => array('Customer'),
'sort_column' => 'Date',
'sort_order' => 'DESC',
)));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -32,8 +32,8 @@ foreach ($fields AS $field => $config) {
$include_after = true;
}
if (empty($column_class))
$column_class = array();
$column_class = array();
if ($include_before)
$column_class[] = 'before';
$column_class[] = 'field';
@@ -79,13 +79,7 @@ foreach ($fields AS $field => $config) {
$cells[] = null;
}
if (empty($config['opts']['label']))
$name = $form->label($field, $config['name'],
empty($config['label_attributes'])
? null : $config['label_attributes']);
else
$name = $config['name'];
$name = $config['name'];
if (isset($config['with_name_before']))
$name = $config['with_name_before'] . $name;
elseif (isset($with_name_before))
@@ -129,7 +123,7 @@ foreach ($fields AS $field => $config) {
}
echo $this->element('table',
compact('id', 'class', 'caption', 'headers',
compact('class', 'caption', 'headers',
'rows', 'row_class', 'suppress_alternate_rows',
'column_class')
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,7 @@ $cols['Comment'] = array('index' => 'Transaction.comment', 'formatter' =
// Render the grid
$grid
->columns($cols)
->sortField('Timestamp', 'DESC')
->sortField('Timestamp')
->defaultFields(array('ID', 'Timestamp'))
->searchFields(array('Type', 'Comment'))
->render($this, isset($config) ? $config : null,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,14 +4,6 @@
<?php
; // Editor alignment
$unit = $lease['Unit'];
$customer = $lease['Customer'];
if (isset($lease['Lease']))
$lease = $lease['Lease'];
//pr(compact('unit', 'customer', 'lease', 'movein'));
/**********************************************************************
**********************************************************************
**********************************************************************
@@ -19,125 +11,87 @@ if (isset($lease['Lease']))
* Javascript
*/
// Warnings _really_ screw up javascript
$saved_debug_state = Configure::read('debug');
Configure::write('debug', '0');
?>
<script type="text/javascript"><!--
var lease_charge_through;
// prepare the form when the DOM is ready
$(document).ready(function() {
var options = {
var options = {
target: '#output-debug', // target element(s) to be updated with server response
beforeSubmit: verifyRequest, // pre-submit callback
success: showResponse, // post-submit callback
// other available options:
//url: url, // override for form's 'action' attribute
//type: 'get', // 'get' or 'post', override for form's 'method' attribute
//dataType: null, // 'xml', 'script', or 'json' (expected server response type)
//clearForm: true, // clear all form fields after successful submit
//resetForm: true, // reset the form after successful submit
url: "<?php echo $html->url(array('controller' => 'transactions',
'action' => 'postInvoice', 0)); ?>"
};
// $.ajax options can be used here too, for example:
//timeout: 3000,
};
// bind form using 'ajaxForm'
if ($('#invoice-form').ajaxForm != null)
// bind form using 'ajaxForm'
$('#invoice-form').ajaxForm(options);
else
$('#repeat, label[for=repeat]').remove();
});
});
// pre-submit callback
function verifyRequest(formData, jqForm, options) {
//$("#debug").html('');
for (var i = 0; i < formData.length; ++i) {
//$("#debug").append(i + ') ' + dump(formData[i]) + '<BR>');
if (formData[i]['name'] == "data[Lease][id]" &&
!(formData[i]['value'] > 0)) {
//$("#debug").append('<P>Missing Lease ID');
alert("Must select a lease first");
return false;
}
if (formData[i]['name'] == "data[Transaction][stamp]" &&
formData[i]['value'] == '') {
//$("#debug").append('<P>Bad Stamp');
if (formData[i]['value'] != '')
alert(formData[i]['value'] + " is not valid date stamp. Please correct it.");
else
alert("Please enter a valid date stamp first.");
return false;
}
// Terrible way to accomplish this...
for (var j = 0; j < 20; ++j) {
if (formData[i]['name'] == "data[Entry]["+j+"][amount]") {
var val = formData[i]['value'].replace(/\$/,'');
//$("#debug").append('<P>Bad Amount');
if (!(val > 0)) {
if (formData[i]['value'] == '')
alert("Please enter an amount for Charge #"+j+", or remove the Charge completely.");
else
alert('"'+formData[i]['value']+'"' + " is not a valid amount for Charge #"+j+". Please correct it.");
return false;
}
}
}
}
//$("#debug").append('OK');
// formData is an array; here we use $.param to convert it to a string to display it
// but the form plugin does this for you automatically when it submits the data
//var_dump(formData);
//$('#request-debug').html('<PRE>'+dump(formData)+'</PRE>');
$('#request-debug').html('Ommitted');
//return false;
$('#results').html('Working <BLINK>...</BLINK>');
$('#response-debug').html('Loading <BLINK>...</BLINK>');
$('#output-debug').html('Loading <BLINK>...</BLINK>');
// here we could return false to prevent the form from being submitted;
// returning anything other than false will allow the form submit to continue
return true;
}
// post-submit callback
function showResponse(responseText, statusText) {
// for normal html responses, the first argument to the success callback
// is the XMLHttpRequest object's responseText property
// if the ajaxForm method was passed an Options Object with the dataType
// property set to 'xml' then the first argument to the success callback
// is the XMLHttpRequest object's responseXML property
// if the ajaxForm method was passed an Options Object with the dataType
// property set to 'json' then the first argument to the success callback
// is the json data object returned by the server
if (statusText == 'success') {
var amount = 0;
$("input.invoice.amount").each(function(i) {
amount += (+ $(this).val().replace(/\$/,''));
});
$('#results').html('<H3>Invoice Saved<BR>' +
$("#invoice-customer").html() +
' : ' + fmtCurrency(amount) +
'</H3>');
if (!$("#repeat").attr("checked")) {
window.location.href =
<?php if (empty($movein)): ?>
"<?php echo $html->url(array('controller' => 'leases',
'action' => 'view')); ?>"
+ "/" + $("#lease-id").val();
<?php else: ?>
"<?php echo $html->url(array('controller' => 'customers',
'action' => 'receipt')); ?>"
+ "/" + "<?php echo $customer['id']; ?>";
<?php endif; ?>
return;
}
// get a clean slate
resetForm();
//resetForm();
}
else {
$('#results').html('<H2>Failed to save invoice!</H2>');
alert('Failed to save invoice.');
alert('not successful??');
}
$('#response-debug').html('<PRE>'+dump(statusText)+'</PRE>');
}
// Reset the form
function resetForm(nocharge) {
$('#charge-entry-id').val(1);
$('#charges').html('');
function resetForm() {
$("#charge-entry-id").val(1);
if (!nocharge)
addChargeSource(false);
$("#invoice-lease").html("INTERNAL ERROR");
$("#invoice-unit").html("INTERNAL ERROR");
$("#invoice-customer").html("INTERNAL ERROR");
$("#invoice-rent").html("INTERNAL ERROR");
$("#invoice-late").html("INTERNAL ERROR");
$("#invoice-deposit").html("INTERNAL ERROR");
addChargeSource(false);
datepickerNow('TransactionStamp');
}
@@ -145,7 +99,17 @@ function onRowSelect(grid_id, lease_id) {
// Set the item id that will be returned with the form
$("#lease-id").val(lease_id);
$("#invoice-lease").html($(grid_id).getCell(lease_id, 'Lease-number'));
// Get the item names from the grid
//$("#invoice-lease").html($(grid_id).getCell(lease_id, 'Lease-number'));
// REVISIT <AP>: 20090708
// This is not intended as a long term solution,
// but I need a way to enter data and then view
// the results. This link will help.
$("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
$(grid_id).getCell(lease_id, 'Lease-id').replace(/^#/,'') +
'">' +
$(grid_id).getCell(lease_id, 'Lease-number') +
'</A>');
$("#invoice-unit").html($(grid_id).getCell(lease_id, 'Unit-name'));
$("#invoice-customer").html($(grid_id).getCell(lease_id, 'Customer-name'));
$("#invoice-rent").html($(grid_id).getCell(lease_id, 'Lease-rent'));
@@ -153,7 +117,6 @@ function onRowSelect(grid_id, lease_id) {
$("#invoice-deposit").html($(grid_id).getCell(lease_id, 'Lease-deposit')
? $(grid_id).getCell(lease_id, 'Lease-deposit')
: '-');
lease_charge_through = $(grid_id).getCell(lease_id, 'Lease-charge_through_date')
// Hide the "no lease" message and show the current lease
$(".lease-selection-invalid").hide();
@@ -179,78 +142,6 @@ function onGridState(grid_id, state) {
}
}
function setNextRent(id) {
var chg_thru;
$('.ChargeForm').each( function(i) {
if ($('.ChargeFormThroughDate', this).attr('id') == 'Entry'+id+'ThroughDate')
return;
if ($('.ChargeFormAccount option:selected', this).val() == <?php echo $rentAccount ?>
&& $('.ChargeFormThroughDate', this).val()) {
var dt = new Date($('.ChargeFormThroughDate', this).val());
//$('#debug').append('Rent in ' + i + '; date ' + dt + '<BR>');
if (chg_thru == null || dt > chg_thru)
chg_thru = dt;
}
});
if (!chg_thru)
chg_thru = new Date(lease_charge_through);
if (chg_thru < dateEOM(chg_thru)) {
// Add a charge to finish out the month
datepickerSet('Entry'+id+'EffectiveDate', dateTomorrow(chg_thru));
datepickerSet('Entry'+id+'ThroughDate', dateEOM(chg_thru));
} else {
// Add a whole month's charge for next month
datepickerSet('Entry'+id+'EffectiveDate', dateNextBOM(chg_thru));
datepickerSet('Entry'+id+'ThroughDate', dateNextEOM(chg_thru));
}
// Now add in the amount owed based on the calculated
// effective and through dates.
prorate(id);
}
function prorate(id) {
var edt = datepickerGet('Entry'+id+'EffectiveDate');
var tdt = datepickerGet('Entry'+id+'ThroughDate');
var rent = $('#invoice-rent').html().replace(/\$/,'');
// Reset the comment. It might wipe out a user comment,
// but it's probably low risk/concern
$('#Entry'+id+'Comment').val('');
if (edt == null || tdt == null) {
alert('Can only prorate with both effective and through dates');
rent = 0;
}
else if (edt > tdt) {
alert('Effective date is later than the Through date');
rent = 0;
}
else if (tdt.getMonth() == edt.getMonth() + 1 &&
edt.getDate() == tdt.getDate() + 1) {
// appears to be anniversary billing, one full cycle
}
else if (edt.getTime() == dateBOM(edt).getTime() &&
tdt.getTime() == dateEOM(edt).getTime()) {
// appears to be one full month
}
else {
var one_day=1000*60*60*24;
var days = Math.ceil((tdt.getTime()-edt.getTime()+1)/(one_day));
var dim =
((edt.getMonth() == tdt.getMonth())
? dateEOM(edt).getDate() // prorated within the month.
: 30); // prorated across months.
rent *= days / dim;
$('#Entry'+id+'Comment').val('Rent proration: '+days+'/'+dim+' days');
}
$('#Entry'+id+'Amount').val(fmtCurrency(rent));
}
function addChargeSource(flash) {
var id = $("#charge-entry-id").val();
addDiv('charge-entry-id', 'charge', 'charges', flash,
@@ -261,33 +152,26 @@ function addChargeSource(flash) {
<?php
echo FormatHelper::phpVarToJavascript
($this->element('form_table',
array('id' => 'Entry%{id}Form',
'class' => "ChargeForm item invoice ledger-entry entry",
array('class' => "item invoice ledger-entry entry",
//'with_name_after' => ':',
'field_prefix' => 'Entry.%{id}',
'fields' => array
("account_id" => array('name' => 'Account',
'opts' =>
array('class' => 'ChargeFormAccount',
'options' => $chargeAccounts,
array('options' => $chargeAccounts,
'value' => $defaultAccount,
),
'between' => '<A HREF="#" ONCLICK="setNextRent(\'%{id}\'); return false;">Rent</A>',
),
"effective_date" => array('opts' =>
array('class' => 'ChargeFormEffectiveDate',
'type' => 'text'),
array('type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerBOM(\'TransactionStamp\',\'Entry%{id}EffectiveDate\'); return false;">BOM</A>',
),
"through_date" => array('opts' =>
array('class' => 'ChargeFormThroughDate',
'type' => 'text'),
array('type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerEOM(\'Entry%{id}EffectiveDate\',\'Entry%{id}ThroughDate\'); return false;">EOM</A>',
),
"amount" => array('opts' => array('class' => 'ChargeFormAmount invoice amount'),
'between' => '<A HREF="#" ONCLICK="prorate(\'%{id}\'); return false;">Prorate</A>',
),
"comment" => array('opts' => array('class' => 'ChargeFormComment', 'size' => 50)),
"amount" => true,
"comment" => array('opts' => array('size' => 50)),
),
))) . "+\n";
?>
@@ -295,40 +179,43 @@ function addChargeSource(flash) {
'</FIELDSET>'
);
datepicker("Entry"+id+"EffectiveDate");
datepicker("Entry"+id+"ThroughDate");
$("#Entry"+id+"EffectiveDate")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
return id;
$("#Entry"+id+"ThroughDate")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
}
--></script>
<?php
; // align
// Re-Enable warnings
Configure::write('debug', $saved_debug_state);
if (empty($movein))
echo $this->element('leases', array
('config' => array
('grid_div_id' => 'leases-list',
'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
' return false;">Select Lease</A>'),
'grid_setup' => array('hiddengrid' => isset($lease['id'])),
'grid_events' => array('onSelectRow' =>
array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
'onHeaderClick' =>
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'include' => array('Charge-Thru'),
'exclude' => array('Closed', 'Paid-Thru'),
'action' => 'active',
'nolinks' => true,
'limit' => 10,
)));
echo $this->element('leases', array
('config' => array
('grid_div_id' => 'leases-list',
'grid_div_class' => 'text-below',
'caption' => ('<A HREF="#" ONCLICK="$(\'#leases-list .HeaderButton\').click();'.
' return false;">Select Lease</A>'),
'grid_setup' => array('hiddengrid' => isset($lease['Lease']['id'])),
'grid_events' => array('onSelectRow' =>
array('ids' =>
'if (ids != null){onRowSelect("#"+$(this).attr("id"), ids);}'),
'onHeaderClick' =>
array('gridstate' =>
'onGridState("#"+$(this).attr("id"), gridstate)'),
),
'nolinks' => true,
'limit' => 10,
)));
echo ('<DIV CLASS="invoice grid-selection-text">' .
@@ -362,12 +249,6 @@ echo $form->input("Lease.id",
'type' => 'hidden',
'value' => 0));
if (!empty($movein))
echo $form->input("Customer.id",
array('id' => 'customer-id',
'type' => 'hidden',
'value' => $customer['id']));
/* echo '<fieldset CLASS="invoice">' . "\n"; */
/* echo ' <legend>Invoice</legend>' . "\n"; */
@@ -386,13 +267,6 @@ echo $this->element('form_table',
/* echo '</fieldset>' . "\n"; */
if (empty($movein)) {
echo "<BR>\n";
echo $form->input('repeat', array('type' => 'checkbox',
'id' => 'repeat',
'label' => 'Enter Multiple Invoices')) . "\n";
}
echo $form->submit('Generate Invoice') . "\n";
?>
@@ -407,114 +281,41 @@ echo $form->submit('Generate Invoice') . "\n";
<?php echo $form->end('Generate Invoice'); ?>
<div id="results"></div>
<div id="output-debug" style="display:none"></div>
<?php
// Warnings _really_ screw up javascript
Configure::write('debug', '0');
?>
<div><H4>Request</H4><div id="request-debug"></div></div>
<div><H4>Response</H4><div id="response-debug"></div></div>
<div><H4>Output</H4><div id="output-debug"></div></div>
<script type="text/javascript"><!--
$.fn.removeCol = function(col){
if(!col){ col = 1; }
$('tr td:nth-child('+col+'), tr th:nth-child('+col+')', this).remove();
};
function addHidden(id, fld, name) {
$('#Entry'+id+fld).after
('<input type="hidden"' +
' name="data[Entry]['+id+']['+name+']"' +
' value="' + $('#Entry'+id+fld).val() + '">');
}
$(document).ready(function(){
datepicker('TransactionStamp');
<?php if (isset($lease['id'])): ?>
$("#lease-id").val(<?php echo $lease['id']; ?>);
$("#invoice-lease").html("<?php echo '#'.$lease['number']; ?>");
$("#invoice-unit").html("<?php echo $unit['name']; ?>");
$("#invoice-customer").html("<?php echo $customer['name']; ?>");
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['rent']); ?>");
$("#invoice-late").html("<?php echo FormatHelper::currency($defaultLate); ?>");
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['deposit']); ?>");
lease_charge_through = <?php
if ($lease['charge_through_date'])
echo 'new Date("'.date('m/d/Y', strtotime($lease['charge_through_date'])).'")';
elseif ($lease['paid_through_date'])
echo 'new Date("'.date('m/d/Y', strtotime($lease['paid_through_date'])).'")';
else
echo 'dateYesterday("'.date('m/d/Y', strtotime($lease['movein_date'])).'")';
?>;
<?php else: ?>
$("#lease-id").val(0);
$("#invoice-lease").html("INTERNAL ERROR");
$("#invoice-unit").html("INTERNAL ERROR");
$("#invoice-customer").html("INTERNAL ERROR");
$("#invoice-rent").html("INTERNAL ERROR");
$("#invoice-late").html("INTERNAL ERROR");
$("#invoice-deposit").html("INTERNAL ERROR");
<?php endif; ?>
<?php if (empty($movein)): ?>
$("#TransactionStamp")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
resetForm();
datepickerNow('TransactionStamp');
<?php else: ?>
var id;
resetForm(true);
$("#TransactionStamp").attr('disabled', true);
$("#TransactionStamp").val("<?php echo date('m/d/Y', $movein['time']); ?>");
$('#TransactionStamp').after
('<input type="hidden"' +
' name="data[Transaction][stamp]"' +
' value="' + $("#TransactionStamp").val() + '">');
$("#TransactionComment").val('Move-In Charges');
<?php if ($movein['deposit'] != 0): ?>
id = addChargeSource(false);
$('#Entry'+id+'Form').removeCol(2);
$('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true);
$('#Entry'+id+'EffectiveDate').val("<?php echo date('m/d/Y', $movein['effective_time']); ?>");
addHidden(id, 'EffectiveDate', 'effective_date');
$('#Entry'+id+'AccountId').val(<?php echo $securityDepositAccount; ?>);
addHidden(id, 'AccountId', 'account_id');
$('#Entry'+id+'Amount').val("<?php echo FormatHelper::currency($movein['deposit']); ?>");
addHidden(id, 'Amount', 'amount');
$('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?>
id = addChargeSource(false);
$('#Entry'+id+'Form').removeCol(2);
$('#Entry'+id+'Form input, #Entry'+id+'Form select').attr('disabled', true);
setNextRent(id);
addHidden(id, 'EffectiveDate', 'effective_date');
addHidden(id, 'ThroughDate', 'through_date');
addHidden(id, 'AccountId', 'account_id');
addHidden(id, 'Amount', 'amount');
$('#Entry'+id+'Comment').removeAttr('disabled');
<?php endif; ?>
<?php if (isset($lease['id'])): ?>
<?php if (isset($lease['Lease']['id'])): ?>
$("#lease-id").val(<?php echo $lease['Lease']['id']; ?>);
//$("#invoice-lease").html("<?php echo '#'.$lease['Lease']['number']; ?>");
$("#invoice-lease").html('<A HREF="/pmgr/site/leases/view/' +
"<?php echo $lease['Lease']['id']; ?>" +
'">#' +
"<?php echo $lease['Lease']['number']; ?>" +
'</A>');
$("#invoice-unit").html("<?php echo $lease['Unit']['name']; ?>");
$("#invoice-customer").html("<?php echo $lease['Customer']['name']; ?>");
$("#invoice-rent").html("<?php echo FormatHelper::currency($lease['Lease']['rent']); ?>");
$("#invoice-late").html('$10.00');
$("#invoice-deposit").html("<?php echo FormatHelper::currency($lease['Lease']['deposit']); ?>");
onGridState(null, 'hidden');
<?php else: ?>
onGridState(null, 'visible');
<?php endif; ?>
<?php if ($this->params['dev']): ?>
$('#output-debug').html('Post Output');
$('#output-debug').show();
<?php endif; ?>
});
--></script>
</div>
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>

View File

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

View File

@@ -58,7 +58,7 @@ echo $this->element('form_table',
"amount" => array('prefix' => 'Entry.0',
'opts' =>
array('value' =>
FormatHelper::currency($balance),
FormatHelper::currency($balance, false, ''),
),
),
"account_id" => array('prefix' => 'Entry.0',
@@ -92,7 +92,13 @@ function resetForm() {
}
$(document).ready(function(){
datepicker('TransactionStamp');
$("#TransactionStamp")
.attr('autocomplete', 'off')
.datepicker({ constrainInput: true,
numberOfMonths: [1, 1],
showCurrentAtPos: 0,
dateFormat: 'mm/dd/yy' });
resetForm();
});
--></script>

View File

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

View File

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

View File

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

View File

@@ -6,19 +6,6 @@
{// for indentation purposes
// Go through each unit, adding a clickable region for the unit
foreach ($info['units'] AS $unit){
$title = ('Unit #' .
$unit['name'] .
(empty($unit['data']['CurrentLease']['id'])
? ''
: ('; ' .
/* 'Lease #' . */
/* $unit['data']['CurrentLease']['id'] . */
/* '; ' . */
$unit['data']['Customer']['name'] .
'; Paid Through ' .
$unit['data']['CurrentLease']['paid_through_date'])
));
echo(' <area shape="rect"' .
' coords="' .
$unit['left'] . ',' .
@@ -29,8 +16,8 @@
$html->url(array('controller' => 'units',
'action' => 'view',
$unit['id'])) .
'" alt="' . $title .
'" title="' . $title .
'" alt="' .
$unit['name'] .
'">' . "\n");
}
}// for indentation purposes

View File

@@ -1,68 +0,0 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="reverse input">' . "\n";
$customer = $entry['Customer'];
$transaction = $entry['Transaction'];
$account = $entry['Account'];
if (isset($entry['StatementEntry']))
$entry = $entry['StatementEntry'];
// We're not actually using a grid to select the customer,
// but selection-text makes for reasonable formatting
echo ('<DIV CLASS="reverse grid-selection-text">' .
'<TABLE>' . "\n");
echo ('<TR><TD style="padding-right: 1em;">' . $customer['name'] . '</TD>' .
' <TD>' . '(Customer #' . $customer['id'] . ')' . '</TD>' .
'</TR>' . "\n");
echo ('<TR><TD style="padding-right: 1em;">' . $account['name'] . '</TD>' .
' <TD>' . '(StatementEntry #' . $entry['id'] . ')' . '</TD>' .
'</TR>' . "\n");
echo ('<TR><TD style="padding-right: 1em;">Amount:</TD>' .
' <TD>' . FormatHelper::currency($entry['amount']) . '</TD>' .
'</TR>' . "\n");
echo ('</TABLE>' .
'</DIV>' . "\n");
echo $form->create(null, array('id' => 'reverse-form',
'url' => array('action' => 'reverse'))) . "\n";
echo $form->input("StatementEntry.id",
array('type' => 'hidden',
'value' => $entry['id'])) . "\n";
echo $this->element('form_table',
array('class' => "item reverse transaction entry",
//'with_name_after' => ':',
'field_prefix' => 'Transaction',
'fields' => array
("stamp" => array('opts' => array('type' => 'text'),
'between' => '<A HREF="#" ONCLICK="datepickerNow(\'TransactionStamp\'); return false;">Now</A>',
),
"comment" => array('opts' => array('size' => 50),
),
))) . "\n";
echo $form->end('Reverse Charge');
?>
<script type="text/javascript"><!--
// Reset the form
function resetForm() {
datepickerNow('TransactionStamp');
}
$(document).ready(function(){
datepicker('TransactionStamp');
resetForm();
});
--></script>
</div>

View File

@@ -15,7 +15,7 @@ $customer = $entry['Customer'];
$lease = $entry['Lease'];
$entry = $entry['StatementEntry'];
$Ttype = ucwords(strtolower(str_replace('_', ' ', $transaction['type'])));
$Ttype = ucfirst(strtolower($transaction['type']));
$rows = array();
$rows[] = array('ID', $entry['id']);
@@ -29,12 +29,10 @@ if (in_array($entry['type'], array('CHARGE', 'PAYMENT')))
$rows[] = array('Through', FormatHelper::date($entry['through_date']));
$rows[] = array('Type', $entry['type']);
$rows[] = array('Amount', FormatHelper::currency($entry['amount']));
$rows[] = array('Account', ($account['link']
? $html->link($account['name'],
array('controller' => 'accounts',
'action' => 'view',
$account['id']))
: $account['name']));
$rows[] = array('Account', $html->link($account['name'],
array('controller' => 'accounts',
'action' => 'view',
$account['id'])));
$rows[] = array('Customer', (isset($customer['name'])
? $html->link($customer['name'],
array('controller' => 'customers',
@@ -42,7 +40,7 @@ $rows[] = array('Customer', (isset($customer['name'])
$customer['id']))
: null));
$rows[] = array('Lease', (isset($lease['id'])
? $html->link('#'.$lease['number'],
? $html->link('#'.$lease['id'],
array('controller' => 'leases',
'action' => 'view',
$lease['id']))
@@ -115,8 +113,9 @@ echo $this->element('statement_entries', array
// Grid configuration
'config' => array
('caption' => $applied_caption,
('caption' => 'Entries Applied',
//'filter' => array('id' => $entry['id']),
'exclude' => array('Entry'),
)));

View File

@@ -30,8 +30,7 @@ foreach ($depositTypes AS $type) {
'separator' => '<BR>',
'onclick' => "switchSelection({$type['id']})",
'legend' => false,
// REVISIT <AP>: 20080811; Make opt-in, or opt-out?
'value' => $type['stats']['undeposited'] > 0 ? 'none' : 'none',
'value' => $type['stats']['undeposited'] > 0 ? 'all' : 'none',
'disabled' => $type['stats']['undeposited'] <= 0,
'options' => $radioOptions,
));

View File

@@ -1,90 +0,0 @@
<?php /* -*- mode:PHP -*- */
echo '<div class="tender edit">' . "\n";
?>
<script type="text/javascript"><!--
function switchTenderType(base, radioid) {
var type_id = $("#"+radioid).val();
if (!$("#"+base+"-"+type_id).is(':visible')) {
$("."+base).slideUp();
$("#"+base+"-"+type_id).slideDown();
}
}
$(document).ready(function(){
switchTenderType("tender-type-div", "TenderTenderTypeId");
});
--></script>
<?php
; // align
echo $form->create('Tender', array('action' => 'edit')) . "\n";
echo $form->input('id') . "\n";
if (empty($this->data['Tender']))
INTERNAL_ERROR('Creation of new Tender not allowed.');
echo $form->input('tender_type_id',
array('div' => 'tender input',
// REVISIT <AP>: 20090810
// We're not ready to allow changing the type
// of a tender, since it will force us to deal
// with changing the LedgerEntry account (easy)
// and the associated StatementEntry accounts
// (not too hard), and make sure the tender has
// not been deposited (easy), and then deal with
// any corner cases that pop up.
'disabled' => true,
'onclick' => ('switchTenderType(' .
'"tender-type-div", ' .
'$(this).attr("id")' .
')'),
)) . "\n";
$form->input('comment');
foreach ($types AS $type) {
$type = $type['TenderType'];
echo('<DIV' .
' ID="tender-type-div-'.$type['id'].'"' .
' CLASS="tender-type-div"' .
($type['id'] != $this->data['TenderType']['id']
? ' STYLE="display:none;"' : '') .
'>' . "\n");
echo ('<INPUT TYPE="hidden"' .
' NAME="data[type]['.$type['id'].'][tender_type_id]"' .
' VALUE="'.$type['id'].'"' .
'>' . "\n");
for ($i=1; $i<=4; ++$i) {
if (!empty($type["data{$i}_name"])) {
echo $form->input("type.{$type['id']}.data$i",
array('label' => $type["data{$i}_name"],
'div' => 'input text tender',
'value' =>
($type['id'] == $this->data['TenderType']['id']
? $this->data['Tender']["data$i"] : null),
)) . "\n";
/* echo ('<DIV CLASS="input text required">' . */
/* ' <INPUT TYPE="text" SIZE="20"' . */
/* ' NAME="data[type]['.$type['id'].'][data'.$i.']"' . */
/* ' CLASS="tender"' . */
/* ' ID= */
/* '<LABEL' . */
/* ' CLASS="tender"' . */
/* ' FOR="tender-data'.$i.'">' . */
/* $type["data{$i}_name"] . */
/* '</LABEL>' . "\n" . */
/* '</DIV>' . "\n"); */
}
}
echo('</DIV>' . "\n");
}
echo $form->submit('Update') . "\n";
echo $form->submit('Cancel', array('name' => 'cancel')) . "\n";
echo $form->end() . "\n";
echo '</div>' . "\n";

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