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