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