Further progress on payment entries. There is an outstanding charges grid, but it doesn't have amounts due to the way I designed the ledger_entries element. I'll do a bit of rework on that next.
git-svn-id: file:///svn-source/pmgr/branches/ledger_transactions_20090605/site@163 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
@@ -180,15 +180,59 @@ class CustomersController extends AppController {
|
||||
/* $customer = $this->data; */
|
||||
/* } */
|
||||
if (isset($id)) {
|
||||
$customer = $this->Customer->details($id);
|
||||
unset($customer['deposits']['Entries']);
|
||||
$this->Customer->recursive = -1;
|
||||
$customer = $this->Customer->read(null, $id);
|
||||
$customer = $customer['Customer'];
|
||||
$unreconciled = $this->Customer->findUnreconciledLedgerEntries($id);
|
||||
$charges = $unreconciled['debit'];
|
||||
}
|
||||
else {
|
||||
$customer = null;
|
||||
$charges = array('balance' => 0, 'entry' => array());
|
||||
}
|
||||
|
||||
$title = 'Payment Entry';
|
||||
$this->set(compact('customer', 'title'));
|
||||
$this->set(compact('customer', 'charges', 'title'));
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
**************************************************************************
|
||||
**************************************************************************
|
||||
* action: unreconciledEntries
|
||||
* - returns the list of unreconciled entries
|
||||
*/
|
||||
|
||||
function unreconciled($id) {
|
||||
|
||||
//$this->layout = 'ajax';
|
||||
$this->layout = null;
|
||||
$this->autoLayout = false;
|
||||
$this->autoRender = false;
|
||||
Configure::write('debug', '0');
|
||||
header("Content-type: text/xml;charset=utf-8");
|
||||
|
||||
App::import('Helper', 'Xml');
|
||||
$xml = new XmlHelper();
|
||||
|
||||
// Find the unreconciled entries, then manipulate the structure
|
||||
// slightly to accomodate the format necessary for XML Helper.
|
||||
$unreconciled = $this->Customer->findUnreconciledLedgerEntries($id);
|
||||
$unreconciled = array('entries' =>
|
||||
array_intersect_key($unreconciled['debit'],
|
||||
array('entry'=>1, 'balance'=>1)));
|
||||
|
||||
// XML Helper will dump an empty tag if the array is empty
|
||||
if (!count($unreconciled['entries']['entry']))
|
||||
unset($unreconciled['entries']['entry']);
|
||||
|
||||
pr($unreconciled);
|
||||
//$reconciled = $cust->reconcileNewLedgerEntry($cust_id, 'credit', $amount);
|
||||
|
||||
$opts = array();
|
||||
//$opts['format'] = 'tags';
|
||||
echo $xml->header();
|
||||
echo $xml->serialize($unreconciled, $opts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ class Account extends AppModel {
|
||||
? array($fundamental_type)
|
||||
: array('debit', 'credit')) AS $fund) {
|
||||
$ucfund = ucfirst($fund);
|
||||
$unreconciled[$fund]['entries'] = $this->find
|
||||
$unreconciled[$fund]['entry'] = $this->find
|
||||
('all', array
|
||||
('link' => array
|
||||
('Ledger' => array
|
||||
@@ -261,7 +261,7 @@ class Account extends AppModel {
|
||||
'fields' => array(),
|
||||
));
|
||||
$balance = 0;
|
||||
foreach ($unreconciled[$fund]['entries'] AS &$entry) {
|
||||
foreach ($unreconciled[$fund]['entry'] AS &$entry) {
|
||||
$entry = array_merge(array_diff_key($entry["LedgerEntry"], array(0=>true)),
|
||||
$entry[0]);
|
||||
$balance += $entry['balance'];
|
||||
@@ -289,7 +289,7 @@ class Account extends AppModel {
|
||||
|
||||
function reconcileNewLedgerEntry($id, $fundamental_type, $amount) {
|
||||
$ofund = $this->fundamentalOpposite($fundamental_type);
|
||||
$unreconciled = array($ofund => array('entries'=>array(), 'balance'=>0));
|
||||
$unreconciled = array($ofund => array('entry'=>array(), 'balance'=>0));
|
||||
$applied = 0;
|
||||
|
||||
// if there is no money in the entry, it can reconcile nothing
|
||||
@@ -297,7 +297,7 @@ class Account extends AppModel {
|
||||
if ($amount > 0) {
|
||||
$unreconciled = $this->findUnreconciledLedgerEntries($id, $ofund);
|
||||
|
||||
foreach ($unreconciled[$ofund]['entries'] AS $i => &$entry) {
|
||||
foreach ($unreconciled[$ofund]['entry'] AS $i => &$entry) {
|
||||
// Determine if amount is sufficient to cover the entry
|
||||
if ($amount > $entry['balance'])
|
||||
$apply = $entry['balance'];
|
||||
|
||||
@@ -122,7 +122,7 @@ class Customer extends AppModel {
|
||||
$left = &$unreconciled[$type];
|
||||
$right = &$unrec[$type];
|
||||
|
||||
$left['entries'] = array_merge($left['entries'], $right['entries']);
|
||||
$left['entry'] = array_merge($left['entry'], $right['entry']);
|
||||
$left['balance'] += $right['balance'];
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ class Customer extends AppModel {
|
||||
$left = &$reconciled[$type];
|
||||
$right = &$rec[$type];
|
||||
|
||||
$left['entries'] = array_merge($left['entries'], $right['entries']);
|
||||
$left['entry'] = array_merge($left['entry'], $right['entry']);
|
||||
$left['balance'] += $right['balance'];
|
||||
$left['applied'] += $right['applied'];
|
||||
$left['unapplied'] = $right['unapplied'];
|
||||
|
||||
@@ -54,36 +54,14 @@
|
||||
|
||||
$grid_setup = array();
|
||||
|
||||
if (isset($customer['Customer']['id']))
|
||||
if (isset($customer['id']))
|
||||
$grid_setup['hiddengrid'] = true;
|
||||
|
||||
$grid_setup['onSelectRow'] = array
|
||||
('--special' =>
|
||||
'function(ids) { if (ids != null)' .
|
||||
' {' .
|
||||
// Set the customer id that will be returned with the form
|
||||
' $("#customer-id").val(ids);' .
|
||||
// Get the customer name from the grid
|
||||
' $("#payment_customer").html($("#"+$(this).attr("id"))' .
|
||||
' .getCell(ids, "Customer-name"));' .
|
||||
// Replace that with just the text portion of the hyperlink
|
||||
' $("#payment_customer").html("Receipt for "+ $("#payment_customer a").html());' .
|
||||
' } }'
|
||||
'function(ids) { if (ids != null) { onRowSelect("#"+$(this).attr("id"), ids); } }'
|
||||
);
|
||||
|
||||
/* $grid_setup['loadComplete'] = array */
|
||||
/* ('--special' => */
|
||||
/* 'function() { ' . */
|
||||
/* //' $("#"+$(this).attr("id")).setSelection($("#customer-id").val());' . */
|
||||
/* ' $(\'#customers-list-jqGrid\').setSelection($(\'#customer-id\').val());' . */
|
||||
/* ' $("#"+$(this).attr("id")).setCaption("Hello");' . */
|
||||
/* ' alert("Loaded");' . */
|
||||
/* ' }' */
|
||||
/* ); */
|
||||
|
||||
|
||||
//pr($customer);
|
||||
//echo ('<A HREF="#" ONCLICK="$(\'#debug\').append(htmlEncode($(\'#customers-list\').html())); return false">Get grid code</A><BR>');
|
||||
|
||||
// Customer
|
||||
// Outstanding balance
|
||||
@@ -95,7 +73,7 @@ $grid_setup['onSelectRow'] = array
|
||||
|
||||
?>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
// prepare the form when the DOM is ready
|
||||
$(document).ready(function() {
|
||||
@@ -127,9 +105,13 @@ $grid_setup['onSelectRow'] = array
|
||||
// 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('<PRE>'+dump(formData)+'</PRE>');
|
||||
$('#request-debug').html('Ommitted');
|
||||
//return false;
|
||||
|
||||
$('#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;
|
||||
@@ -311,6 +293,60 @@ function switchPaymentType(paymentid, type) {
|
||||
}
|
||||
|
||||
|
||||
function updateChargesCaption(customer_name, balance) {
|
||||
$('#charge-entries-jqGrid').setCaption('Outstanding Charges for ' +
|
||||
customer_name + ': ' +
|
||||
fmtCurrency(balance));
|
||||
}
|
||||
|
||||
function updateChargesGrid(idlist, balance) {
|
||||
updateChargesCaption($("#payment_customer").html(), balance);
|
||||
|
||||
$('#charge-entries-jqGrid').setPostDataItem('idlist', serialize(idlist));
|
||||
$('#charge-entries-jqGrid')
|
||||
.setGridParam({ page: 1 })
|
||||
.trigger("reloadGrid");
|
||||
}
|
||||
|
||||
function updateCharges(id) {
|
||||
var url = '<?php echo ($html->url(array("controller" => $this->params["controller"],
|
||||
"action" => "unreconciled"))); ?>';
|
||||
//url += '/'+$("#customer-id").val();
|
||||
url += '/'+id;
|
||||
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "xml",
|
||||
success: function(xml) {
|
||||
var ids = new Array();
|
||||
$('#update-target ol').html('<A HREF="'+url+'">Data URL</A>');
|
||||
$('entry',xml).each(function(i){
|
||||
ids.push($(this).attr('id'));
|
||||
$('#update-target').append("Push: len=" + ids.length + '<BR>');
|
||||
});
|
||||
updateChargesGrid(ids, $('entries',xml).attr('balance'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onRowSelect(grid_id, cust_id) {
|
||||
// Set the customer id that will be returned with the form
|
||||
$("#customer-id").val(cust_id);
|
||||
|
||||
// Get the customer name from the grid
|
||||
$("#payment_customer").html($(grid_id).getCell(cust_id, "Customer-name"));
|
||||
|
||||
// Replace that with just the text portion of the hyperlink
|
||||
$("#payment_customer").html($("#payment_customer a").html());
|
||||
|
||||
// Hide the "no customer" message and show the current customer
|
||||
$("#no_customer").hide();
|
||||
$("#current_customer").show();
|
||||
|
||||
updateCharges(cust_id);
|
||||
}
|
||||
|
||||
--></script>
|
||||
|
||||
<?php
|
||||
@@ -318,16 +354,34 @@ function switchPaymentType(paymentid, type) {
|
||||
//echo '<DIV ID="dialog">' . "\n";
|
||||
|
||||
echo $this->element('customers',
|
||||
array('caption' => '<A HREF="#" ONCLICK="$(\'.HeaderButton\').click(); return false;">Select Customer</A>',
|
||||
array('grid_div_id' => 'customers-list',
|
||||
'caption' => ('<A HREF="#" ONCLICK="$(\'#customers-list .HeaderButton\').click();'.
|
||||
' return false;">Select Customer</A>'),
|
||||
'limit' => 7,
|
||||
'grid_setup' => $grid_setup,
|
||||
));
|
||||
|
||||
echo ('<H2><SPAN id="payment_customer">' .
|
||||
(isset($customer['Customer']['id'])
|
||||
? 'Receipt for ' . $customer['Customer']['name']
|
||||
: 'Please select customer') .
|
||||
'</SPAN></H2>' . "\n");
|
||||
echo $this->element('ledger_entries',
|
||||
array('grid_div_id' => 'charge-entries',
|
||||
'caption' => 'Outstanding Charges',
|
||||
/* (isset($customer['name']) */
|
||||
/* ? " for {$customer['name']}: ".FormatHelper::currency($charges['balance']) */
|
||||
/* : '')), */
|
||||
'limit' => 8,
|
||||
'ledger_id' => 6,
|
||||
'account_type' => 'credit',
|
||||
'ledger_entries' => $charges['entry'],
|
||||
));
|
||||
|
||||
echo ('<H2>' .
|
||||
'<SPAN id="current_customer" style="display:'.(isset($customer['id'])?"inline":"none").'">' .
|
||||
'Enter new receipt for ' .
|
||||
'<SPAN id="payment_customer">' . (isset($customer['name']) ? $customer['name'] : "") . '</SPAN>' .
|
||||
'</SPAN>' .
|
||||
'<SPAN id="no_customer" style="display:'.(isset($customer['id'])?"none":"inline").'">' .
|
||||
'Please select customer' .
|
||||
'</SPAN>' .
|
||||
'</H2>' . "\n");
|
||||
|
||||
echo $form->create(null, array('id' => 'payment-form',
|
||||
'url' => array('controller' => 'transactions',
|
||||
@@ -373,7 +427,7 @@ echo $form->create(null, array('id' => 'payment-form',
|
||||
***************************************************/
|
||||
|
||||
?>
|
||||
<input type="hidden" id="customer-id" name="data[Customer][id]" value="<?php echo $customer['Customer']['id']; ?>">
|
||||
<input type="hidden" id="customer-id" name="data[Customer][id]" value="<?php echo $customer['id']; ?>">
|
||||
|
||||
<fieldset CLASS="payment superset">
|
||||
<legend>Payments</legend>
|
||||
@@ -393,12 +447,10 @@ echo $form->end('Post Payment');
|
||||
//echo '</DIV>' . "\n"; // End of the dialog DIV
|
||||
?>
|
||||
|
||||
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>
|
||||
<?php
|
||||
/* <button id="post-payment" class="ui-button ui-state-default ui-corner-all">Create Payment</button> */
|
||||
?>
|
||||
|
||||
|
||||
<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>
|
||||
@@ -412,6 +464,13 @@ echo $form->end('Post Payment');
|
||||
$("#datepicker").datepicker()
|
||||
.datepicker('setDate', '+0');
|
||||
|
||||
<?php if (isset($customer['id'])) { ?>
|
||||
$("#customer-id").val(<?php echo $customer['id']; ?>);
|
||||
updateChargesCaption("<?php echo $customer['name']; ?>",
|
||||
<?php echo $charges['balance']; ?>);
|
||||
<?php } ?>
|
||||
|
||||
|
||||
/* $("#dialog").dialog({ */
|
||||
/* bgiframe: true, */
|
||||
/* autoOpen: false, */
|
||||
@@ -439,8 +498,10 @@ echo $form->end('Post Payment');
|
||||
/* }); */
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<a href="#" onClick="$('#debug').html(''); return false;">Clear Debug Output</a>
|
||||
|
||||
@@ -15,7 +15,7 @@ $jqGrid_options = array('jqGridColumns' => $cols,
|
||||
'controller' => 'customers');
|
||||
|
||||
// User requested options have priority
|
||||
$jqGrid_options += compact('caption', 'grid_setup', 'limit');
|
||||
$jqGrid_options += compact('grid_div_id', 'grid_id', 'caption', 'grid_setup', 'limit');
|
||||
|
||||
if (isset($customers)) {
|
||||
$jqGrid_options += array('custom_ids' =>
|
||||
|
||||
@@ -18,11 +18,11 @@ $custom_post_data = array('ledger_id' => $ledger_id,
|
||||
'account_type' => $account_type);
|
||||
|
||||
$jqGrid_options = array('jqGridColumns' => $cols,
|
||||
'grid_id' => isset($grid_id) ? $grid_id : null,
|
||||
'caption' => isset($caption) ? $caption : null,
|
||||
'controller' => 'ledger_entries',
|
||||
);
|
||||
|
||||
$jqGrid_options += compact('grid_div_id', 'grid_id', 'caption', 'grid_setup', 'limit');
|
||||
|
||||
if (isset($ledger_entries)) {
|
||||
$jqGrid_options += array('custom_ids' =>
|
||||
array_map(create_function('$data',
|
||||
|
||||
@@ -134,3 +134,105 @@ function fmtCurrency(amount) {
|
||||
}
|
||||
|
||||
|
||||
// REVISIT <AP>: 20090617
|
||||
// I would rather use XML to pass from JS to PHP, but at the
|
||||
// moment things were working just fine with serialize, and
|
||||
// I'm not keen on redesigning it at the moment. So, here
|
||||
// is a serialize implementation I found on the web.
|
||||
|
||||
function serialize( mixed_value ) {
|
||||
// http://kevin.vanzonneveld.net
|
||||
// + original by: Arpad Ray (mailto:arpad@php.net)
|
||||
// + improved by: Dino
|
||||
// + bugfixed by: Andrej Pavlovic
|
||||
// + bugfixed by: Garagoth
|
||||
// + input by: DtTvB (http://dt.in.th/2008-09-16.string-length-in-bytes.html)
|
||||
// + bugfixed by: Russell Walker
|
||||
// % note: We feel the main purpose of this function should be to ease the transport of data between php & js
|
||||
// % note: Aiming for PHP-compatibility, we have to translate objects to arrays
|
||||
// * example 1: serialize(['Kevin', 'van', 'Zonneveld']);
|
||||
// * returns 1: 'a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}'
|
||||
// * example 2: serialize({firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'});
|
||||
// * returns 2: 'a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}'
|
||||
|
||||
var _getType = function( inp ) {
|
||||
var type = typeof inp, match;
|
||||
var key;
|
||||
if (type == 'object' && !inp) {
|
||||
return 'null';
|
||||
}
|
||||
if (type == "object") {
|
||||
if (!inp.constructor) {
|
||||
return 'object';
|
||||
}
|
||||
var cons = inp.constructor.toString();
|
||||
match = cons.match(/(\w+)\(/);
|
||||
if (match) {
|
||||
cons = match[1].toLowerCase();
|
||||
}
|
||||
var types = ["boolean", "number", "string", "array"];
|
||||
for (key in types) {
|
||||
if (cons == types[key]) {
|
||||
type = types[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return type;
|
||||
};
|
||||
var type = _getType(mixed_value);
|
||||
var val, ktype = '';
|
||||
|
||||
switch (type) {
|
||||
case "function":
|
||||
val = "";
|
||||
break;
|
||||
case "undefined":
|
||||
val = "N";
|
||||
break;
|
||||
case "boolean":
|
||||
val = "b:" + (mixed_value ? "1" : "0");
|
||||
break;
|
||||
case "number":
|
||||
val = (Math.round(mixed_value) == mixed_value ? "i" : "d") + ":" + mixed_value;
|
||||
break;
|
||||
case "string":
|
||||
val = "s:" + encodeURIComponent(mixed_value).replace(/%../g, 'x').length + ":\"" + mixed_value + "\"";
|
||||
break;
|
||||
case "array":
|
||||
case "object":
|
||||
val = "a";
|
||||
/*
|
||||
if (type == "object") {
|
||||
var objname = mixed_value.constructor.toString().match(/(\w+)\(\)/);
|
||||
if (objname == undefined) {
|
||||
return;
|
||||
}
|
||||
objname[1] = serialize(objname[1]);
|
||||
val = "O" + objname[1].substring(1, objname[1].length - 1);
|
||||
}
|
||||
*/
|
||||
var count = 0;
|
||||
var vals = "";
|
||||
var okey;
|
||||
var key;
|
||||
for (key in mixed_value) {
|
||||
ktype = _getType(mixed_value[key]);
|
||||
if (ktype == "function") {
|
||||
continue;
|
||||
}
|
||||
|
||||
okey = (key.match(/^[0-9]+$/) ? parseInt(key, 10) : key);
|
||||
vals += serialize(okey) +
|
||||
serialize(mixed_value[key]);
|
||||
count++;
|
||||
}
|
||||
val += ":" + count + ":{" + vals + "}";
|
||||
break;
|
||||
}
|
||||
if (type != "object" && type != "array") {
|
||||
val += ";";
|
||||
}
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user