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