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@163 97e9348a-65ac-dc4b-aefc-98561f571b83
This commit is contained in:
abijah
2009-06-18 00:49:40 +00:00
parent ba218fbeeb
commit a2ae522b2d
7 changed files with 255 additions and 48 deletions

View File

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

View File

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

View File

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

View File

@@ -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,8 +105,12 @@ $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
@@ -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>

View File

@@ -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' =>

View File

@@ -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',

View File

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