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