]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/server/patron/bill2.js
12109b1bd832a12f9e8d57f9ba2d1b185f3ab0ee
[Evergreen.git] / Open-ILS / xul / staff_client / server / patron / bill2.js
1 function my_init() {
2     try {
3         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
4         if (typeof JSAN == 'undefined') { throw( $("commonStrings").getString('common.jsan.missing') ); }
5         JSAN.errorLevel = "die"; // none, warn, or die
6         JSAN.addRepository('/xul/server/');
7
8         JSAN.use('util.error'); g.error = new util.error();
9         JSAN.use('util.network'); g.network = new util.network();
10         JSAN.use('util.date');
11         JSAN.use('util.money');
12         JSAN.use('util.widgets');
13         JSAN.use('patron.util');
14         JSAN.use('OpenILS.data'); g.data = new OpenILS.data(); g.data.init({'via':'stash'});
15         g.data.voided_billings = []; g.data.stash('voided_billings');
16
17         g.error.sdump('D_TRACE','my_init() for bill2.xul');
18
19         if (xul_param('current')) {
20             $('caption').setAttribute('label',$("patronStrings").getString('staff.patron.bill_history.my_init.current_bills'));
21             document.title = $("patronStrings").getString('staff.patron.bill_history.my_init.current_bills');
22         } else {
23             $('caption').setAttribute('label',$("patronStrings").getString('staff.patron.bill_history.my_init.bill_history'));
24             document.title = $("patronStrings").getString('staff.patron.bill_history.my_init.bill_history');
25         }
26
27         g.funcs = []; g.bill_map = {}; g.row_map = {}; g.check_map = {};
28
29         g.patron_id = xul_param('patron_id');
30
31         $('circulating_hint').hidden = true;
32
33         init_lists();
34
35         retrieve_mbts_for_list();
36
37         event_listeners();
38
39         JSAN.use('util.exec'); var exec = new util.exec(20); 
40         exec.on_error = function(E) { alert(E); return true; }
41         exec.timer(g.funcs,100);
42
43         $('credit_forward').setAttribute('value','???');
44         if (!g.patron) {
45             refresh_patron();
46         } else {
47             $('credit_forward').setAttribute('value',util.money.sanitize( g.patron.credit_forward_balance() ));
48         }
49
50         default_focus();
51
52         tally_all();
53
54     } catch(E) {
55         var err_msg = $("commonStrings").getFormattedString('common.exception', ['patron/bill2.xul', E]);
56         try { g.error.sdump('D_ERROR',err_msg); } catch(E) { dump(err_msg); }
57         alert(err_msg);
58     }
59 }
60
61 function event_listeners() {
62     try {
63         $('details').addEventListener(
64             'command',
65             handle_details,
66             false
67         );
68
69         $('add').addEventListener(
70             'command',
71             handle_add,
72             false
73         );
74
75         $('voidall').addEventListener(
76             'command',
77             handle_void_all,
78             false
79         );
80
81         $('refund').addEventListener(
82             'command',
83             handle_refund,
84             false
85         );
86
87         $('opac').addEventListener(
88             'command',
89             handle_opac,
90             false
91         );
92
93         $('copy_details').addEventListener(
94             'command',
95             handle_copy_details,
96             false
97         );
98
99         $('payment').addEventListener(
100             'change',
101             function(ev) {
102                 if ($('payment_type').value == 'credit_payment') {
103                     JSAN.use('util.money');
104                     JSAN.use('patron.util'); g.patron = patron.util.retrieve_fleshed_au_via_id(ses(),g.patron_id,null);
105                     var proposed = util.money.dollars_float_to_cents_integer(ev.target.value);
106                     var available = util.money.dollars_float_to_cents_integer(g.patron.credit_forward_balance());
107                     if (proposed > available) {
108                         alert($("patronStrings").getFormattedString('staff.patron.bills.bill_payment_amount.credit_amount', [g.patron.credit_forward_balance()]));
109                         ev.target.value = util.money.cents_as_dollars( available );
110                         ev.target.setAttribute('value',ev.target.value);
111                     }
112                 }
113                 distribute_payment(); 
114             },
115             false
116         );
117
118         $('payment').addEventListener(
119             'focus',
120             function(ev) { ev.target.select(); },
121             false
122         );
123
124         $('payment').addEventListener(
125             'keypress',
126             function(ev) {
127                 if (! (ev.keyCode == 13 /* enter */ || ev.keyCode == 77 /* mac enter */) ) { return; }
128                 distribute_payment();
129                 $('apply_payment_btn').focus();
130             },
131             false
132         );
133
134         $('bill_patron_btn').addEventListener(
135             'command',
136             function() {
137                 JSAN.use('util.window'); var win = new util.window();
138                 var my_xulG = win.open(
139                     urls.XUL_PATRON_BILL_WIZARD,
140                     'billwizard',
141                     'chrome,resizable,modal',
142                     { 'patron_id' : g.patron_id }
143                 );
144                 if (my_xulG.xact_id) { g.funcs.push( gen_list_append_func( my_xulG.xact_id ) ); /* FIXME: do something to update summary sidebar */ }
145             },
146             false
147         );
148
149         $('bill_history_btn').addEventListener(
150             'command',
151             function() {
152                 xulG.display_window.g.patron.right_deck.reset_iframe( 
153                     urls.XUL_PATRON_BILL_HISTORY,
154                     {},
155                     {
156                         'patron_id' : g.patron_id,
157                         'refresh' : function() { refresh(); },
158                         'new_tab' : xulG.new_tab
159                     }
160                 );
161             },
162             false
163         );
164
165         $('convert_change_to_credit').addEventListener(
166             'command',
167             function(ev) {
168                 if (ev.target.checked) {
169                     addCSSClass( $('change_due'), 'change_to_credit' );
170                 } else {
171                     removeCSSClass( $('change_due'), 'change_to_credit' );
172                 }
173             },
174             false
175         );
176
177         $('apply_payment_btn').addEventListener(
178             'command',
179             function(ev) {
180                 try {
181                     apply_payment();
182                 } catch(E) {
183                     alert('Error in bill2.js, apply_payment_btn: ' + E);
184                 }
185             },
186             false
187         );
188
189     } catch(E) {
190         alert('Error in bill2.js, event_listeners(): ' + E);
191     }
192 }
193
194 function $(id) { return document.getElementById(id); }
195
196 function default_focus() {
197     try { $('payment').focus(); } catch(E) { alert('Error in default_focus(): ' + E); }
198 }
199
200 function tally_pending() {
201     try {
202         var payments = [];
203         JSAN.use('util.money');
204         var tb = $('payment');
205         var payment_tendered = util.money.dollars_float_to_cents_integer( tb.value );
206         var payment_pending = 0;
207         var retrieve_ids = g.bill_list.dump_retrieve_ids();
208         for (var i = 0; i < retrieve_ids.length; i++) {
209             var row_params = g.row_map[retrieve_ids[i]];
210             if (g.check_map[retrieve_ids[i]]) { 
211                 var value = util.money.dollars_float_to_cents_integer( row_params.row.my.payment_pending );
212                 payment_pending += value;
213                 if (value != '0.00') { payments.push( [ retrieve_ids[i], util.money.cents_as_dollars(value) ] ); }
214             }
215         }
216         var change_pending = payment_tendered - payment_pending;
217         $('pending_payment').value = util.money.cents_as_dollars( payment_pending );
218         $('pending_change').value = util.money.cents_as_dollars( change_pending );
219         $('change_due').value = util.money.cents_as_dollars( change_pending );
220         return { 'payments' : payments, 'change' : util.money.cents_as_dollars( change_pending ) };
221     } catch(E) {
222         alert('Error in bill2.js, tally_pending(): ' + E);
223     }
224 }
225
226 function tally_selected() {
227     try {
228         JSAN.use('util.money');
229         var selected_billed = 0;
230         var selected_paid = 0;
231         var selected_balance = 0;
232
233         for (var i = 0; i < g.bill_list_selection.length; i++) {
234             var bill = g.bill_map[g.bill_list_selection[i]];
235             if (!bill) {
236                 //$('checked_owed').setAttribute('value', '???');
237                 //$('checked_billed').setAttribute('value', '???');
238                 //$('checked_paid').setAttribute('value', '???');
239                 return;
240             }
241             var to = util.money.dollars_float_to_cents_integer( bill.transaction.total_owed() );
242             var tp = util.money.dollars_float_to_cents_integer( bill.transaction.total_paid() );
243             var bo = util.money.dollars_float_to_cents_integer( bill.transaction.balance_owed() );
244             selected_billed += to;
245             selected_paid += tp;
246             selected_balance += bo;
247         }
248         //$('checked_billed').setAttribute('value', util.money.cents_as_dollars( selected_billed ) );
249         //$('checked_paid').setAttribute('value', util.money.cents_as_dollars( selected_paid ) );
250         //$('checked_owed').setAttribute('value', util.money.cents_as_dollars( selected_balance ) );
251     } catch(E) {
252         alert('Error in bill2.js, tally_selected(): ' + E);
253     }
254 }
255
256 function tally_voided() {
257     try {
258         JSAN.use('util.money');
259         var voided_total = 0;
260
261         g.data.stash_retrieve();
262
263         for (var i = 0; i < g.data.voided_billings.length; i++) {
264             var billing = g.data.voided_billings[i];
265             var bv = util.money.dollars_float_to_cents_integer( billing.amount() );
266             voided_total += bv;
267         }
268         $('currently_voided').setAttribute('value', util.money.cents_as_dollars( voided_total ) );
269     } catch(E) {
270         alert('Error in bill2.js, tally_voided(): ' + E);
271     }
272 }
273
274 function tally_all() {
275     try {
276         JSAN.use('util.money');
277         var checked_billed = 0;
278         var checked_paid = 0;
279         var checked_balance = 0;
280         var total_billed = 0;
281         var total_paid = 0;
282         var total_balance = 0;
283         var refunds_owed = 0;
284
285         var retrieve_ids = g.bill_list.dump_retrieve_ids();
286         for (var i = 0; i < retrieve_ids.length; i++) {
287             var bill = g.bill_map[retrieve_ids[i]];
288             if (!bill) {
289                 $('checked_owed').value = '???';
290                 $('checked_owed2').setAttribute('value', '???');
291                 $('checked_billed').value = '???';
292                 $('checked_paid').value = '???';
293                 $('tb_total_owed').value = '???';
294                 $('total_owed2').setAttribute('value', '???');
295                 $('total_billed').value = '???';
296                 $('tb_total_paid').value = '???';
297                 $('refunds_owed').setAttribute('value', '???');
298                 return;
299             }
300             var to = util.money.dollars_float_to_cents_integer( bill.transaction.total_owed() );
301             var tp = util.money.dollars_float_to_cents_integer( bill.transaction.total_paid() );
302             var bo = util.money.dollars_float_to_cents_integer( bill.transaction.balance_owed() );
303             total_billed += to;
304             total_paid += tp;
305             total_balance += bo;
306             if ( bo < 0 ) refunds_owed += bo;
307             if (g.check_map[retrieve_ids[i]]) {
308                 checked_billed += to;
309                 checked_paid += tp;
310                 checked_balance += bo;
311             }
312         }
313         $('checked_billed').value = util.money.cents_as_dollars( checked_billed );
314         $('checked_paid').value = util.money.cents_as_dollars( checked_paid );
315         $('checked_owed').value = util.money.cents_as_dollars( checked_balance );
316         $('checked_owed2').setAttribute('value', util.money.cents_as_dollars( checked_balance ) );
317         $('total_billed').value = util.money.cents_as_dollars( total_billed );
318         $('tb_total_paid').value = util.money.cents_as_dollars( total_paid );
319         $('tb_total_owed').value = util.money.cents_as_dollars( total_balance );
320         $('total_owed2').setAttribute('value', util.money.cents_as_dollars( total_balance ) );
321         $('refunds_owed').setAttribute('value', util.money.cents_as_dollars( Math.abs( refunds_owed ) ) );
322         // tally_selected();
323     } catch(E) {
324         alert('Error in bill2.js, tally_all(): ' + E);
325     }
326 }
327
328 function handle_refund() {
329     if(g.bill_list_selection.length > 1) {
330         var msg = $("patronStrings").getFormattedString('staff.patron.bills.handle_refund.message_plural', [g.bill_list_selection]);
331     } else {
332         var msg = $("patronStrings").getFormattedString('staff.patron.bills.handle_refund.message_singular', [g.bill_list_selection]);
333     }
334         
335     var r = g.error.yns_alert(msg,
336         $("patronStrings").getString('staff.patron.bills.handle_refund.title'),
337         $("patronStrings").getString('staff.patron.bills.handle_refund.btn_yes'),
338         $("patronStrings").getString('staff.patron.bills.handle_refund.btn_no'),null,
339         $("patronStrings").getString('staff.patron.bills.handle_refund.confirm_message'));
340     if (r == 0) {
341         for (var i = 0; i < g.bill_list_selection.length; i++) {
342             var bill_id = g.bill_list_selection[i];
343             //alert('g.check_map['+bill_id+'] = '+g.check_map[bill_id]+' bill_map['+bill_id+'] = ' + js2JSON(g.bill_map[bill_id]));
344             g.check_map[bill_id] = true;
345             var row_params = g.row_map[bill_id];
346             row_params.row.my.checked = true;
347             g.bill_list.refresh_row(row_params);
348         }
349     }
350     tally_all();
351     distribute_payment();
352 }
353
354
355 function check_all() {
356     try {
357         for (var i in g.bill_map) {
358             g.check_map[i] = true;
359             var row_params = g.row_map[i];
360             row_params.row.my.checked = true;
361             g.bill_list.refresh_row(row_params);
362         }
363         tally_all();
364         distribute_payment();
365     } catch(E) {
366         alert('Error in bill2.js, check_all(): ' + E);
367     }
368
369 }
370
371 function uncheck_all() {
372     try {
373         for (var i in g.bill_map) {
374             g.check_map[i] = false;
375             var row_params = g.row_map[i];
376             row_params.row.my.checked = false;
377             g.bill_list.refresh_row(row_params);
378         }
379         tally_all();
380         distribute_payment();
381     } catch(E) {
382         alert('Error in bill2.js, check_all(): ' + E);
383     }
384
385 }
386
387 function check_all_refunds() {
388     try {
389         for (var i in g.bill_map) {
390             if ( Number( g.bill_map[i].transaction.balance_owed() ) < 0 ) {
391                 g.check_map[i] = true;
392                 var row_params = g.row_map[i];
393                 row_params.row.my.checked = true;
394                 g.bill_list.refresh_row(row_params);
395             }
396         }
397         tally_all();
398         distribute_payment();
399     } catch(E) {
400         alert('Error in bill2.js, check_all_refunds(): ' + E);
401     }
402 }
403
404 function gen_list_append_func(r) {
405     return function() {
406         if (typeof r == 'object') { g.row_map[ r.id() ] = g.bill_list.append( { 'retrieve_id' : r.id(), 'flesh_immediately' : true, 'row' : { 'my' : { 'checked' : true, 'mbts' : r } } } );
407         } else { g.row_map[r] = g.bill_list.append( { 'retrieve_id' : r, 'flesh_immediately' : true, 'row' : { 'my' : { 'checked' : true } } } ); }
408     }
409 }
410
411 function retrieve_mbts_for_list() {
412     var method = 'FM_MBTS_IDS_RETRIEVE_ALL_HAVING_BALANCE.authoritative';
413     g.mbts_ids = g.network.simple_request(method,[ses(),g.patron_id]);
414     if (g.mbts_ids.ilsevent) {
415         switch(Number(g.mbts_ids.ilsevent)) {
416             case -1: g.error.standard_network_error_alert($("patronStrings").getString('staff.patron.bill_history.retrieve_mbts_for_list.close_win_try_again')); break;
417             default: g.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.bill_history.retrieve_mbts_for_list.close_win_try_again'),g.mbts_ids); break;
418         }
419     } else if (g.mbts_ids == null) {
420         g.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.bill_history.retrieve_mbts_for_list.close_win_try_again'),null);
421     } else {
422    
423         g.mbts_ids.reverse();
424  
425         for (var i = 0; i < g.mbts_ids.length; i++) {
426             dump('i = ' + i + ' g.mbts_ids[i] = ' + g.mbts_ids[i] + '\n');
427             g.funcs.push( gen_list_append_func(g.mbts_ids[i]) );
428         }
429     }
430 }
431
432 function init_lists() {
433     JSAN.use('util.list'); JSAN.use('circ.util'); 
434
435     g.bill_list_selection = [];
436
437     g.bill_list = new util.list('bill_tree');
438
439     g.bill_list.init( {
440         'columns' : 
441             [
442                 {
443                     'id' : 'select', 'primary' : true, 'type' : 'checkbox', 'editable' : true, 'label' : '', 'style' : 'min-width: 3em;',
444                     'render' : function(my) { return String( my.checked ) == 'true'; }, 
445                 }
446             ].concat(
447                 patron.util.mbts_columns({
448                     'mbts_xact_finish' : { 'hidden' : xul_param('current') ? true : false }
449                 }
450             ).concat( 
451                 circ.util.columns({ 
452                     'title' : { 'hidden' : false, 'flex' : '3' }
453                 }
454             ).concat( 
455                 [
456                     {
457                         'id' : 'payment_pending', 'editable' : false, 'sort_type' : 'money', 
458                         'label' : $('patronStrings').getString('staff.patron.bill_interface.payment_pending.column_header'),
459                         'render' : function(my) { return my.payment_pending || '0.00'; }, 
460                     }
461                 ]
462             ))),
463         'map_row_to_columns' : patron.util.std_map_row_to_columns(' '),
464         'on_select' : function(ev) {
465             JSAN.use('util.functional');
466             g.bill_list_selection = util.functional.map_list(
467                 g.bill_list.retrieve_selection(),
468                 function(o) { return o.getAttribute('retrieve_id'); }
469             );
470             //tally_selected();
471             $('details').setAttribute('disabled', g.bill_list_selection.length == 0);
472             $('add').setAttribute('disabled', g.bill_list_selection.length == 0);
473             $('voidall').setAttribute('disabled', g.bill_list_selection.length == 0);
474             $('refund').setAttribute('disabled', g.bill_list_selection.length == 0);
475             $('opac').setAttribute('disabled', g.bill_list_selection.length == 0);
476             $('copy_details').setAttribute('disabled', g.bill_list_selection.length == 0);
477         },
478         'on_click' : function(ev) {
479             netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserRead');
480             var row = {}; var col = {}; var nobj = {};
481             g.bill_list.node.treeBoxObject.getCellAt(ev.clientX,ev.clientY,row,col,nobj);
482             if (row.value == -1) return;
483             var treeItem = g.bill_list.node.contentView.getItemAtIndex(row.value);
484             if (treeItem.nodeName != 'treeitem') return;
485             var treeRow = treeItem.firstChild;
486             var treeCell = treeRow.firstChild;
487             if (g.check_map[ treeItem.getAttribute('retrieve_id') ] != (treeCell.getAttribute('value') == 'true')) {
488                 g.check_map[ treeItem.getAttribute('retrieve_id') ] = treeCell.getAttribute('value') == 'true';
489                 g.row_map[ treeItem.getAttribute('retrieve_id') ].row.my.checked = treeCell.getAttribute('value') == 'true';
490                 tally_all();
491                 distribute_payment();
492             }
493         },
494         'on_sort' : function() {
495             tally_all();
496         },
497         'on_checkbox_toggle' : function(toggle) {
498             try {
499                 var retrieve_ids = g.bill_list.dump_retrieve_ids();
500                 for (var i = 0; i < retrieve_ids.length; i++) {
501                     g.check_map[ retrieve_ids[i] ] = (toggle=='on');
502                     g.row_map[ retrieve_ids[i] ].row.my.checked = (toggle=='on');
503                 }
504                 tally_all();
505             } catch(E) {
506                 alert('error in on_checkbox_toggle(): ' + E);
507             }
508         },
509         'retrieve_row' : function(params) {
510             try {
511                 var id = params.retrieve_id;
512                 var row = params.row;
513
514                 function handle_props(row) {
515                     try {
516                         if ( row && row.my && row.my.mbts && Number( row.my.mbts.balance_owed() ) < 0 ) {
517                             util.widgets.addProperty(params.row_node.firstChild,'refundable');
518                             util.widgets.addProperty(params.row_node.firstChild.childNodes[ g.payment_pending_column_idx ],'refundable');
519                         }
520                         if ( row && row.my && row.my.circ && ! row.my.circ.checkin_time() ) {
521                             $('circulating_hint').hidden = false;
522                             util.widgets.addProperty(params.row_node.firstChild,'circulating');
523                             util.widgets.addProperty(params.row_node.firstChild.childNodes[ g.title_column_idx ],'circulating');
524                         }
525                     } catch(E) {
526                         g.error.sdump('D_WARN','Error setting list properties in bill2.js: ' + E);
527                         alert('Error setting list properties in bill2.js: ' + E);
528                     }
529                 }
530
531                 if (id) {
532                     if (typeof row.my == 'undefined') row.my = {};
533                     if (typeof row.my.mbts == 'undefined' ) {
534                         g.network.simple_request('BLOB_MBTS_DETAILS_RETRIEVE',[ses(),id], function(req) {
535                             var blob = req.getResultObject();
536                             row.my.mbts = blob.transaction;
537                             row.my.circ = blob.circ;
538                             row.my.acp = blob.copy;
539                             row.my.mvr = blob.record;
540                             if (typeof params.on_retrieve == 'function') {
541                                 if ( row.my.mbts && Number( row.my.mbts.balance_owed() ) < 0 ) {
542                                     row.my.checked = false;
543                                 }
544                                 handle_props(row);
545                                 params.on_retrieve(row);
546                             };
547                             g.bill_map[ id ] = blob;
548                             g.check_map[ id ] = row.my.checked;
549                             tally_all();
550                         } );
551                     } else {
552                         if (typeof params.on_retrieve == 'function') { 
553                             handle_props(row);
554                             params.on_retrieve(row); 
555                         }
556                     }
557                 } else {
558                     if (typeof params.on_retrieve == 'function') { 
559                         params.on_retrieve(row); 
560                     }
561                 }
562
563                 return row;
564             } catch(E) {
565                 alert('Error in bill2.js, retrieve_row(): ' + E);
566             }
567         }
568     } );
569
570     g.title_column_idx = util.functional.map_list( g.bill_list.columns, function(o) { return o.id; } ).indexOf( 'title' );
571     g.payment_pending_column_idx = util.functional.map_list( g.bill_list.columns, function(o) { return o.id; } ).indexOf( 'payment_pending' );
572     $('bill_list_actions').appendChild( g.bill_list.render_list_actions() );
573     g.bill_list.set_list_actions();
574 }
575
576 function handle_add() {
577     if(g.bill_list_selection.length > 1) {
578         var msg = $("patronStrings").getFormattedString('staff.patron.bill_history.handle_add.message_plural', [g.bill_list_selection]);
579     } else {
580         var msg = $("patronStrings").getFormattedString('staff.patron.bill_history.handle_add.message_singular', [g.bill_list_selection]);
581     }
582         
583     var r = g.error.yns_alert(msg,
584         $("patronStrings").getString('staff.patron.bill_history.handle_add.title'),
585         $("patronStrings").getString('staff.patron.bill_history.handle_add.btn_yes'),
586         $("patronStrings").getString('staff.patron.bill_history.handle_add.btn_no'),null,
587         $("patronStrings").getString('staff.patron.bill_history.handle_add.confirm_message'));
588     if (r == 0) {
589         JSAN.use('util.window');
590         var win = new util.window();
591         for (var i = 0; i < g.bill_list_selection.length; i++) {
592             var w = win.open(
593                 urls.XUL_PATRON_BILL_WIZARD,
594                 'billwizard',
595                 'chrome,resizable,modal',
596                 { 'patron_id' : g.patron_id, 'xact_id' : g.bill_list_selection[i] }
597             );
598         }
599         refresh();
600         if (typeof window.xulG == 'object' && typeof window.xulG.refresh == 'function') window.xulG.refresh();
601     }
602 }
603
604 function handle_void_all() {
605     if(g.bill_list_selection.length > 1) {
606         var msg = $("patronStrings").getFormattedString('staff.patron.bill_history.handle_void.message_plural', [g.bill_list_selection]);
607     } else {
608         var msg = $("patronStrings").getFormattedString('staff.patron.bill_history.handle_void.message_singular', [g.bill_list_selection]);
609     }
610         
611     var r = g.error.yns_alert(msg,
612         $("patronStrings").getString('staff.patron.bill_history.handle_void.title'),
613         $("patronStrings").getString('staff.patron.bill_history.handle_void.btn_yes'),
614         $("patronStrings").getString('staff.patron.bill_history.handle_void.btn_no'),null,
615         $("patronStrings").getString('staff.patron.bill_history.handle_void.confirm_message'));
616     if (r == 0) {
617         for (var i = 0; i < g.bill_list_selection.length; i++) {
618             void_all_billings( g.bill_list_selection[i] );
619         }
620         refresh();
621         if (typeof window.xulG == 'object' && typeof window.xulG.refresh == 'function') window.xulG.refresh();
622         if (typeof window.xulG == 'object' && typeof window.xulG.on_money_change == 'function') window.xulG.on_money_change();
623     }
624 }
625
626 function handle_opac() {
627     try {
628         var ids = [];
629         for (var i = 0; i < g.bill_list_selection.length; i++) {
630             var my_mvr = g.bill_map[ g.bill_list_selection[i] ].record;
631             var my_acp = g.bill_map[ g.bill_list_selection[i] ].copy;
632             if (typeof my_mvr != 'undefined' && my_mvr != null) {
633                 ids.push( { 'barcode' : my_acp.barcode(), 'doc_id' : my_mvr.doc_id() } );
634             }
635         }
636         JSAN.use('cat.util');
637         cat.util.show_in_opac( ids );
638     } catch(E) {
639         alert('Error in bill2.js, handle_opac: ' + E);
640     }
641 }
642
643 function handle_copy_details() {
644     try {
645         var ids = [];
646         for (var i = 0; i < g.bill_list_selection.length; i++) {
647             var my_acp = g.bill_map[ g.bill_list_selection[i] ].copy;
648             if (typeof my_acp != 'undefined' && my_acp != null) {
649                 ids.push( my_acp.barcode() );
650             }
651         }
652         JSAN.use('circ.util');
653         circ.util.item_details_new( ids );
654     } catch(E) {
655         alert('Error in bill2.js, handle_opac: ' + E);
656     }
657 }
658
659 function handle_details() {
660     JSAN.use('util.window'); var win = new util.window();
661     for (var i = 0; i < g.bill_list_selection.length; i++) {
662         var my_xulG = win.open(
663             urls.XUL_PATRON_BILL_DETAILS,
664             'test_billdetails_' + g.bill_list_selection[i],
665             'chrome,resizable',
666             {
667                 'patron_id' : g.patron_id,
668                 'mbts_id' : g.bill_list_selection[i],
669                 'refresh' : function() {
670                     refresh(); 
671                     if (typeof window.xulG == 'object' && typeof window.xulG.refresh == 'function') window.xulG.refresh();
672                 }, 
673                 'new_tab' : xulG.new_tab,
674                 'url_prefix' : xulG.url_prefix
675             }
676         );
677     }
678 }
679
680 function print_bills() {
681     try {
682         var template = 'bills_historical'; if (xul_param('current')) template = 'bills_current';
683         JSAN.use('patron.util');
684         g.patron = patron.util.retrieve_fleshed_au_via_id(ses(),g.patron_id,null); 
685         var params = { 
686             'patron' : g.patron,
687             'printer_context' : 'receipt',
688             'template' : template
689         };
690         g.bill_list.print(params);
691     } catch(E) {
692         g.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.bill_history.print_bills.print_error'), E);
693     }
694 }
695
696 function distribute_payment() {
697     try {
698         JSAN.use('util.money');
699         var tb = $('payment');
700         tb.value = util.money.cents_as_dollars( util.money.dollars_float_to_cents_integer( tb.value ) );
701         tb.setAttribute('value', tb.value );
702         var total = util.money.dollars_float_to_cents_integer( tb.value );
703         if (total < 0) { tb.value = '0.00'; tb.setAttribute('value','0.00'); total = 0; }
704         var retrieve_ids = g.bill_list.dump_retrieve_ids();
705         for (var i = 0; i < retrieve_ids.length; i++) {
706             var row_params = g.row_map[retrieve_ids[i]];
707             if (g.check_map[retrieve_ids[i]]) { 
708                 var bill = g.bill_map[retrieve_ids[i]].transaction;
709                 var bo = util.money.dollars_float_to_cents_integer( bill.balance_owed() );
710                 if ( bo > total ) {
711                     row_params.row.my.payment_pending = util.money.cents_as_dollars( total );
712                     total = 0;
713                 } else {
714                     row_params.row.my.payment_pending = util.money.cents_as_dollars( bo );
715                     total = total - bo;
716                 }
717             } else {
718                 row_params.row.my.payment_pending = '0.00';
719             }
720             g.bill_list.refresh_row(row_params);
721         }
722         tally_pending();
723     } catch(E) {
724         alert('Error in bill2.js, distribute_payment(): ' + E);
725     }
726 }
727
728 function apply_payment() {
729     try {
730         var payment_blob = {};
731         JSAN.use('util.window');
732         var win = new util.window();
733         switch($('payment_type').value) {
734             case 'credit_card_payment' :
735                 g.data.temp = '';
736                 g.data.stash('temp');
737                 var my_xulG = win.open(
738                     urls.XUL_PATRON_BILL_CC_INFO,
739                     'billccinfo',
740                     'chrome,resizable,modal',
741                     {'patron_id': g.patron_id}
742                 );
743                 g.data.stash_retrieve();
744                 payment_blob = JSON2js( g.data.temp ); // FIXME - replace with my_xulG and update_modal_xulG, though it looks like we were using that before and moved away from it
745             break;
746             case 'check_payment' :
747                 g.data.temp = '';
748                 g.data.stash('temp');
749                 var my_xulG = win.open(
750                     urls.XUL_PATRON_BILL_CHECK_INFO,
751                     'billcheckinfo',
752                     'chrome,resizable,modal'
753                 );
754                 g.data.stash_retrieve();
755                 payment_blob = JSON2js( g.data.temp );
756             break;
757         }
758         if (
759             (typeof payment_blob == 'undefined') || 
760             payment_blob=='' || 
761             payment_blob.cancelled=='true'
762         ) { 
763             alert( $('commonStrings').getString('common.cancelled') ); 
764             return; 
765         }
766         payment_blob.userid = g.patron_id;
767         payment_blob.note = payment_blob.note || '';
768         //payment_blob.cash_drawer = 1; // FIXME: get new Config() to work
769         payment_blob.payment_type = $('payment_type').value;
770         var tally_blob = tally_pending();
771         payment_blob.payments = tally_blob.payments;
772         // Handle patron credit
773         if ( payment_blob.payment_type == 'credit_payment' ) { // paying with patron credit
774             if ( $('convert_change_to_credit').checked ) {
775                 // No need to convert credit into credit, handled automatically
776                 payment_blob.patron_credit = '0.00';
777             } else {
778                 // Cashing out extra credit as change
779                 payment_blob.patron_credit = 0 - tally_blob.change;
780             }
781         } else if ( $('convert_change_to_credit').checked ) {
782             // Saving change from a non-credit payment as patron credit on server
783             payment_blob.patron_credit = tally_blob.change;
784         } else {
785             payment_blob.patron_credit = '0.00';
786         }
787         if ( payment_blob.payments.length == 0 && payment_blob.patron_credit == '0.00' ) {
788             alert($("patronStrings").getString('staff.patron.bills.apply_payment.nothing_applied'));
789             return;
790         }
791         if ( pay( payment_blob ) ) {
792
793             $('payment').value = ''; $('payment').select(); $('payment').focus();
794             refresh({'clear_voided_summary':true});
795             if (typeof window.xulG == 'object' && typeof window.xulG.refresh == 'function') window.xulG.refresh();
796             if (typeof window.xulG == 'object' && typeof window.xulG.on_money_change == 'function') window.xulG.on_money_change();
797             if ( $('payment_type').value == 'credit_payment' || $('convert_change_to_credit').checked ) {
798                 refresh_patron();
799             }
800             try {
801                 if ( ! $('receipt_upon_payment').hasAttribute('checked') ) { return; } // Skip print attempt
802                 if ( ! $('receipt_upon_payment').getAttribute('checked') ) { return; } // Skip print attempt
803                 var no_print_prompting = g.data.hash.aous['circ.staff_client.do_not_auto_attempt_print'];
804                 if (no_print_prompting) {
805                     if (no_print_prompting.indexOf( "Bill Pay" ) > -1) { return; } // Skip print attempt
806                 }
807                 netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
808                 g.data.stash_retrieve();
809                 var template = 'bill_payment';
810                 JSAN.use('patron.util'); JSAN.use('util.functional');
811                 var params = { 
812                     'patron' : g.patron,
813                     'lib' : g.data.hash.aou[ ses('ws_ou') ],
814                     'staff' : ses('staff'),
815                     'header' : g.data.print_list_templates[template].header,
816                     'line_item' : g.data.print_list_templates[template].line_item,
817                     'footer' : g.data.print_list_templates[template].footer,
818                     'type' : g.data.print_list_templates[template].type,
819                     'list' : util.functional.map_list(
820                         payment_blob.payments,
821                         function(o) {
822                             return {
823                                 'bill_id' : o[0],
824                                 'payment' : o[1],
825                                 'last_billing_type' : g.bill_map[ o[0] ].transaction.last_billing_type(),
826                                 'last_billing_note' : g.bill_map[ o[0] ].transaction.last_billing_note(),
827                                 'title' : typeof g.bill_map[ o[0] ].record != 'undefined' ? g.bill_map[ o[0] ].record.title() : '', 
828                                 'barcode' : typeof g.bill_map[ o[0] ].copy != 'undefined' ? g.bill_map[ o[0] ].copy.barcode() : ''
829                             };
830                         }
831                     ),
832                     'data' : g.previous_summary
833                 };
834                 g.error.sdump('D_DEBUG',js2JSON(params));
835                 if ($('printer_prompt').hasAttribute('checked')) {
836                     if ($('printer_prompt').getAttribute('checked')) {
837                             params.no_prompt = false;
838                     } else {
839                             params.no_prompt = true;
840                     }
841                 } else {
842                     params.no_prompt = true;
843                 }
844                 JSAN.use('util.print'); var print = new util.print('receipt');
845                 for (var i = 0; i < $('num_of_receipts').value; i++) {
846                     print.tree_list( params );
847                 }
848             } catch(E) {
849                 g.error.standard_unexpected_error_alert('bill receipt', E);
850             }
851         }
852     } catch(E) {
853         alert('Error in bill2.js, apply_payment(): ' + E);
854     }
855 }
856
857 function pay(payment_blob) {
858     try {
859         var x = $('annotate_payment');
860         if (x && x.checked && (! payment_blob.note)) {
861             payment_blob.note = window.prompt(
862                 $("patronStrings").getString('staff.patron.bills.pay.annotate_payment'),
863                 '', 
864                 $("patronStrings").getString('staff.patron.bills.pay.annotate_payment.title')
865             );
866         }
867         g.previous_summary = {
868             original_balance : $('tb_total_owed').value,
869             voided_balance : $('currently_voided').value,
870             payment_received : $('payment').value,
871             payment_applied : $('pending_payment').value,
872             change_given : $('convert_change_to_credit').checked ? 0 : $('pending_change').value,
873             credit_given : $('convert_change_to_credit').checked ? $('pending_change').value : 0,
874             new_balance : util.money.cents_as_dollars( 
875                 util.money.dollars_float_to_cents_integer( $('tb_total_owed').value ) - 
876                 util.money.dollars_float_to_cents_integer( $('pending_payment').value )
877             ),
878             payment_type : $('payment_type').getAttribute('label'),
879             note : payment_blob.note
880         }
881         var robj = g.network.simple_request( 'BILL_PAY', [ ses(), payment_blob, g.patron.last_xact_id() ]);
882         if (typeof robj.ilsevent != 'undefined') {
883             switch(robj.textcode) {
884                 case 'SUCCESS' : return true; break;
885                 case 'REFUND_EXCEEDS_DESK_PAYMENTS' : alert($("patronStrings").getFormattedString('staff.patron.bills.pay.refund_exceeds_desk_payment', [robj.desc])); return false; break;
886                 case 'INVALID_USER_XACT_ID' :
887                     refresh(); default_focus();
888                     alert($("patronStrings").getFormattedString('staff.patron.bills.pay.invalid_user_xact_id', [robj.desc])); return false; break;
889                 default: throw(robj); break;
890             }
891         }
892         return true;
893     } catch(E) {
894         g.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.bills.pay.payment_failed'),E);
895         return false;
896     }
897 }
898
899 function refresh(params) {
900     try {
901         if (params && params.clear_voided_summary) {
902             g.data.voided_billings = []; g.data.stash('voided_billings');
903         }
904         refresh_patron();
905         g.bill_list.clear();
906         retrieve_mbts_for_list();
907         tally_voided();
908         distribute_payment(); 
909     } catch(E) {
910         alert('Error in bill2.js, refresh(): ' + E);
911     }
912 }
913
914 function void_all_billings(mobts_id) {
915     try {
916         JSAN.use('util.functional');
917         
918         var mb_list = g.network.simple_request( 'FM_MB_RETRIEVE_VIA_MBTS_ID.authoritative', [ ses(), mobts_id ] );
919         if (typeof mb_list.ilsevent != 'undefined') throw(mb_list);
920
921         mb_list = util.functional.filter_list( mb_list, function(o) { return ! get_bool( o.voided() ) });
922
923         if (mb_list.length == 0) { alert($("patronStrings").getString('staff.patron.bills.void_all_billings.all_voided')); return; }
924
925         var sum = 0;
926         for (var i = 0; i < mb_list.length; i++) sum += util.money.dollars_float_to_cents_integer( mb_list[i].amount() );
927         sum = util.money.cents_as_dollars( sum );
928
929         var msg = $("patronStrings").getFormattedString('staff.patron.bills.void_all_billings.void.message', [sum]);
930         var r = g.error.yns_alert(msg,
931             $("patronStrings").getString('staff.patron.bills.void_all_billings.void.title'),
932             $("patronStrings").getString('staff.patron.bills.void_all_billings.void.yes'),
933             $("patronStrings").getString('staff.patron.bills.void_all_billings.void.no'), null,
934             $("patronStrings").getString('staff.patron.bills.void_all_billings.void.confirm_message'));
935         if (r == 0) {
936             var robj = g.network.simple_request('FM_MB_VOID',[ses()].concat(util.functional.map_list(mb_list,function(o){return o.id();})));
937             if (robj.ilsevent) {
938                 switch(Number(robj.ilsevent)) {
939                     case 5000 /* PERM_FAILURE */:
940                         return;
941                     break;
942                     default: 
943                         g.error.standard_unexpected_error_alert($("patronStrings").getString('staff.patron.bills.void_all_billings.error_voiding_bills'),robj); 
944                         return; 
945                     break;
946                 }
947             }
948
949             g.data.stash_retrieve(); if (! g.data.voided_billings ) g.data.voided_billings = []; 
950             for (var i = 0; i < mb_list.length; i++) {
951                     g.data.voided_billings.push( mb_list[i] );
952             }
953             g.data.stash('voided_billings');
954         }
955     } catch(E) {
956         try { g.error.standard_unexpected_error_alert('bill2.js, void_all_billings():',E); } catch(F) { alert(E); }
957     }
958 }
959
960 function refresh_patron() {
961     JSAN.use('patron.util'); JSAN.use('util.money');
962     patron.util.retrieve_fleshed_au_via_id(ses(),g.patron_id,null,function(req) {
963         var au_obj = req.getResultObject();
964         if (typeof au_obj.ilsevent == 'undefined') {
965             g.patron = au_obj;
966             $('credit_forward').setAttribute('value',util.money.sanitize( g.patron.credit_forward_balance() ));
967         }
968     });
969 }