]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/server/cat/util.js
Merge branch 'dbs/ttopac-sfx-integration' into dbs/template-toolkit-integration
[Evergreen.git] / Open-ILS / xul / staff_client / server / cat / util.js
1 dump('entering cat/util.js\n');
2
3 function $(id) { return document.getElementById(id); }
4
5 if (typeof cat == 'undefined') var cat = {};
6 cat.util = {};
7
8 cat.util.EXPORT_OK    = [ 
9     'spawn_copy_editor', 'add_copies_to_bucket', 'show_in_opac', 'spawn_spine_editor', 'transfer_copies', 
10     'transfer_title_holds', 'mark_item_missing', 'mark_item_damaged', 'replace_barcode', 'fast_item_add', 
11     'make_bookable', 'edit_new_brsrc', 'edit_new_bresv', 'batch_edit_volumes', 'render_fine_level',
12     'render_loan_duration', 'mark_item_as_missing_pieces', 'render_callnumbers_for_bib_menu',
13     'render_cn_prefix_menuitems', 'render_cn_suffix_menuitems', 'render_cn_class_menu',
14     'render_cn_prefix_menu', 'render_cn_suffix_menu', 'transfer_specific_title_holds'
15 ];
16 cat.util.EXPORT_TAGS    = { ':all' : cat.util.EXPORT_OK };
17
18 cat.util.replace_barcode = function(old_bc) {
19     try {
20         JSAN.use('util.network');
21         var network = new util.network();
22
23         if (!old_bc) old_bc = window.prompt($("catStrings").getString('staff.cat.util.replace_barcode.old_bc_window_prompt.prompt'),
24             '',
25             $("catStrings").getString('staff.cat.util.replace_barcode.old_bc_window_prompt.title'));
26         if (!old_bc) return;
27
28         var copy;
29         try {
30             copy = network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ old_bc ]);
31             if (typeof copy.ilsevent != 'undefined') throw(copy); 
32             if (!copy) throw(copy);
33         } catch(E) {
34             alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.error_alert', [old_bc]) + '\n');
35             return old_bc;
36         }
37     
38         // Why did I want to do this twice?  Because this copy is more fleshed?
39         try {
40             copy = network.simple_request('FM_ACP_RETRIEVE',[ copy.id() ]);
41             if (typeof copy.ilsevent != 'undefined') throw(copy);
42             if (!copy) throw(copy);
43         } catch(E) {
44             try {
45                 alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.error_alert', [old_bc]) +
46                      '\n' + (typeof E.ilsevent == 'undefined' ? '' : E.textcode + ' : ' + E.desc));
47             } catch(F) {
48                 alert(E + '\n' + F);
49             }
50             return old_bc;
51         }
52     
53         var new_bc = window.prompt($("catStrings").getString('staff.cat.util.replace_barcode.new_bc_window_prompt.prompt'),
54             '',
55             $("catStrings").getString('staff.cat.util.replace_barcode.new_bc_window_prompt.title'));
56         new_bc = String( new_bc ).replace(/\s/g,'');
57         /* Casting a possibly null input value to a String turns it into "null" */
58         if (!new_bc || new_bc == 'null') {
59             alert($("catStrings").getString('staff.cat.util.replace_barcode.new_bc.failed'));
60             return old_bc;
61         }
62     
63         var test = network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ new_bc ]);
64         if (typeof test.ilsevent == 'undefined') {
65             alert('Rename aborted.  Another copy has barcode "' + new_bc + '".');
66             return old_bc;
67         } else {
68             if (test.ilsevent != 1502 /* ASSET_COPY_NOT_FOUND */) {
69                 obj.error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.testing_error', [new_bc]), test);
70                 return old_bc;
71             }    
72         }
73
74         copy.barcode(new_bc); copy.ischanged('1');
75         var r = network.simple_request('FM_ACP_FLESHED_BATCH_UPDATE', [ ses(), [ copy ] ]);
76         if (typeof r.ilsevent != 'undefined') { 
77             if (r.ilsevent != 0) {
78                 if (r.ilsevent == 5000 /* PERM_FAILURE */) {
79                     alert($("catStrings").getString('staff.cat.util.replace_barcode.insufficient_permission_for_rename'));
80                     return old_bc;
81                 } else {
82                     obj.error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.replace_barcode.item_rename_error'),r);
83                     return old_bc;
84                 }
85             }
86         }
87
88         return new_bc;
89     } catch(E) {
90         JSAN.use('util.error'); var error = new util.error();
91         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.replace_barcode.rename_error'),E);
92         return old_bc;
93     }
94 }
95
96 cat.util.transfer_title_holds = function(old_targets) {
97     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
98     JSAN.use('util.network'); var network = new util.network();
99     try {
100         data.stash_retrieve();
101         var target = data.marked_record_for_hold_transfer;
102         if (!target) {
103             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.destination_needed.label');
104             alert(m);
105             return;
106         }
107         var robj = network.simple_request('TRANSFER_TITLE_HOLDS',[ ses(), target, old_targets ]);
108         if (robj == 1) {
109             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.success.label');
110             alert(m);
111         } else {
112             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.failure.label');
113             alert(m);
114         }
115     } catch(E) {
116         alert('Error in cat.util.transfer_title.holds(): ' + E);
117     }
118 }
119
120 cat.util.transfer_specific_title_holds = function(hold_ids,unique_targets) {
121     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
122     JSAN.use('util.network'); var network = new util.network();
123     try {
124         data.stash_retrieve();
125         var target = data.marked_record_for_hold_transfer;
126         if (!target) {
127             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.destination_needed.label');
128             alert(m);
129             return;
130         }
131         if (unique_targets.length > 1) {
132             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.many_bibs.warning');
133             if (! window.confirm(m)) {
134                 return;
135             }
136         }
137         var robj = network.simple_request('TRANSFER_SPECIFIC_TITLE_HOLDS',[ ses(), target, hold_ids ]);
138         if (robj == 1) {
139             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.success.label');
140             alert(m);
141         } else {
142             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.failure.label');
143             alert(m);
144         }
145     } catch(E) {
146         alert('Error in cat.util.transfer_title.holds(): ' + E);
147     }
148 }
149
150
151 cat.util.transfer_copies = function(params) {
152     JSAN.use('util.error'); var error = new util.error();
153     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
154     JSAN.use('util.network'); var network = new util.network();
155     try {
156         data.stash_retrieve();
157         if (!data.marked_volume) {
158             alert($("catStrings").getString('staff.cat.util.transfer_copies.unmarked_volume_alert'));
159             return;
160         }
161         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
162         var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: auto">';
163         if (!params.message) {
164             params.message = $("catStrings").getFormattedString('staff.cat.util.transfer_copies.params_message', [data.hash.aou[ params.owning_lib ].shortname(), params.volume_label]);
165             //params.message = 'Transfer items from their original volumes to ';
166             //params.message += data.hash.aou[ params.owning_lib ].shortname() + "'s volume labelled ";
167             //params.message += '"' + params.volume_label + '" on the following record (and change their circ libs to match)?';
168         }
169
170         xml += '<description>' + params.message.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') + '</description>';
171         xml += '<hbox><button label="' + $("catStrings").getString('staff.cat.util.transfer_copies.transfer.label')+ '" name="fancy_submit"/>';
172         xml += '<button label="' + $("catStrings").getString('staff.cat.util.transfer_copies.cancel.label');
173         xml += '" accesskey="'+ $("catStrings").getString('staff.cat.util.transfer_copies.cancel.accesskey') +'" name="fancy_cancel"/></hbox>';
174         xml += '<iframe style="overflow: scroll" flex="1" src="' + urls.XUL_BIB_BRIEF + '?docid=' + params.docid + '"/>';
175         xml += '</vbox>';
176         //data.temp_transfer = xml; data.stash('temp_transfer');
177         JSAN.use('util.window'); var win = new util.window();
178         var fancy_prompt_data = win.open(
179             urls.XUL_FANCY_PROMPT,
180             //+ '?xml_in_stash=temp_transfer'
181             //+ '&title=' + window.escape('Item Transfer'),
182             'fancy_prompt', 'chrome,resizable,modal,width=500,height=300',
183             { 'xml' : xml, 'title' : $("catStrings").getString('staff.cat.util.transfer_copies.window_title') }
184         );
185         if (fancy_prompt_data.fancy_status == 'incomplete') { alert($("catStrings").getString('staff.cat.util.transfer_copies.aborted_transfer')); return; }
186
187         JSAN.use('util.functional');
188
189         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ params.copy_ids ]);
190
191         for (var i = 0; i < copies.length; i++) {
192             copies[i].call_number( data.marked_volume );
193             copies[i].circ_lib( params.owning_lib );
194             copies[i].ischanged( 1 );
195         }
196
197         var robj = network.simple_request(
198             'FM_ACP_FLESHED_BATCH_UPDATE', 
199             [ ses(), copies, true ], 
200             null,
201             {
202                 'title' : $("catStrings").getString('staff.cat.util.transfer_copies.override_transfer_failure'),
203                 'overridable_events' : [
204                     1208 /* TITLE_LAST_COPY */,
205                     1227 /* COPY_DELETE_WARNING */,
206                 ]
207             }
208         );
209         
210         if (typeof robj.ilsevent != 'undefined') {
211             throw(robj);
212         } else {
213             alert($("catStrings").getString('staff.cat.util.transfer_copies.successful_transfer'));
214         }
215
216     } catch(E) {
217         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.transfer_copies.transfer_error'),E);
218     }
219 }
220
221 cat.util.spawn_spine_editor = function(selection_list) {
222     JSAN.use('util.error'); var error = new util.error();
223     try {
224         JSAN.use('util.functional');
225         xulG.new_tab(
226             xulG.url_prefix( urls.XUL_SPINE_LABEL ),
227             { 'tab_name' : $("catStrings").getString('staff.cat.util.spine_editor.tab_name') },
228             {
229                 'barcodes' : util.functional.map_list( selection_list, function(o){return o.barcode;}) 
230             }
231         );
232     } catch(E) {
233         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.spine_editor.spine_editor_error'),E);
234     }
235 }
236
237 cat.util.show_in_opac = function(selection_list) {
238     JSAN.use('util.error'); var error = new util.error();
239     JSAN.use('util.network'); var network = new util.network();
240     var doc_id; var seen = {};
241     try {
242         for (var i = 0; i < selection_list.length; i++) {
243             doc_id = selection_list[i].doc_id;
244             if (!doc_id) {
245                 var barcode = selection_list[i].barcode;
246                 doc_id = network.simple_request('FM_BRE_ID_VIA_BARCODE',[barcode]);
247                 if (typeof doc_id.ilsevent != 'undefined' || doc_id == -1) {
248                     alert($("catStrings").getFormattedString('staff.cat.util.show_in_opac.unknown_barcode', [barcode]));
249                     continue;
250                 }
251             }
252             if (doc_id == -1 ) {
253                 continue; /* pre-cat */
254             }
255             if (typeof seen[doc_id] != 'undefined') {
256                 continue;
257             }
258             seen[doc_id] = true;
259             var opac_url = xulG.url_prefix( urls.opac_rdetail ) + '?r=' + doc_id;
260             var content_params = { 
261                 'session' : ses(),
262                 'authtime' : ses('authtime'),
263                 'opac_url' : opac_url,
264             };
265             xulG.new_tab(
266                 xulG.url_prefix(urls.XUL_OPAC_WRAPPER), 
267                 {'tab_name':$('catStrings').getString('staff.cat.util.show_in_opac.retrieving_title')}, 
268                 content_params
269             );
270         }
271     } catch(E) {
272         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.show_in_opac.catalog_error_for_doc_id', [doc_id]),E);
273     }
274 }
275
276 cat.util.add_copies_to_bucket = function(selection_list) {
277     JSAN.use('util.functional');
278     JSAN.use('util.window'); var win = new util.window();
279     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
280     data.cb_temp_copy_ids = js2JSON(
281         util.functional.map_list(
282             selection_list,
283             function (o) {
284                 if (typeof o.copy_id != 'undefined' && o.copy_id != null) {
285                     return o.copy_id;
286                 } else {
287                     return o;
288                 }
289             }
290         )
291     );
292     data.stash('cb_temp_copy_ids');
293     win.open( 
294         xulG.url_prefix(urls.XUL_COPY_BUCKETS_QUICK),
295         '_blank',
296         'chrome,resizable,center'
297     );
298 }
299
300 cat.util.add_titles_to_bucket = function(record_ids) {
301     JSAN.use('util.window'); var win = new util.window();
302     win.open(
303         xulG.url_prefix(urls.XUL_RECORD_BUCKETS_QUICK),
304         '_blank',
305         'chrome,resizable,modal,center',
306         {
307             record_ids: record_ids 
308         }
309     );
310 }
311
312 cat.util.spawn_copy_editor = function(params) {
313     try {
314         if (!params.copy_ids && !params.copies) return;
315         if (params.copy_ids && params.copy_ids.length == 0) return;
316         if (params.copies && params.copies.length == 0) return;
317         if (params.copy_ids) params.copy_ids = js2JSON(params.copy_ids); // legacy
318         if (!params.caller_handles_update) params.handle_update = 1; // legacy
319
320         var obj = {};
321         JSAN.use('util.network'); obj.network = new util.network();
322         JSAN.use('util.error'); obj.error = new util.error();
323     
324         var title = '';
325         if (params.copy_ids && params.copy_ids.length > 1 && params.edit == 1)
326             title = $("catStrings").getString('staff.cat.util.copy_editor.batch_edit');
327         else if(params.copies && params.copies.length > 1 && params.edit == 1)
328             title = $("catStrings").getString('staff.cat.util.copy_editor.batch_view');
329         else if(params.copy_ids && params.copy_ids.length == 1)
330             title = $("catStrings").getString('staff.cat.util.copy_editor.edit');
331         else
332             title = $("catStrings").getString('staff.cat.util.copy_editor.view');
333
334         JSAN.use('util.window'); var win = new util.window();
335         var my_xulG = win.open(
336             (urls.XUL_COPY_EDITOR),
337             title,
338             'chrome,modal,resizable',
339             params
340         );
341         if (!my_xulG.copies && params.edit) {
342         } else {
343             return my_xulG.copies;
344         }
345         return [];
346     } catch(E) {
347         JSAN.use('util.error'); var error = new util.error();
348         error.standard_unexpected_error_alert('error in cat.util.spawn_copy_editor',E);
349     }
350 }
351
352 cat.util.mark_item_damaged = function(copy_ids) {
353     var error;
354     try {
355         JSAN.use('util.error'); error = new util.error();
356         JSAN.use('util.functional'); JSAN.use('util.date');
357         JSAN.use('util.network'); var network = new util.network();
358         if (!copy_ids) { return; }
359         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
360         if (copy_ids.length < 1) { return; }
361         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
362         if (typeof copies.ilsevent != 'undefined') throw(copies);
363         var magic_status = false;
364         for (var i = 0; i < copies.length; i++) {
365             var status = copies[i].status(); if (typeof status == 'object') status = status.id();
366             if (typeof my_constants.magical_statuses[ status ] != 'undefined') 
367                 if (my_constants.magical_statuses[ status ].block_mark_item_damaged) magic_status = true;
368         }
369         if (magic_status) {
370         
371             error.yns_alert($("catStrings").getString('staff.cat.util.mark_item_damaged.af_message'),
372                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_title'),
373                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_ok_label'), null, null,
374                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_confirm_action'));
375
376         } else {
377
378             var r = error.yns_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.md_message', [util.functional.map_list( copies, function(o) { return o.barcode(); } ).join(", ")]),
379                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_title'),
380                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_ok_label'),
381                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_cancel_label'), null,
382                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_confirm_action'));
383
384             if (r == 0) {
385                 var count = 0;
386                 for (var i = 0; i < copies.length; i++) {
387                     try {
388
389                         var my_circ = network.simple_request('FM_CIRC_RETRIEVE_VIA_COPY',[ses(),copies[i].id(),1]);
390                         if (typeof my_circ.ilsevent == 'undefined') { 
391                             JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
392                             my_circ = my_circ[0];
393                             if (typeof my_circ != 'undefined') {
394                                 if (! my_circ.checkin_time() ) {
395                                     var due_date = my_circ.due_date() ? util.date.formatted_date( my_circ.due_date(), '%F' ) : null;
396                                     var auto_checkin = String( data.hash.aous['circ.auto_checkin_on_mark_damage'] ) == 'true';
397                                     /* short-circuit this behavior.  We don't want to mark an item damaged and still have it circulating.  At least for now.  Wait until someone asks for it. */
398                                     auto_checkin = true; 
399                                     JSAN.use('patron.util');
400                                     var patron_obj = patron.util.retrieve_fleshed_au_via_id( ses(), my_circ.usr() );
401                                     var patron_name = patron.util.format_name( patron_obj ) + ' : ' + patron_obj.card().barcode();
402                                     var msg = $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.item_circulating_to_patron', [ 
403                                         copies[i].barcode(),
404                                         patron_name,
405                                         util.date.formatted_date( my_circ.due_date(), '%{localized}' )]);
406                                     JSAN.use('util.date'); var today = util.date.formatted_date(new Date(),'%F');
407                                     var r2 = auto_checkin ? 1 : error.yns_alert(
408                                         msg,
409                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.title'),
410                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.no_checkin'),
411                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.normal_checkin'),
412                                         due_date ? (today > due_date ? document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.forgiving_checkin') : null) : null,
413                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.confirm_action')
414                                     );
415                                     JSAN.use('circ.util');
416                                     switch(r2) {
417                                         case 1:
418                                             circ.util.checkin_via_barcode( ses(), { 'barcode' : copies[i].barcode(), 'noop' : 1 } );
419                                         break;
420                                         case 2:
421                                             circ.util.checkin_via_barcode( ses(), { 'barcode' : copies[i].barcode(), 'noop' : 1 }, due_date );
422                                         break;
423                                     }
424                                 }
425                             }
426                         }
427
428                         var robj = network.simple_request('MARK_ITEM_DAMAGED',[ses(),copies[i].id()]);
429                         if (typeof robj.ilsevent != 'undefined') {
430                             switch(robj.textcode) {
431                                 case 'DAMAGE_CHARGE' :
432                                     var params = {};
433                                     JSAN.use('util.money');
434                                     var circ_obj = robj.payload.circ;
435                                     var patron_obj = circ_obj.usr();
436                                     JSAN.use('patron.util'); 
437                                     var patron_name = patron.util.format_name( patron_obj ) + ' : ' + patron_obj.card().barcode(); 
438                                     var r1 = error.yns_alert( 
439                                         $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.charge_patron_prompt.message', [  
440                                             copies[i].barcode(),  
441                                             patron_name,  
442                                             util.date.formatted_date( circ_obj.checkin_time(), '%{localized}' ),
443                                             util.money.sanitize(robj.payload.charge) ]), 
444                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.title'), 
445                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.ok_label'), 
446                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.change_amount_label'), 
447                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.cancel_label'), 
448                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.confirm_action')); 
449                                     if (r1 == 0) {
450                                         params.apply_fines = 'apply';
451                                     } else if (r1 == 1) { 
452                                         JSAN.use('util.window'); var win = new util.window();
453                                         var my_xulG = win.open(
454                                             urls.XUL_PATRON_BILL_WIZARD,
455                                             'billwizard',
456                                             'chrome,resizable,modal',
457                                             { 
458                                                 'patron' : patron_obj, 
459                                                 'patron_id' : patron_obj.id(), 
460                                                 'circ' : circ_obj, 
461                                                 'xact_id' : circ_obj.id(), 
462                                                 'do_not_process_bill' : true,
463                                                 /* 'override_default_billing_type' : 7, FIXME: maybe reintroduce this with an org setting for the specific btype? */
464                                                 'override_default_price' : util.money.sanitize( robj.payload.charge ) 
465                                             }
466                                         );
467
468                                         params.apply_fines = my_xulG.proceed ? 'apply' : 'noapply';
469                                         if (my_xulG.proceed) {
470                                             params.override_amount = my_xulG.amount;
471                                             params.override_btype = my_xulG.cbt_id;
472                                             params.override_note = my_xulG.note;
473                                         }
474                                     } else {
475                                         params.apply_fines = 'noapply';
476                                     }
477                                     robj = network.simple_request('MARK_ITEM_DAMAGED',[ ses(), copies[i].id(), params ]);
478                                     if (typeof robj.ilsevent != 'undefined') { throw(robj); }
479                                     break;
480                                 default: throw(robj);
481                             }
482                         }
483                         count++;
484                     } catch(E) {
485                         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.marking_error', [copies[i].barcode()]),E);
486                     }
487                 }
488                 alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_damaged.one_item_damaged') :
489                     $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.multiple_item_damaged', [count]));
490             }
491         }
492
493     } catch(E) {
494         if (error) error.standard_unexpected_error_alert('cat.util.mark_item_damaged',E); else alert('FIXME: ' + E);
495     }
496 }
497
498 cat.util.mark_item_missing = function(copy_ids) {
499     var error;
500     try {
501         JSAN.use('util.error'); error = new util.error();
502         JSAN.use('util.functional');
503         JSAN.use('util.network'); var network = new util.network();
504         if (!copy_ids) { return; }
505         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
506         if (copy_ids.length < 1) { return; }
507         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
508         if (typeof copies.ilsevent != 'undefined') throw(copies);
509         var magic_status = false;
510         for (var i = 0; i < copies.length; i++) {
511             var status = copies[i].status(); if (typeof status == 'object') status = status.id();
512             if (typeof my_constants.magical_statuses[ status ] != 'undefined') 
513                 if (my_constants.magical_statuses[ status ].block_mark_item_action) magic_status = true;
514         }
515         if (magic_status) {
516         
517             error.yns_alert($("catStrings").getString('staff.cat.util.mark_item_missing.af_message'),
518                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_title'),
519                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_ok_label'), null, null,
520                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_confirm_action'));
521
522         } else {
523
524             var r = error.yns_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing.ms_message', [util.functional.map_list( copies, function(o) { return o.barcode(); } ).join(", ")]),
525                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_title'),
526                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_ok_label'),
527                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_cancel_label'), null,
528                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_confirm_action'));
529
530             if (r == 0) {
531                 var count = 0;
532                 for (var i = 0; i < copies.length; i++) {
533                     try {
534                         var robj = network.simple_request('MARK_ITEM_MISSING',[ses(),copies[i].id()]);
535                         if (typeof robj.ilsevent != 'undefined') throw(robj);
536                         count++;
537                     } catch(E) {
538                         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing.marking_error', [copies[i].barcode()]),E);
539                     }
540                 }
541                 alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_missing.one_item_missing') :
542                     $("catStrings").getFormattedString('staff.cat.util.mark_item_missing.multiple_item_missing', [count]));
543             }
544         }
545
546     } catch(E) {
547         if (error) error.standard_unexpected_error_alert('cat.util.mark_item_missing',E); else alert('FIXME: ' + E);
548     }
549 }
550
551 cat.util.fast_item_add = function(doc_id,cn_label,cp_barcode) {
552     var error;
553     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
554     try {
555
556         JSAN.use('util.error'); error = new util.error();
557         JSAN.use('util.network'); var network = new util.network();
558
559         var acn_blob = network.simple_request(
560             'FM_ACN_FIND_OR_CREATE',
561             [ ses(), cn_label, doc_id, ses('ws_ou') ]
562         );
563
564         if (typeof acn_blob.ilsevent != 'undefined') {
565             error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.volume_copy_creator.stash_and_close.problem_with_volume', [cn]), acn_blob);
566             return;
567         }
568
569         // Get the default copy status; default to available if unset, per 1.6
570         var fast_ccs = data.hash.aous['cat.default_copy_status_fast'] || 0;
571
572         var copy_obj = new acp();
573         copy_obj.id( -1 );
574         copy_obj.isnew('1');
575         copy_obj.barcode( cp_barcode );
576         copy_obj.call_number( acn_blob.acn_id );
577         copy_obj.circ_lib( ses('ws_ou') );
578         /* FIXME -- use constants */
579         copy_obj.deposit(0);
580         copy_obj.price(0);
581         copy_obj.deposit_amount(0);
582         copy_obj.fine_level(2); // Normal
583         copy_obj.loan_duration(2); // Normal
584         copy_obj.location(1); // Stacks
585         copy_obj.status(fast_ccs);
586         copy_obj.circulate(get_db_true());
587         copy_obj.holdable(get_db_true());
588         copy_obj.opac_visible(get_db_true());
589         copy_obj.ref(get_db_false());
590
591         JSAN.use('util.window'); var win = new util.window();
592         JSAN.use('cat.util');
593
594         var unified_interface = String( data.hash.aous['ui.unified_volume_copy_editor'] ) == 'true';
595         if (unified_interface) {
596             var horizontal_interface = String( data.hash.aous['ui.cat.volume_copy_editor.horizontal'] ) == 'true';
597             var url = window.xulG.url_prefix( horizontal_interface ? urls.XUL_VOLUME_COPY_CREATOR_HORIZONTAL : urls.XUL_VOLUME_COPY_CREATOR );
598             var w = xulG.set_tab(
599                 url,
600                 {
601                     'tab_name' : document.getElementById('offlineStrings').getFormattedString(
602                         'cat.bib_record',
603                         [ doc_id ]
604                     )
605                 },
606                 {
607                     'doc_id' : doc_id, 
608                     'existing_copies' : [ copy_obj ],
609                     'load_opac_when_done' : true,
610                     'labels_in_new_tab' : true
611                 }
612             );
613
614         } else {
615             return cat.util.spawn_copy_editor( { 'handle_update' : 1, 'edit' : 1, 'docid' : doc_id, 'copies' : [ copy_obj ] });
616         }
617
618     } catch(E) {
619         if (error) error.standard_unexpected_error_alert('cat.util.fast_item_add',E); else alert('FIXME: ' + E);
620     }
621 }
622
623 cat.util.make_bookable = function(copy_ids) {
624     if (!copy_ids) { return; }
625     copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
626     if (copy_ids.length < 1) { return; }
627     var results = fieldmapper.standardRequest(
628         ["open-ils.booking", "open-ils.booking.resources.create_from_copies"],
629         [ses(), copy_ids]
630     );
631     if (results == null) {
632         alert(document.getElementById("catStrings").getString(
633             "staff.cat.copy_browser.make_bookable.create_failed_silent"
634         ));
635     }
636     else if (typeof results.ilsevent != "undefined") {
637         alert(document.getElementById("catStrings").getFormattedString(
638             "staff.cat.copy_browser.make_bookable.create_failed",
639             [results.ilsevent, results.textcode, results.desc, results.debug]
640         ));
641     }
642     return results;
643 }
644
645 cat.util.edit_new_brsrc = function(brsrc_list) {
646     /* Spawn new tab to allow editing new resources. */
647     try {
648         xulG.resultant_brsrc = brsrc_list.map(function(o) { return o[0]; });
649         xulG.new_tab(
650             urls.XUL_BROWSER + "?url=" + window.escape(
651                 xulG.url_prefix("/eg/conify/global/booking/resource")
652             ), {
653                 "tab_name": offlineStrings.getString(
654                     "menu.cmd_booking_resource.tab"
655                  ),
656                 "browser" : true
657             }, {
658                 "no_xulG": false,
659                 "show_print_button": false,
660                 "show_nav_buttons": true,
661                 "passthru_content_params": xulG
662             }
663         );
664     } catch(E) {
665         alert(
666             document.getElementById("catStrings").getFormattedString(
667                 "staff.cat.copy_browser.make_bookable.newtab_failed"
668             ), E
669         );
670     }
671 }
672
673 cat.util.edit_new_bresv = function(booking_results) {
674     /* Spawn new tab to allow editing new reservations. */
675     try {
676         if (xulG.auth == undefined) {
677             xulG.auth = {"session": {"key": ses()}};
678         }
679         xulG.bresv_interface_opts = {"booking_results": booking_results};
680         xulG.new_tab(
681             xulG.url_prefix("/eg/booking/reservation"),
682             {
683                 "tab_name": offlineStrings.getString(
684                     "menu.cmd_booking_reservation.tab"
685                  ),
686                 "browser" : false
687             }, xulG
688         );
689     } catch(E) {
690         alert(
691             document.getElementById("catStrings").getString(
692                 "staff.cat.copy_browser.make_bookable.newtab_failed"
693             ) + E
694         );
695     }
696 }
697
698 cat.util.batch_edit_volumes = function(fleshed_volumes) {
699     try {
700         if (!fleshed_volumes || fleshed_volumes.length < 1) { return false; }
701
702         JSAN.use('util.functional');
703         JSAN.use('util.network'); var net = new util.network();
704         JSAN.use('util.window'); var win = new util.window();
705
706         var can_edit = net.simple_request(
707             'PERM_MULTI_ORG_CHECK',
708             [
709                 ses(),
710                 ses('staff_id'),
711                 util.functional.map_list(
712                     fleshed_volumes,
713                     function(v) {
714                         return v.owning_lib();
715                     }
716                 ),
717                 ['UPDATE_VOLUME']
718             ]
719         );
720         if (!can_edit) {
721             alert(document.getElementById('catStrings').getString('staff.cat.edit_volume.permission_error'));
722             return false;
723         }
724         var title;
725         if (fleshed_volumes.length == 1) {
726             title = document.getElementById('catStrings').getString('staff.cat.edit_volume.title');
727         } else {
728             title = document.getElementById('catStrings').getString('staff.cat.edit_volume.title.plural');
729         }
730
731         function clone_list(o) {
732             var list = JSON2js( js2JSON( o ) );
733             // now that it is safe to clear copies, let's do so, otherwise may get an error from volume edit method
734             for (var i = 0; i < list.length; i++) { list[i].copies( [] ); } 
735             return list;
736         }
737
738         var my_xulG = win.open(
739             xulG.url_prefix(urls.XUL_VOLUME_EDITOR),
740             title,
741             'chrome,modal,resizable',
742             { 'volumes' : clone_list( fleshed_volumes ) }
743         );
744
745         if (typeof my_xulG.update_these_volumes == 'undefined') { return false; }
746
747         var volumes = util.functional.filter_list(
748             my_xulG.volumes,
749             function(v) {
750                 return get_bool( v.ischanged() );
751             }
752         );
753
754         if (volumes.length < 1) { return false; }
755
756         volumes = util.functional.map_list( volumes, function(o){
757             if (typeof o.suffix() == 'object') { o.suffix( o.suffix().id() ); }
758             if (typeof o.prefix() == 'object') { o.prefix( o.prefix().id() ); }
759             if (typeof o.label_class() == 'object') { o.label_class( o.label_class().id() ); }
760             return o;
761         });
762
763         var r = net.simple_request(
764             'FM_ACN_TREE_UPDATE',
765             [ ses(), volumes, false, { 'auto_merge_vols' : my_xulG.auto_merge } ],
766             null,
767             {
768                 'title' : document.getElementById('catStrings').getString('staff.cat.edit_volumes.override.confirm'),
769                 'overridable_events' : [
770                     1705 /* VOLUME_LABEL_EXISTS */
771                 ],
772                 'text' : {
773                     '1705' : function(r) {
774                         var payload_acn = util.functional.find_id_object_in_list( volumes, r.payload );
775                         return document.getElementById('catStrings').getFormattedString('staff.cat.edit_volumes.label_exists.details',[payload_acn.label()]);
776                     }
777                 }
778             }
779         );
780         if (!r) { throw('Update method returned null or false.'); }
781         if (typeof r.ilsevent != 'undefined') {
782             if (r.ilsevent == 1705 /* VOLUME_LABEL_EXISTS */) {
783                /* not overriden, but otherwise handled, so ignore */
784                 return false;
785             } else {
786                 throw(r);
787             }
788         }
789
790         return true;
791
792     } catch(E) {
793         alert('Error in cat.util.batch_edit_volumes: ' + E);
794         return false;
795     }
796 }
797
798 cat.util.render_fine_level = function(value) {
799     var text;
800     switch(Number(value)){
801         case 1: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.low"); break;
802         case 2: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.normal"); break;
803         case 3: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.high"); break; 
804     }
805     return text;
806 }
807 cat.util.render_loan_duration = function(value) {
808     var text;
809     switch(Number(value)){
810         case 1: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.short"); break;
811         case 2: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.normal"); break;
812         case 3: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.extended"); break;
813     }
814     return text;
815 }
816
817 cat.util.mark_item_as_missing_pieces = function(copy_ids) {
818     var error;
819     try {
820         JSAN.use('util.error'); error = new util.error();
821         JSAN.use('util.functional'); JSAN.use('util.date');
822         JSAN.use('util.network'); var network = new util.network();
823         JSAN.use('util.print'); var print = new util.print();
824         JSAN.use('util.window'); var win = new util.window();
825         if (!copy_ids) { return; }
826         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
827         if (copy_ids.length < 1) { return; }
828         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
829         if (typeof copies.ilsevent != 'undefined') throw(copies);
830
831         var r = error.yns_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.ms_message', [util.functional.map_list( copies, function(o) { return o.barcode(); } ).join(", ")]),
832             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_title'),
833             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_ok_label'),
834             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_cancel_label'), null,
835             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_confirm_action'));
836
837         if (r == 0) {
838             var count = 0;
839             JSAN.use('cat.util');
840             for (var i = 0; i < copies.length; i++) {
841                 try {
842                     var robj = network.simple_request('MARK_ITEM_MISSING_PIECES',[ses(),copies[i].id()]);
843                     if (typeof robj.ilsevent != 'undefined') {
844                         if (robj.ilsevent == 0 /* SUCCESS */) {
845                             count++;
846                             // Print Slip
847                             if (robj.payload && robj.payload.slip) {
848                                 print.simple( robj.payload.slip.template_output().data() );
849                             }
850                             // Item Note
851                             cat.util.spawn_copy_editor( { 'copy_ids' : [ copies[i].id() ], 'edit' : 1 } );
852                             // Patron Message
853                             var my_xulG = win.open(
854                                 urls.XUL_NEW_STANDING_PENALTY,
855                                 'new_standing_penalty',
856                                 'chrome,resizable,modal',
857                                 {}
858                             );
859                             if (my_xulG.id) {
860                                 var penalty = new ausp();
861                                 penalty.usr( robj.payload.circ.usr() );
862                                 penalty.isnew( 1 );
863                                 penalty.standing_penalty( my_xulG.id );
864                                 penalty.org_unit( ses('ws_ou') );
865                                 penalty.note( my_xulG.note );
866                                 network.simple_request(
867                                     'FM_AUSP_APPLY',
868                                     [ ses(), penalty ]
869                                 );
870                             }
871                             // Patron Letter
872
873                             var txt_file = new util.file('letter.txt');
874                             txt_file.write_content('truncate',robj.payload.letter.template_output().data());
875                             var text_path = '"' + txt_file._file.path + '"';
876                             txt_file.close();
877
878                             var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces['nsIPrefBranch']);
879                             var key = 'oils.text_editor.external.cmd';
880                             var has_key = prefs.prefHasUserValue(key);
881                             var oils_external_letter_opener_cmd = has_key ? prefs.getCharPref(key) : 'C:\\Windows\\notepad.exe %letter.txt%';
882
883                             var cmd = oils_external_letter_opener_cmd.replace('%letter.txt%',text_path);
884
885                             var file = new util.file('letter.bat');
886                             file.write_content('truncate+exec',cmd);
887                             file.close();
888                             file = new util.file('letter.bat');
889
890                             dump('letter exec: ' + cmd + '\n');
891                             var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
892                             process.init(file._file);
893
894                             var args = [];
895
896                             dump('process.run = ' + process.run(false, args, args.length) + '\n');
897
898                             file.close();
899
900                         } else if (robj.ilsevent == 1500 /* ACTION_CIRCULATION_NOT_FOUND */) {
901                             alert( $("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.circ_not_found',[ copies[i].barcode() ]) );
902                         } else {
903                             throw(robj);
904                         }
905                     } else {
906                         throw(robj);
907                     }
908                 } catch(E) {
909                     error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.marking_error', [copies[i].barcode()]),E);
910                 }
911             }
912             /*alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.one_item_missing_pieces') :
913                 $("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.multiple_item_missing_pieces', [count]));*/
914         }
915
916         return true;
917     } catch(E) {
918         alert('Error in cat.util.mark_item_as_missing_pieces: ' + E);
919         return false;
920     }
921 }
922
923 cat.util.render_callnumbers_for_bib_menu = function(node, doc_id, label_class) {
924     try {
925         var cn_blob;
926         try {
927             cn_blob = g.network.simple_request('BLOB_MARC_CALLNUMBERS_RETRIEVE',[doc_id, label_class]);
928         } catch(E) {
929             cn_blob = [];
930         }
931         var hbox = typeof node == 'string' ? document.getElementById(node) : node;
932         JSAN.use('util.widgets');
933         JSAN.use('util.functional');
934         var ml = util.widgets.make_menulist(
935             [
936                 [ '', '' ]
937             ].concat(
938                 util.functional.map_list(
939                     cn_blob,
940                     function(o) {
941                         for (var i in o) {
942                             return [ o[i], i ];
943                         }
944                     }
945                 )
946             )
947         ); hbox.appendChild(ml);
948         ml.setAttribute('editable','true');
949         ml.setAttribute('width', '200');
950         ml.setAttribute('id', hbox.id + '_menulist');
951     } catch(E) {
952         alert('Error in cat.util.render_callnumbers_for_bib_menu: ' + E);
953     }
954 }
955
956 cat.util.render_cn_prefix_menuitems = function(menupopup,ou_id) {
957     try {
958         JSAN.use('OpenILS.data');
959         var data = new OpenILS.data(); data.stash_retrieve();
960         JSAN.use('util.network');
961         var network = new util.network();
962
963         if (typeof data.list['acnp_for_lib_'+ou_id] == 'undefined') {
964             data.list['acnp_for_lib_'+ou_id] = network.simple_request(
965                 'FM_ACNP_RETRIEVE_VIA_PCRUD',
966                 [ ses(), {"owning_lib":{"=":ou_id}}, {"order_by":{"acnp":"label_sortkey"}} ]
967             );
968             data.stash('list');
969         }
970         for (var i = 0; i < data.list['acnp_for_lib_'+ou_id].length; i++) {
971             var my_acnp = data.list['acnp_for_lib_'+ou_id][i];
972             var menuitem = document.createElement('menuitem');
973             menupopup.appendChild(menuitem);
974                 menuitem.setAttribute(
975                     'label',
976                     my_acnp.id() == -1 ? '' :
977                     $('catStrings').getFormattedString(
978                         'staff.cat.volume_copy_creator.call_number_prefix.menuitem_label',
979                         [
980                             my_acnp.label(),
981                             data.hash.aou[ ou_id ].shortname()
982                         ]
983                     )
984                 );
985                 menuitem.setAttribute('value',my_acnp.id());
986         }
987     } catch(E) {
988         alert('Error in cat.util.render_cn_prefix_menuitems: ' + E);
989     }
990 }
991
992 cat.util.render_cn_suffix_menuitems = function(menupopup,ou_id) {
993     try {
994         JSAN.use('OpenILS.data');
995         var data = new OpenILS.data(); data.stash_retrieve();
996         JSAN.use('util.network');
997         var network = new util.network();
998
999         if (typeof data.list['acns_for_lib_'+ou_id] == 'undefined') {
1000             data.list['acns_for_lib_'+ou_id] = network.simple_request(
1001                 'FM_ACNS_RETRIEVE_VIA_PCRUD',
1002                 [ ses(), {"owning_lib":{"=":ou_id}}, {"order_by":{"acns":"label_sortkey"}} ]
1003             );
1004             data.stash('list');
1005         }
1006         for (var i = 0; i < data.list['acns_for_lib_'+ou_id].length; i++) {
1007             var my_acns = data.list['acns_for_lib_'+ou_id][i];
1008             var menuitem = document.createElement('menuitem');
1009             menupopup.appendChild(menuitem);
1010                 menuitem.setAttribute(
1011                     'label',
1012                     my_acns.id() == -1 ? '' :
1013                     $('catStrings').getFormattedString(
1014                         'staff.cat.volume_copy_creator.call_number_suffix.menuitem_label',
1015                         [
1016                             my_acns.label(),
1017                             data.hash.aou[ ou_id ].shortname()
1018                         ]
1019                     )
1020                 );
1021                 menuitem.setAttribute('value',my_acns.id());
1022         }
1023     } catch(E) {
1024         alert('Error in cat.util.render_cn_suffix_menuitems: ' + E);
1025     }
1026 }
1027
1028 cat.util.render_cn_class_menu = function(extra_menuitems,menu_default) {
1029     try {
1030         JSAN.use('util.widgets');
1031         JSAN.use('OpenILS.data');
1032         var data = new OpenILS.data(); data.stash_retrieve();
1033
1034         var menulist = util.widgets.make_menulist(
1035             (extra_menuitems || []).concat(
1036                 util.functional.map_list(
1037                     data.list.acnc,
1038                     function(o) {
1039                         return [ o.name(), o.id() ];
1040                     }
1041                 )
1042             )
1043         );
1044
1045         if (typeof menu_default != 'undefined') {
1046             menulist.setAttribute('value',menu_default);
1047         }
1048         return menulist;
1049
1050     } catch(E) {
1051         alert('Error in cat.util.render_cn_class_menu: ' + E);
1052     }
1053 }
1054
1055 cat.util.render_cn_prefix_menu = function(ou_ids,extra_menuitems,menu_default) {
1056     try {
1057         JSAN.use('util.widgets');
1058         var menulist = util.widgets.make_menulist(extra_menuitems||[],menu_default);
1059             var menupopup = menulist.firstChild;
1060             var org_list;
1061             if (ou_ids.length == 1) {
1062                 JSAN.use('OpenILS.data');
1063                 var data = new OpenILS.data(); data.stash_retrieve();
1064                 var org = data.hash.aou[ ou_ids[0] ];
1065                 org_list = []; // order from top of consortium to owning lib
1066                 while(org) {
1067                     org_list.unshift(org.id());
1068                     org = org.parent_ou();
1069                     if (org && typeof org != 'object') {
1070                         org = data.hash.aou[ org ];
1071                     }
1072                 }
1073             } else {
1074                 org_list = ou_ids;
1075             }
1076             for (var i = 0; i < org_list.length; i++) {
1077                 cat.util.render_cn_prefix_menuitems(menupopup,org_list[i]);
1078             }
1079         if (typeof menu_default != 'undefined') {
1080             menulist.setAttribute('value',menu_default);
1081         }
1082         return menulist;
1083     } catch(E) {
1084         alert('Error in cat.util.render_cn_prefix_menu('+ou_id+'): ' + E);
1085     }
1086 }
1087
1088 cat.util.render_cn_suffix_menu = function(ou_ids,extra_menuitems,menu_default) {
1089     try {
1090         JSAN.use('util.widgets');
1091         var menulist = util.widgets.make_menulist(extra_menuitems||[],menu_default);
1092             var menupopup = menulist.firstChild;
1093             var org_list;
1094             if (ou_ids.length == 1) {
1095                 JSAN.use('OpenILS.data');
1096                 var data = new OpenILS.data(); data.stash_retrieve();
1097                 var org = data.hash.aou[ ou_ids[0] ];
1098                 org_list = []; // order from top of consortium to owning lib
1099                 while(org) {
1100                     org_list.unshift(org.id());
1101                     org = org.parent_ou();
1102                     if (org && typeof org != 'object') {
1103                         org = data.hash.aou[ org ];
1104                     }
1105                 }
1106             } else {
1107                 org_list = ou_ids;
1108             }
1109             for (var i = 0; i < org_list.length; i++) {
1110                 cat.util.render_cn_suffix_menuitems(menupopup,org_list[i]);
1111             }
1112         if (typeof menu_default != 'undefined') {
1113             menulist.setAttribute('value',menu_default);
1114         }
1115         return menulist;
1116     } catch(E) {
1117         alert('Error in cat.util.render_cn_suffix_menu('+ou_id+'): ' + E);
1118     }
1119 }
1120
1121 dump('exiting cat/util.js\n');