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