6849c346c43244cff7866079b784b12eb2772725
[working/Evergreen.git] / Open-ILS / xul / staff_client / server / patron / util.js
1 dump('entering patron/util.js\n');
2
3 if (typeof patron == 'undefined') var patron = {};
4 patron.util = {};
5
6 patron.util.EXPORT_OK    = [ 
7     'columns', 'mbts_columns', 'mb_columns', 'mp_columns',
8     'retrieve_au_via_id', 'retrieve_fleshed_au_via_id', 'retrieve_fleshed_au_via_barcode', 'set_penalty_css', 'retrieve_name_via_id',
9     'merge', 'ausp_columns', 'format_name', 'work_log_patron_edit'
10 ];
11 patron.util.EXPORT_TAGS    = { ':all' : patron.util.EXPORT_OK };
12
13 patron.util.mbts_columns = function(modify,params) {
14
15     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
16     JSAN.use('util.money'); JSAN.use('util.date');
17
18     var commonStrings = document.getElementById('commonStrings');
19
20     var c = [
21         {
22             'persist' : 'hidden width ordinal', 'id' : 'mbts_id', 'label' : commonStrings.getString('staff.mbts_id_label'), 'flex' : 1,
23             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mbts.id(); }
24         },
25         {
26             'persist' : 'hidden width ordinal', 'id' : 'usr', 'label' : commonStrings.getString('staff.mbts_usr_label'), 'flex' : 1,
27             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mbts.usr() ? "Id = " + my.mbts.usr() : ""; }
28         },
29         {
30             'persist' : 'hidden width ordinal', 'id' : 'xact_type', 'label' : commonStrings.getString('staff.mbts_xact_type_label'), 'flex' : 1,
31             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mbts.xact_type(); }
32         },
33         {
34             'persist' : 'hidden width ordinal', 'id' : 'balance_owed', 'label' : commonStrings.getString('staff.mbts_balance_owed_label'), 'flex' : 1,
35             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return util.money.sanitize( my.mbts.balance_owed() ); },
36             'sort_type' : 'money'
37         },
38         {
39             'persist' : 'hidden width ordinal', 'id' : 'total_owed', 'label' : commonStrings.getString('staff.mbts_total_owed_label'), 'flex' : 1,
40             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return util.money.sanitize( my.mbts.total_owed() ); },
41             'sort_type' : 'money'
42         },
43         {
44             'persist' : 'hidden width ordinal', 'id' : 'total_paid', 'label' : commonStrings.getString('staff.mbts_total_paid_label'), 'flex' : 1,
45             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return util.money.sanitize( my.mbts.total_paid() ); },
46             'sort_type' : 'money'
47         },
48         {
49             'persist' : 'hidden width ordinal', 'id' : 'last_billing_note', 'label' : commonStrings.getString('staff.mbts_last_billing_note_label'), 'flex' : 2,
50             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mbts.last_billing_note(); }
51         },
52         {
53             'persist' : 'hidden width ordinal', 'id' : 'last_billing_type', 'label' : commonStrings.getString('staff.mbts_last_billing_type_label'), 'flex' : 1,
54             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mbts.last_billing_type(); }
55         },
56         {
57             'persist' : 'hidden width ordinal', 'id' : 'last_billing_ts', 'label' : commonStrings.getString('staff.mbts_last_billing_timestamp_label'), 'flex' : 1,
58             'sort_type' : 'date',
59             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.mbts.last_billing_ts(), "%{localized}" ); }
60             ,'sort_value' : function(my) {
61                 return util.date.db_date2Date(
62                     my.mbts
63                     ? my.mbts.last_billing_ts()
64                     : null
65                 ).getTime();
66             }
67         },
68         {
69             'persist' : 'hidden width ordinal', 'id' : 'last_payment_note', 'label' : commonStrings.getString('staff.mbts_last_payment_note_label'), 'flex' : 2,
70             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mbts.last_payment_note(); }
71         },
72         {
73             'persist' : 'hidden width ordinal', 'id' : 'last_payment_type', 'label' : commonStrings.getString('staff.mbts_last_payment_type_label'), 'flex' : 1,
74             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mbts.last_payment_type(); }
75         },
76         {
77             'persist' : 'hidden width ordinal', 'id' : 'last_payment_ts', 'label' : commonStrings.getString('staff.mbts_last_payment_timestamp_label'), 'flex' : 1,
78             'sort_type' : 'date',
79             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.mbts.last_payment_ts(), "%{localized}" ); }
80             ,'sort_value' : function(my) { return util.date.db_date2Date(
81                     my.mbts
82                     ? my.mbts.last_payment_ts()
83                     : null
84                 ).getTime();
85             }
86         },
87         {
88             'persist' : 'hidden width ordinal', 'id' : 'mbts_xact_start', 'label' : commonStrings.getString('staff.mbts_xact_start_label'), 'flex' : 1,
89             'sort_type' : 'date',
90             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mbts.xact_start() ? util.date.formatted_date( my.mbts.xact_start(), "%{localized}" ) : ""; }
91             ,'sort_value' : function(my) { return util.date.db_date2Date(
92                     my.mbts
93                     ? my.mbts.xact_start()
94                     : null
95                 ).getTime();
96             }
97         },
98         {
99             'persist' : 'hidden width ordinal', 'id' : 'mbts_xact_finish', 'label' : commonStrings.getString('staff.mbts_xact_finish_label'), 'flex' : 1,
100             'sort_type' : 'date',
101             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mbts.xact_finish() ? util.date.formatted_date( my.mbts.xact_finish(), "%{localized}" ) : ""; }
102             ,'sort_value' : function(my) { return util.date.db_date2Date(
103                     my.mbts
104                     ? my.mbts.xact_finish()
105                     : null
106                 ).getTime();
107             }
108         },
109     ];
110     for (var i = 0; i < c.length; i++) {
111         if (modify[ c[i].id ]) {
112             for (var j in modify[ c[i].id ]) {
113                 c[i][j] = modify[ c[i].id ][j];
114             }
115         }
116     }
117     if (params) {
118         if (params.just_these) {
119             JSAN.use('util.functional');
120             var new_c = [];
121             for (var i = 0; i < params.just_these.length; i++) {
122                 var x = util.functional.find_list(c,function(d){return(d.id==params.just_these[i]);});
123                 new_c.push( function(y){ return y; }( x ) );
124             }
125             c = new_c;
126         }
127         if (params.except_these) {
128             JSAN.use('util.functional');
129             var new_c = [];
130             for (var i = 0; i < c.length; i++) {
131                 var x = util.functional.find_list(params.except_these,function(d){return(d==c[i].id);});
132                 if (!x) new_c.push(c[i]);
133             }
134             c = new_c;
135         }
136     }
137     return c.sort( function(a,b) { if (a.label < b.label) return -1; if (a.label > b.label) return 1; return 0; } );
138 }
139
140 patron.util.mb_columns = function(modify,params) {
141
142     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
143     JSAN.use('util.money'); JSAN.use('util.date');
144
145     var commonStrings = document.getElementById('commonStrings');
146
147     var c = [
148         {
149             'persist' : 'hidden width ordinal', 'id' : 'mb_id', 'label' : commonStrings.getString('staff.mb_id_label'), 'flex' : 1,
150             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mb.id(); }
151         },
152         {
153             'persist' : 'hidden width ordinal', 'id' : 'voided', 'label' : commonStrings.getString('staff.mb_voided_label'), 'flex' : 1,
154             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return get_bool( my.mb.voided() ) ? "Yes" : "No"; }
155         },
156         {
157             'persist' : 'hidden width ordinal', 'id' : 'voider', 'label' : commonStrings.getString('staff.mb_voider_label'), 'flex' : 1,
158             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mb.voider() ? "Id = " + my.mb.voider() : ""; }
159         },
160         {
161             'persist' : 'hidden width ordinal', 'id' : 'void_time', 'label' : commonStrings.getString('staff.mb_void_time_label'), 'flex' : 1,
162             'sort_type' : 'date',
163             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.mb.void_time(), "%{localized}" ); }
164             ,'sort_value' : function(my) { return util.date.db_date2Date(
165                     my.mbts
166                     ? my.mb.void_time()
167                     : null
168                 ).getTime();
169             }
170         },
171         {
172             'persist' : 'hidden width ordinal', 'id' : 'amount', 'label' : commonStrings.getString('staff.mb_amount_label'), 'flex' : 1,
173             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return util.money.sanitize( my.mb.amount() ); },
174             'sort_type' : 'money'
175         },
176         {
177             'persist' : 'hidden width ordinal', 'id' : 'billing_type', 'label' : commonStrings.getString('staff.mb_billing_type_label'), 'flex' : 1,
178             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mb.billing_type(); }
179         },
180         {
181             'persist' : 'hidden width ordinal', 'id' : 'billing_ts', 'label' : commonStrings.getString('staff.mb_billing_ts_label'), 'flex' : 1,
182             'sort_type' : 'date',
183             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.mb.billing_ts(), "%{localized}" ); }
184             ,'sort_value' : function(my) { return util.date.db_date2Date(
185                     my.mb
186                     ? my.mb.billing_ts()
187                     : null
188                 ).getTime();
189             }
190         },
191         {
192             'persist' : 'hidden width ordinal', 'id' : 'note', 'label' : commonStrings.getString('staff.mb_note_label'), 'flex' : 2,
193             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mb.note(); }
194         },
195         {
196             'persist' : 'hidden width ordinal', 'id' : 'xact', 'label' : commonStrings.getString('staff.mb_xact_label'), 'flex' : 1,
197             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mb.xact(); }
198         },
199     ];
200     for (var i = 0; i < c.length; i++) {
201         if (modify[ c[i].id ]) {
202             for (var j in modify[ c[i].id ]) {
203                 c[i][j] = modify[ c[i].id ][j];
204             }
205         }
206     }
207     if (params) {
208         if (params.just_these) {
209             JSAN.use('util.functional');
210             var new_c = [];
211             for (var i = 0; i < params.just_these.length; i++) {
212                 var x = util.functional.find_list(c,function(d){return(d.id==params.just_these[i]);});
213                 new_c.push( function(y){ return y; }( x ) );
214             }
215             c = new_c;
216         }
217         if (params.except_these) {
218             JSAN.use('util.functional');
219             var new_c = [];
220             for (var i = 0; i < c.length; i++) {
221                 var x = util.functional.find_list(params.except_these,function(d){return(d==c[i].id);});
222                 if (!x) new_c.push(c[i]);
223             }
224             c = new_c;
225         }
226
227     }
228     return c.sort( function(a,b) { if (a.label < b.label) return -1; if (a.label > b.label) return 1; return 0; } );
229 }
230
231 patron.util.mp_columns = function(modify,params) {
232
233     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
234     JSAN.use('util.money'); JSAN.use('util.date'); JSAN.use('patron.util');
235
236     var commonStrings = document.getElementById('commonStrings');
237
238     var c = [
239         {
240             'persist' : 'hidden width ordinal', 'id' : 'mp_id', 'label' : commonStrings.getString('staff.mp_id_label'), 'flex' : 1,
241             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mp.id(); }
242         },
243         {
244             'persist' : 'hidden width ordinal', 'id' : 'mp_amount', 'label' : commonStrings.getString('staff.mp_amount_label'), 'flex' : 1,
245             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return util.money.sanitize( my.mp.amount() ); },
246             'sort_type' : 'money'
247         },
248         {
249             'persist' : 'hidden width ordinal', 'id' : 'mp_payment_type', 'label' : commonStrings.getString('staff.mp_payment_type_label'), 'flex' : 1,
250             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mp.payment_type(); }
251         },
252         {
253             'persist' : 'hidden width ordinal', 'id' : 'mp_payment_ts', 'label' : commonStrings.getString('staff.mp_payment_timestamp_label'), 'flex' : 1,
254             'sort_type' : 'date',
255             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.mp.payment_ts(), "%{localized}" ); }
256             ,'sort_value' : function(my) { return util.date.db_date2Date(
257                     my.mp
258                     ? my.mp.payment_ts()
259                     : null
260                 ).getTime();
261             }
262         },
263         {
264             'persist' : 'hidden width ordinal', 'id' : 'mp_note', 'label' : commonStrings.getString('staff.mp_note_label'), 'flex' : 2,
265             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mp.note(); }
266         },
267         {
268             'persist' : 'hidden width ordinal', 'id' : 'mp_ws', 'label' : commonStrings.getString('staff.mp_cash_drawer_label'), 'flex' : 1,
269             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return my.mp.cash_drawer().name(); }
270         },
271         {
272             'persist' : 'hidden width ordinal', 'id' : 'mp_staff', 'label' : commonStrings.getString('staff.mp_accepting_usr_label'), 'flex' : 1,
273             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { var s = my.mp.accepting_usr(); if (s && typeof s != "object") s = patron.util.retrieve_fleshed_au_via_id(ses(),s,["card"]); return s.family_name() + " (" + s.card().barcode() + ") @ " + data.hash.aou[ s.home_ou() ].shortname(); }
274         },
275         {
276             'persist' : 'hidden width ordinal', 'id' : 'mp_xact', 'label' : commonStrings.getString('staff.mp_xact_label'), 'flex' : 1,
277             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.mp.xact(); }
278         },
279     ];
280     for (var i = 0; i < c.length; i++) {
281         if (modify[ c[i].id ]) {
282             for (var j in modify[ c[i].id ]) {
283                 c[i][j] = modify[ c[i].id ][j];
284             }
285         }
286     }
287     if (params) {
288         if (params.just_these) {
289             JSAN.use('util.functional');
290             var new_c = [];
291             for (var i = 0; i < params.just_these.length; i++) {
292                 var x = util.functional.find_list(c,function(d){return(d.id==params.just_these[i]);});
293                 new_c.push( function(y){ return y; }( x ) );
294             }
295             c = new_c;
296         }
297         if (params.except_these) {
298             JSAN.use('util.functional');
299             var new_c = [];
300             for (var i = 0; i < c.length; i++) {
301                 var x = util.functional.find_list(params.except_these,function(d){return(d==c[i].id);});
302                 if (!x) new_c.push(c[i]);
303             }
304             c = new_c;
305         }
306
307     }
308     return c.sort( function(a,b) { if (a.label < b.label) return -1; if (a.label > b.label) return 1; return 0; } );
309 }
310
311 patron.util.ausp_columns = function(modify,params) {
312
313     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
314     JSAN.use('util.functional');
315
316     var commonStrings = document.getElementById('commonStrings');
317
318     var c = [
319         {
320             'persist' : 'hidden width ordinal', 'id' : 'csp_id', 'label' : commonStrings.getString('staff.csp_id_label'), 'flex' : 1,
321             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return typeof my.csp == 'object' ? my.csp.id() : my.csp; }
322         },
323         {
324             'persist' : 'hidden width ordinal', 'id' : 'csp_name', 'label' : commonStrings.getString('staff.csp_name_label'), 'flex' : 1,
325             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return typeof my.csp == 'object' ? my.csp.name() : data.hash.csp[ my.csp ].name(); }
326         },
327         {
328             'persist' : 'hidden width ordinal', 'id' : 'csp_label', 'label' : commonStrings.getString('staff.csp_label_label'), 'flex' : 1,
329             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { return typeof my.csp == 'object' ? my.csp.label() : data.hash.csp[ my.csp ].label(); }
330         },
331         {
332             'persist' : 'hidden width ordinal', 'id' : 'csp_block_list', 'label' : commonStrings.getString('staff.csp_block_list_label'), 'flex' : 1,
333             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return typeof my.csp == 'object' ? my.csp.block_list() : data.hash.csp[ my.csp ].block_list(); }
334         },
335         {
336             'persist' : 'hidden width ordinal', 'id' : 'csp_block_circ', 'label' : commonStrings.getString('staff.csp_block_circ_label'), 'flex' : 1,
337             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { 
338                 var my_csp = typeof my.csp == 'object' ? my.csp : data.hash.csp[ my.csp ];
339                 return String( my_csp.block_list() ).match('CIRC') ? commonStrings.getString('staff.csp_block_circ_yes') : commonStrings.getString('staff.csp_block_circ_no'); 
340             }
341         },
342         {
343             'persist' : 'hidden width ordinal', 'id' : 'csp_block_renew', 'label' : commonStrings.getString('staff.csp_block_renew_label'), 'flex' : 1,
344             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { 
345                 var my_csp = typeof my.csp == 'object' ? my.csp : data.hash.csp[ my.csp ];
346                 return String( my_csp.block_list() ).match('RENEW') ? commonStrings.getString('staff.csp_block_renew_yes') : commonStrings.getString('staff.csp_block_renew_no'); 
347
348             }
349         },
350         {
351             'persist' : 'hidden width ordinal', 'id' : 'csp_block_hold', 'label' : commonStrings.getString('staff.csp_block_hold_label'), 'flex' : 1,
352             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { 
353                 var my_csp = typeof my.csp == 'object' ? my.csp : data.hash.csp[ my.csp ];
354                 return String( my_csp.block_list() ).match('HOLD') ?  commonStrings.getString('staff.csp_block_hold_yes') : commonStrings.getString('staff.csp_block_hold_no'); 
355             }
356         },
357         {
358             'persist' : 'hidden width ordinal', 'id' : 'ausp_id', 'label' : commonStrings.getString('staff.ausp_id_label'), 'flex' : 1,
359             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.ausp ? my.ausp.id() : ''; }
360         },
361         {
362             'persist' : 'hidden width ordinal', 'id' : 'ausp_staff', 'label' : commonStrings.getString('staff.ausp_staff_label'), 'flex' : 1,
363             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { 
364                 return my.ausp ? my.ausp.staff() : '';
365             }
366         },
367         {
368             'persist' : 'hidden width ordinal', 'id' : 'ausp_set_date', 'label' : commonStrings.getString('staff.ausp_set_date_label'), 'flex' : 1,
369             'sort_type' : 'date',
370             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { 
371                 return my.ausp ? util.date.formatted_date( my.ausp.set_date(), "%{localized}" ) : '';
372             }
373             ,'sort_value' : function(my) { return util.date.db_date2Date(
374                     my.ausp
375                     ? my.ausp.set_date()
376                     : null
377                 ).getTime();
378             }
379         },
380         {
381             'persist' : 'hidden width ordinal', 'id' : 'ausp_note', 'label' : commonStrings.getString('staff.ausp_note_label'), 'flex' : 1,
382             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { 
383                 return my.ausp ? my.ausp.note() : '';
384             }
385         },
386         {
387             'persist' : 'hidden width ordinal', 'id' : 'ausp_org_unit', 'label' : commonStrings.getString('staff.ausp_org_unit_label'), 'flex' : 1,
388             'primary' : false, 'hidden' : false, 'editable' : false, 'render' : function(my) { 
389                 return my.ausp ? data.hash.aou[ my.ausp.org_unit() ].shortname() : '';
390             }
391         },
392         {
393             'persist' : 'hidden width ordinal', 'id' : 'ausp_org_unit_full', 'label' : commonStrings.getString('staff.ausp_org_unit_full_label'), 'flex' : 1,
394             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { 
395                 return my.ausp ? data.hash.aou[ my.ausp.org_unit() ].name() : '';
396             }
397         }
398
399     ];
400     for (var i = 0; i < c.length; i++) {
401         if (modify[ c[i].id ]) {
402             for (var j in modify[ c[i].id ]) {
403                 c[i][j] = modify[ c[i].id ][j];
404             }
405         }
406     }
407     if (params) {
408         if (params.just_these) {
409             var new_c = [];
410             for (var i = 0; i < params.just_these.length; i++) {
411                 var x = util.functional.find_list(c,function(d){return(d.id==params.just_these[i]);});
412                 new_c.push( function(y){ return y; }( x ) );
413             }
414             c = new_c;
415         }
416         if (params.except_these) {
417             var new_c = [];
418             for (var i = 0; i < c.length; i++) {
419                 var x = util.functional.find_list(params.except_these,function(d){return(d==c[i].id);});
420                 if (!x) new_c.push(c[i]);
421             }
422             c = new_c;
423         }
424
425     }
426     return c.sort( function(a,b) { if (a.label < b.label) return -1; if (a.label > b.label) return 1; return 0; } );
427 }
428
429
430 patron.util.columns = function(modify,params) {
431     
432     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
433
434     var commonStrings = document.getElementById('commonStrings');
435
436     var c = [
437         {
438             'persist' : 'hidden width ordinal', 'id' : 'au_barcode', 'label' : commonStrings.getString('staff.card_barcode_label'), 'flex' : 1, 
439             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.card().barcode(); }
440         },
441         { 
442             'persist' : 'hidden width ordinal', 'id' : 'usrname', 'label' : commonStrings.getString('staff.au_usrname_label'), 'flex' : 1, 
443             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.usrname(); }
444         },
445         { 
446             'persist' : 'hidden width ordinal', 'id' : 'profile', 'label' : commonStrings.getString('staff.au_profile_label'), 'flex' : 1, 
447             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return data.hash.pgt[ my.au.profile() ].name(); }
448         },
449         { 
450             'persist' : 'hidden width ordinal', 'id' : 'active', 'label' : commonStrings.getString('staff.au_active_label'), 'flex' : 1, 
451             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return get_bool( my.au.active() ) ? "Yes" : "No"; }
452         },
453         {
454             'persist' : 'hidden width ordinal', 'id' : 'barred', 'label' : commonStrings.getString('staff.au_barred_label'), 'flex' : 1,
455             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return get_bool( my.au.barred() ) ? "Yes" : "No"; }
456         },
457         { 
458             'persist' : 'hidden width ordinal', 'id' : 'au_id', 'label' : document.getElementById('commonStrings').getString('staff.au_id_label'), 'flex' : 1, 
459             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.id(); }
460         },
461         { 
462             'persist' : 'hidden width ordinal', 'id' : 'prefix', 'label' : document.getElementById('commonStrings').getString('staff.au_name_prefix_label'), 'flex' : 1, 
463             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.prefix(); }
464         },
465         { 
466             'persist' : 'hidden width ordinal', 'id' : 'family_name', 'label' : document.getElementById('commonStrings').getString('staff.au_family_name_label'), 'flex' : 1, 
467             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.family_name(); }
468         },
469         { 
470             'persist' : 'hidden width ordinal', 'id' : 'first_given_name', 'label' : document.getElementById('commonStrings').getString('staff.au_first_given_name_label'), 'flex' : 1, 
471             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.first_given_name(); }
472         },
473         { 
474             'persist' : 'hidden width ordinal', 'id' : 'second_given_name', 'label' : document.getElementById('commonStrings').getString('staff.au_second_given_name_label'), 'flex' : 1, 
475             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.second_given_name(); }
476         },
477         { 
478             'persist' : 'hidden width ordinal', 'id' : 'suffix', 'label' : document.getElementById('commonStrings').getString('staff.au_name_suffix_label'), 'flex' : 1, 
479             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.suffix(); }
480         },
481         { 
482             'persist' : 'hidden width ordinal', 'id' : 'au_alert_message', 'label' : commonStrings.getString('staff.au_alert_message_label'), 'flex' : 1, 
483             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.alert_message(); }
484         },
485         { 
486             'persist' : 'hidden width ordinal', 'id' : 'claims_returned_count', 'label' : commonStrings.getString('staff.au_claims_returned_count_label'), 'flex' : 1, 
487             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.claims_returned_count(); },
488             'sort_type' : 'number'
489         },
490         { 
491             'persist' : 'hidden width ordinal', 'id' : 'au_create_date', 'label' : commonStrings.getString('staff.au_create_date_label'), 'flex' : 1, 
492             'sort_type' : 'date',
493             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.au.create_date(), "%{localized}" ); }
494             ,'sort_value' : function(my) { return util.date.db_date2Date(
495                     my.au
496                     ? my.au.create_date()
497                     : null
498                 ).getTime();
499             }
500         },
501         { 
502             'persist' : 'hidden width ordinal', 'id' : 'au_last_update_time', 'label' : commonStrings.getString('staff.au_last_update_time_label'), 'flex' : 1, 
503             'sort_type' : 'date',
504             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.au.last_update_time(), "%{localized}" ); }
505             ,'sort_value' : function(my) { return util.date.db_date2Date(
506                     my.au
507                     ? my.au.last_update_time()
508                     : null
509                 ).getTime();
510             }
511         },
512
513         { 
514             'persist' : 'hidden width ordinal', 'id' : 'expire_date', 'label' : commonStrings.getString('staff.au_expire_date_label'), 'flex' : 1, 
515             'sort_type' : 'date',
516             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.au.expire_date(), "%{localized_date}" ); }
517             ,'sort_value' : function(my) { return util.date.db_date2Date(
518                     my.au
519                     ? my.au.expire_date()
520                     : null
521                 ).getTime();
522             }
523         },
524         { 
525             'persist' : 'hidden width ordinal', 'id' : 'home_ou', 'label' : commonStrings.getString('staff.au_home_library_label'), 'flex' : 1, 
526             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return data.hash.aou[ my.au.home_ou() ].shortname(); }
527         },
528         { 
529             'persist' : 'hidden width ordinal', 'id' : 'home_ou_fullname', 'label' : commonStrings.getString('staff.au_home_library_fullname_label'), 'flex' : 1, 
530             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return data.hash.aou[ my.au.home_ou() ].name(); }
531         },
532         { 
533             'persist' : 'hidden width ordinal', 'id' : 'credit_forward_balance', 'label' : commonStrings.getString('staff.au_credit_forward_balance_label'), 'flex' : 1, 
534             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.credit_forward_balance(); },
535             'sort_type' : 'money'
536         },
537         { 
538             'persist' : 'hidden width ordinal', 'id' : 'day_phone', 'label' : commonStrings.getString('staff.au_day_phone_label'), 'flex' : 1, 
539             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.day_phone(); }
540         },
541         { 
542             'persist' : 'hidden width ordinal', 'id' : 'evening_phone', 'label' : commonStrings.getString('staff.au_evening_phone_label'), 'flex' : 1, 
543             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.evening_phone(); }
544         },
545         { 
546             'persist' : 'hidden width ordinal', 'id' : 'other_phone', 'label' : commonStrings.getString('staff.au_other_phone_label'), 'flex' : 1, 
547             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.other_phone(); }
548         },
549         { 
550             'persist' : 'hidden width ordinal', 'id' : 'email', 'label' : commonStrings.getString('staff.au_email_label'), 'flex' : 1, 
551             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.email(); }
552         },
553         { 
554             'persist' : 'hidden width ordinal', 'id' : 'alias', 'label' : commonStrings.getString('staff.au_alias_label'), 'flex' : 1, 
555             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.alias(); }
556         },
557         { 
558             'persist' : 'hidden width ordinal', 'id' : 'dob', 'label' : commonStrings.getString('staff.au_birth_date_label'), 'flex' : 1, 
559             'sort_type' : 'date',
560             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return util.date.formatted_date( my.au.dob(), "%{localized_date}" ); }
561             ,'sort_value' : function(my) { return util.date.db_date2Date(
562                     my.au
563                     ? my.au.dob()
564                     : null
565                 ).getTime();
566             }
567         },
568         { 
569             'persist' : 'hidden width ordinal', 'id' : 'ident_type', 'label' : commonStrings.getString('staff.au_ident_type_label'), 'flex' : 1, 
570             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return data.hash.cit[ my.au.ident_type() ].name(); }
571         },
572         { 
573             'persist' : 'hidden width ordinal', 'id' : 'ident_value', 'label' : commonStrings.getString('staff.au_ident_value_label'), 'flex' : 1, 
574             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.ident_value(); }
575         },
576         { 
577             'persist' : 'hidden width ordinal', 'id' : 'ident_type2', 'label' : commonStrings.getString('staff.au_ident_type2_label'), 'flex' : 1, 
578             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return data.hash.cit[ my.au.ident_type2() ].name(); }
579         },
580         { 
581             'persist' : 'hidden width ordinal', 'id' : 'ident_value2', 'label' : commonStrings.getString('staff.au_ident_value2_label'), 'flex' : 1, 
582             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.ident_value2(); }
583         },
584         { 
585             'persist' : 'hidden width ordinal', 'id' : 'net_access_level', 'label' : commonStrings.getString('staff.au_net_access_level_label'), 'flex' : 1, 
586             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.net_access_level(); }
587         },
588         { 
589             'persist' : 'hidden width ordinal', 'id' : 'master_account', 'label' : commonStrings.getString('staff.au_master_account_label'), 'flex' : 1, 
590             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return get_bool( my.au.master_account() ) ? "Yes" : "No"; }
591         },
592         { 
593             'persist' : 'hidden width ordinal', 'id' : 'usrgroup', 'label' : commonStrings.getString('staff.au_group_id_label'), 'flex' : 1, 
594             'primary' : false, 'hidden' : true, 'editable' : false, 'render' : function(my) { return my.au.usrgroup(); }
595         },
596     ];
597     for (var i = 0; i < c.length; i++) {
598         if (modify[ c[i].id ]) {
599             for (var j in modify[ c[i].id ]) {
600                 c[i][j] = modify[ c[i].id ][j];
601             }
602         }
603     }
604     if (params) {
605         if (params.just_these) {
606             JSAN.use('util.functional');
607             var new_c = [];
608             for (var i = 0; i < params.just_these.length; i++) {
609                 var x = util.functional.find_list(c,function(d){return(d.id==params.just_these[i]);});
610                 new_c.push( function(y){ return y; }( x ) );
611             }
612             c = new_c;
613         }
614         if (params.except_these) {
615             JSAN.use('util.functional');
616             var new_c = [];
617             for (var i = 0; i < c.length; i++) {
618                 var x = util.functional.find_list(params.except_these,function(d){return(d==c[i].id);});
619                 if (!x) new_c.push(c[i]);
620             }
621             c = new_c;
622         }
623
624     }
625     return c.sort( function(a,b) { if (a.label < b.label) return -1; if (a.label > b.label) return 1; return 0; } );
626 }
627
628 patron.util.retrieve_au_via_id = function(session, id, f) {
629     JSAN.use('util.network');
630     var network = new util.network();
631     var patron_obj = network.simple_request(
632         'FM_AU_RETRIEVE_VIA_ID.authoritative',
633         [ session, id ],
634         f
635     );
636     return patron_obj;
637 }
638
639 patron.util.retrieve_name_via_id = function(session, id) {
640     JSAN.use('util.network');
641     var network = new util.network();
642     var parts = network.simple_request(
643         'BLOB_AU_PARTS_RETRIEVE',
644         [ session, id, ['family_name', 'first_given_name', 'second_given_name', 'home_ou' ] ]
645     );
646     return parts;
647 }
648
649 patron.util.retrieve_fleshed_au_via_id = function(session, id, fields, func) {
650     JSAN.use('util.network');
651     var network = new util.network();
652     var patron_obj = network.simple_request(
653         'FM_AU_FLESHED_RETRIEVE_VIA_ID.authoritative',
654         [ session, id, fields ],
655         typeof func == 'function' ? func : null
656     );
657     if (typeof func != 'function') {
658         if (!fields) { patron.util.set_penalty_css(patron_obj); }
659         return patron_obj;
660     }
661 }
662
663 patron.util.retrieve_fleshed_au_via_barcode = function(session, id) {
664     JSAN.use('util.network');
665     var network = new util.network();
666     var patron_obj = network.simple_request(
667         'FM_AU_RETRIEVE_VIA_BARCODE.authoritative',
668         [ session, id ]
669     );
670     if (typeof patron_obj.ilsevent == 'undefined') patron.util.set_penalty_css(patron_obj);
671     return patron_obj;
672 }
673
674 var TIME = { minute : 60, hour : 60*60, day : 60*60*24, year : 60*60*24*365 };
675
676 patron.util.set_penalty_css = function(patron) {
677     try {
678         removeCSSClass(document.documentElement,'PATRON_HAS_BILLS');
679         removeCSSClass(document.documentElement,'PATRON_HAS_OVERDUES');
680         removeCSSClass(document.documentElement,'PATRON_HAS_NOTES');
681         removeCSSClass(document.documentElement,'PATRON_HAS_LOST');
682         removeCSSClass(document.documentElement,'PATRON_HAS_LOST_AND_COUNTED');
683         removeCSSClass(document.documentElement,'PATRON_EXCEEDS_CHECKOUT_COUNT');
684         removeCSSClass(document.documentElement,'PATRON_EXCEEDS_OVERDUE_COUNT');
685         removeCSSClass(document.documentElement,'PATRON_EXCEEDS_LOST_COUNT');
686         removeCSSClass(document.documentElement,'PATRON_EXCEEDS_FINES');
687         removeCSSClass(document.documentElement,'NO_PENALTIES');
688         removeCSSClass(document.documentElement,'ONE_PENALTY');
689         removeCSSClass(document.documentElement,'MULTIPLE_PENALTIES');
690         removeCSSClass(document.documentElement,'INVALID_PATRON_EMAIL_ADDRESS');
691         removeCSSClass(document.documentElement,'INVALID_PATRON_DAY_PHONE');
692         removeCSSClass(document.documentElement,'INVALID_PATRON_EVENING_PHONE');
693         removeCSSClass(document.documentElement,'INVALID_PATRON_OTHER_PHONE');
694         removeCSSClass(document.documentElement,'PATRON_HAS_ALERT');
695         removeCSSClass(document.documentElement,'PATRON_BARRED');
696         removeCSSClass(document.documentElement,'PATRON_INACTIVE');
697         removeCSSClass(document.documentElement,'PATRON_EXPIRED');
698         removeCSSClass(document.documentElement,'PATRON_HAS_INVALID_DOB');
699         removeCSSClass(document.documentElement,'PATRON_HAS_INVALID_ADDRESS');
700         removeCSSClass(document.documentElement,'PATRON_AGE_GE_65');
701         removeCSSClass(document.documentElement,'PATRON_AGE_LT_65');
702         removeCSSClass(document.documentElement,'PATRON_AGE_GE_24');
703         removeCSSClass(document.documentElement,'PATRON_AGE_LT_24');
704         removeCSSClass(document.documentElement,'PATRON_AGE_GE_21');
705         removeCSSClass(document.documentElement,'PATRON_AGE_LT_21');
706         removeCSSClass(document.documentElement,'PATRON_AGE_GE_18');
707         removeCSSClass(document.documentElement,'PATRON_AGE_LT_18');
708         removeCSSClass(document.documentElement,'PATRON_AGE_GE_13');
709         removeCSSClass(document.documentElement,'PATRON_AGE_LT_13');
710         removeCSSClass(document.documentElement,'PATRON_NET_ACCESS_1');
711         removeCSSClass(document.documentElement,'PATRON_NET_ACCESS_2');
712         removeCSSClass(document.documentElement,'PATRON_NET_ACCESS_3');
713
714         JSAN.use('util.network'); var net = new util.network();
715         net.simple_request('FM_MOUS_RETRIEVE.authoritative',[ ses(), patron.id() ], function(req) {
716             var summary = req.getResultObject();
717             if (summary && summary.balance_owed() > 0) addCSSClass(document.documentElement,'PATRON_HAS_BILLS');
718         });
719         net.simple_request('FM_CIRC_COUNT_RETRIEVE_VIA_USER.authoritative',[ ses(), patron.id() ], function(req) {
720             try {
721                 var co = req.getResultObject();
722                 if (co.overdue > 0 || co.long_overdue > 0) addCSSClass(document.documentElement,'PATRON_HAS_OVERDUES');
723             } catch(E) {
724                 alert(E);
725             }
726         });
727         net.simple_request('FM_AUN_RETRIEVE_ALL.authoritative',[ ses(), { 'patronid' : patron.id() } ], function(req) {
728             var notes = req.getResultObject();
729             if (notes.length > 0) addCSSClass(document.documentElement,'PATRON_HAS_NOTES');
730         });
731         net.simple_request('FM_CIRC_COUNT_RETRIEVE_VIA_USER.authoritative',[ ses(), patron.id() ], function(req) {
732             try {
733                 var co = req.getResultObject();
734                 if (co.lost > 0) addCSSClass(document.documentElement,'PATRON_HAS_LOST');
735                 JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
736                 if ((String( data.hash.aous['circ.tally_lost'] ) == 'true') && (co.lost > 0)) addCSSClass(document.documentElement,'PATRON_HAS_LOST_AND_COUNTED');
737             } catch(E) {
738                 alert(E);
739             }
740         });
741
742         /*
743         JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
744         data.last_patron = patron.id(); data.stash('last_patron');
745         */
746
747         var penalties = patron.standing_penalties() || [];
748         penalties = penalties.filter(
749             function(p) {
750                 return (!(p.isdeleted() || p.stop_date()));
751             }
752         );
753         for (var i = 0; i < penalties.length; i++) {
754             /* this comes from /opac/common/js/utils.js */
755             addCSSClass(document.documentElement,penalties[i].standing_penalty().name());
756             if (penalties[i].standing_penalty().id() >= 100) {
757                 addCSSClass(document.documentElement,'PATRON_HAS_CUSTOM_PENALTY');
758             }
759             if (get_bool( penalties[i].standing_penalty().staff_alert() )) {
760                 addCSSClass(document.documentElement,'PATRON_HAS_STAFF_ALERT');
761             }
762             var block_list = penalties[i].standing_penalty().block_list();
763             if (block_list) {
764                 addCSSClass(document.documentElement,'PATRON_HAS_BLOCK');
765                 // TODO: futureproofing, split and loop on block_list to produce these classnames
766                 if (block_list.match('CIRC')) {
767                     addCSSClass(document.documentElement,'PATRON_HAS_CIRC_BLOCK');
768                 }
769                 if (block_list.match('RENEW')) {
770                     addCSSClass(document.documentElement,'PATRON_HAS_RENEW_BLOCK');
771                 }
772                 if (block_list.match('HOLD')) {
773                     addCSSClass(document.documentElement,'PATRON_HAS_HOLD_BLOCK');
774                 }
775                 if (block_list.match('CAPTURE')) {
776                     addCSSClass(document.documentElement,'PATRON_HAS_CAPTURE_BLOCK');
777                 }
778                 if (block_list.match('FULFILL')) {
779                     addCSSClass(document.documentElement,'PATRON_HAS_FULFILL_BLOCK');
780                 }
781             }
782         }
783
784         switch(penalties.length) {
785             case 0: addCSSClass(document.documentElement,'NO_PENALTIES'); break;
786             case 1: addCSSClass(document.documentElement,'ONE_PENALTY'); break;
787             default: addCSSClass(document.documentElement,'MULTIPLE_PENALTIES'); break;
788         }
789
790         if (patron.alert_message()) {
791             addCSSClass(document.documentElement,'PATRON_HAS_ALERT');
792         }
793
794         if (get_bool( patron.barred() )) {
795             addCSSClass(document.documentElement,'PATRON_BARRED');
796         }
797
798         if (!get_bool( patron.active() )) {
799             addCSSClass(document.documentElement,'PATRON_INACTIVE');
800         }
801
802         try { addCSSClass(document.documentElement,'PATRON_NET_ACCESS_' + patron.net_access_level()); } catch(E) {}
803
804         var now = new Date();
805         now = now.getTime()/1000;
806
807         var expire_parts = patron.expire_date().substr(0,10).split('-');
808         expire_parts[1] = expire_parts[1] - 1;
809
810         var expire = new Date();
811         expire.setFullYear(expire_parts[0], expire_parts[1], expire_parts[2]);
812         expire = expire.getTime()/1000
813
814         if (expire < now) addCSSClass(document.documentElement,'PATRON_EXPIRED');
815
816         if (patron.dob()) {
817             var age_parts = patron.dob().substr(0,10).split('-');
818             age_parts[1] = age_parts[1] - 1;
819
820             var born = new Date();
821             born.setFullYear(age_parts[0], age_parts[1], age_parts[2]);
822             born = born.getTime()/1000
823
824             var patron_age = now - born;
825             var years_old = Number(patron_age / TIME.year);
826
827             addCSSClass(document.documentElement,'PATRON_AGE_IS_' + years_old);
828
829             if ( years_old >= 65 ) addCSSClass(document.documentElement,'PATRON_AGE_GE_65');
830             if ( years_old < 65 )  addCSSClass(document.documentElement,'PATRON_AGE_LT_65');
831         
832             if ( years_old >= 24 ) addCSSClass(document.documentElement,'PATRON_AGE_GE_24');
833             if ( years_old < 24 )  addCSSClass(document.documentElement,'PATRON_AGE_LT_24');
834             
835             if ( years_old >= 21 ) addCSSClass(document.documentElement,'PATRON_AGE_GE_21');
836             if ( years_old < 21 )  addCSSClass(document.documentElement,'PATRON_AGE_LT_21');
837         
838             if ( years_old >= 18 ) addCSSClass(document.documentElement,'PATRON_AGE_GE_18');
839             if ( years_old < 18 )  addCSSClass(document.documentElement,'PATRON_AGE_LT_18');
840         
841             if ( years_old >= 13 ) addCSSClass(document.documentElement,'PATRON_AGE_GE_13');
842             if ( years_old < 13 )  addCSSClass(document.documentElement,'PATRON_AGE_LT_13');
843         } else {
844             addCSSClass(document.documentElement,'PATRON_HAS_INVALID_DOB');
845         }
846
847         if ( get_bool( patron.juvenile() ) ) addCSSClass(document.documentElement,'PATRON_JUVENILE');
848         else removeCSSClass(document.documentElement,'PATRON_JUVENILE');
849
850         if (patron.mailing_address() && typeof patron.mailing_address() == 'object') {
851             if (!get_bool(patron.mailing_address().valid())) {
852                 addCSSClass(document.documentElement,'PATRON_HAS_INVALID_ADDRESS');
853             }
854         }
855         if (patron.billing_address() && typeof patron.billing_address() == 'object') {
856             if (!get_bool(patron.billing_address().valid())) {
857                 addCSSClass(document.documentElement,'PATRON_HAS_INVALID_ADDRESS');
858             }
859         }
860
861     } catch(E) {
862         dump('patron.util.set_penalty_css: ' + E + '\n');
863         alert('patron.util.set_penalty_css: ' + E + '\n');
864     }
865 }
866
867 patron.util.merge = function(record_ids) {
868     var error;
869     try {
870         JSAN.use('util.error'); error = new util.error();
871         JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
872         var horizontal_interface = String( data.hash.aous['ui.circ.patron_summary.horizontal'] ) == 'true';
873         var top_xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" >';
874         top_xml += '<description>' + $("patronStrings").getString('staff.patron.usr_buckets.merge_records.merge_lead') + '</description>';
875         top_xml += '<hbox>';
876         top_xml += '<button id="lead" disabled="true" label="'
877                 + $("patronStrings").getString('staff.patron.usr_buckets.merge_records.button.label') + '" name="fancy_submit"/>';
878         top_xml += '<button label="' + $("patronStrings").getString('staff.patron.usr_buckets.merge_records.cancel_button.label') +'" accesskey="'
879                 + $("patronStrings").getString('staff.patron.usr_buckets.merge_records.cancel_button.accesskey') +'" name="fancy_cancel"/></hbox></vbox>';
880
881         var xml = '<form xmlns="http://www.w3.org/1999/xhtml">';
882         xml += '<table>';
883
884         function table_cell_with_lead_button(id) {
885             var xml = '';
886             xml += '<td><input value="' + $("patronStrings").getString('staff.patron.usr_buckets.merge_records.lead')
887             xml += '" id="record_' + id + '" type="radio" name="lead"';
888             xml += ' onclick="' + "try { var x = $('lead'); x.setAttribute('value',";
889             xml += id + '); x.disabled = false; } catch(E) { alert(E); }">';
890             xml += '</input>' + $("patronStrings").getFormattedString('staff.patron.usr_buckets.merge_records.lead_record_number',[id]) + '</td>';
891             return xml;
892         }
893
894         var iframe_css;
895         if (!horizontal_interface) {
896             xml += '<tr valign="top">';
897             for (var i = 0; i < record_ids.length; i++) {
898                 xml += table_cell_with_lead_button( record_ids[i] );
899             }
900             xml += '</tr><tr valign="top">';
901             iframe_css = 'min-height: 1000px; min-width: 300px;';
902         } else {
903             iframe_css = 'min-height: 200px; min-width: 1000px;';
904         }
905         for (var i = 0; i < record_ids.length; i++) {
906             if (horizontal_interface) {
907                 xml += '<tr valign="top">' + table_cell_with_lead_button( record_ids[i] );
908             }
909             xml += '<td nowrap="nowrap"><iframe style="' + iframe_css + '" flex="1" src="' + urls.XUL_PATRON_SUMMARY; 
910             xml += '?id=' + record_ids[i] + '&amp;show_name=1" oils_force_external="true"/></td>';
911             if (horizontal_interface) {
912                 xml += '</tr>';
913             }
914         }
915         if (!horizontal_interface) {
916             xml += '</tr>';
917         }
918         xml += '</table></form>';
919         JSAN.use('util.window'); var win = new util.window();
920         var fancy_prompt_data = win.open(
921             urls.XUL_FANCY_PROMPT,
922             'fancy_prompt', 'chrome,resizable,modal,width=1000,height=700',
923             {
924                 'top_xml' : top_xml, 'xml' : xml, 'title' : $("patronStrings").getString('staff.patron.usr_buckets.merge_records.fancy_prompt_title')
925             }
926         );
927
928         if (typeof fancy_prompt_data.fancy_status == 'undefined' || fancy_prompt_data.fancy_status == 'incomplete') {
929             alert($("patronStrings").getString('staff.patron.usr_buckets.merge_records.fancy_prompt.alert'));
930             return false;
931         }
932
933         JSAN.use('util.functional'); JSAN.use('util.network'); var network = new util.network();
934         var robj = network.simple_request('FM_AU_MERGE', 
935             [ 
936                 ses(), 
937                 fancy_prompt_data.lead,
938                 util.functional.filter_list( record_ids,
939                     function(o) {
940                         return o != fancy_prompt_data.lead;
941                     }
942                 )
943             ]
944         );
945         if (Number(robj) != 1) { throw(robj); }
946         return fancy_prompt_data.lead;
947     } catch(E) {
948         dump('patron.util.merge: ' + js2JSON(E) + '\n');
949         try { error.standard_unexpected_error_alert('Error in patron.util.merge',E); } catch(F) { alert('patron.util.merge: ' + E + '\n'); }
950         return false;
951     }
952 }
953
954 patron.util.format_name = function(patron_obj) {
955     var patron_name = ( patron_obj.prefix() ? patron_obj.prefix() + ' ' : '') +
956         patron_obj.family_name() + ', ' +
957         patron_obj.first_given_name() + ' ' +
958         ( patron_obj.second_given_name() ? patron_obj.second_given_name() + ' ' : '' ) +
959         ( patron_obj.suffix() ? patron_obj.suffix() : ''); 
960     return patron_name;
961 }
962
963 patron.util.work_log_patron_edit = function(p) {
964     var error;
965     try {
966         JSAN.use('util.error'); error = new util.error();
967         error.work_log(
968             document.getElementById('patronStrings').getFormattedString(
969                 'staff.circ.work_log_patron_edit.message',
970                 [
971                     ses('staff_usrname'),
972                     p.family_name(),
973                     p.card().barcode()
974                 ]
975             ), {
976                 'au_id' : p.id(),
977                 'au_family_name' : p.family_name(),
978                 'au_barcode' : p.card().barcode()
979             }
980         );
981     } catch(E) {
982         error.sdump('D_ERROR','Error with work_logging in menu.js, cmd_patron_register:' + E);
983     }
984 }
985
986
987 dump('exiting patron/util.js\n');