]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/xul/staff_client/server/cat/util.js
Saner behavior for Actions for Selected Holds -> Transfer to Marked Title
[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', 'transfer_specific_title_holds'
13 ];
14 cat.util.EXPORT_TAGS    = { ':all' : cat.util.EXPORT_OK };
15
16 cat.util.replace_barcode = function(old_bc) {
17     try {
18         JSAN.use('util.network');
19         var network = new util.network();
20
21         if (!old_bc) old_bc = window.prompt($("catStrings").getString('staff.cat.util.replace_barcode.old_bc_window_prompt.prompt'),
22             '',
23             $("catStrings").getString('staff.cat.util.replace_barcode.old_bc_window_prompt.title'));
24         if (!old_bc) return;
25
26         var copy;
27         try {
28             copy = network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ old_bc ]);
29             if (typeof copy.ilsevent != 'undefined') throw(copy); 
30             if (!copy) throw(copy);
31         } catch(E) {
32             alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.error_alert', [old_bc]) + '\n');
33             return old_bc;
34         }
35     
36         // Why did I want to do this twice?  Because this copy is more fleshed?
37         try {
38             copy = network.simple_request('FM_ACP_RETRIEVE',[ copy.id() ]);
39             if (typeof copy.ilsevent != 'undefined') throw(copy);
40             if (!copy) throw(copy);
41         } catch(E) {
42             try {
43                 alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.error_alert', [old_bc]) +
44                      '\n' + (typeof E.ilsevent == 'undefined' ? '' : E.textcode + ' : ' + E.desc));
45             } catch(F) {
46                 alert(E + '\n' + F);
47             }
48             return old_bc;
49         }
50     
51         var new_bc = window.prompt($("catStrings").getString('staff.cat.util.replace_barcode.new_bc_window_prompt.prompt'),
52             '',
53             $("catStrings").getString('staff.cat.util.replace_barcode.new_bc_window_prompt.title'));
54         new_bc = String( new_bc ).replace(/\s/g,'');
55         /* Casting a possibly null input value to a String turns it into "null" */
56         if (!new_bc || new_bc == 'null') {
57             alert($("catStrings").getString('staff.cat.util.replace_barcode.new_bc.failed'));
58             return old_bc;
59         }
60     
61         var test = network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ new_bc ]);
62         if (typeof test.ilsevent == 'undefined') {
63             alert('Rename aborted.  Another copy has barcode "' + new_bc + '".');
64             return old_bc;
65         } else {
66             if (test.ilsevent != 1502 /* ASSET_COPY_NOT_FOUND */) {
67                 obj.error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.replace_barcode.testing_error', [new_bc]), test);
68                 return old_bc;
69             }    
70         }
71
72         copy.barcode(new_bc); copy.ischanged('1');
73         var r = network.simple_request('FM_ACP_FLESHED_BATCH_UPDATE', [ ses(), [ copy ] ]);
74         if (typeof r.ilsevent != 'undefined') { 
75             if (r.ilsevent != 0) {
76                 if (r.ilsevent == 5000 /* PERM_FAILURE */) {
77                     alert($("catStrings").getString('staff.cat.util.replace_barcode.insufficient_permission_for_rename'));
78                     return old_bc;
79                 } else {
80                     obj.error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.replace_barcode.item_rename_error'),r);
81                     return old_bc;
82                 }
83             }
84         }
85
86         return new_bc;
87     } catch(E) {
88         JSAN.use('util.error'); var error = new util.error();
89         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.replace_barcode.rename_error'),E);
90         return old_bc;
91     }
92 }
93
94 cat.util.transfer_title_holds = function(old_targets) {
95     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
96     JSAN.use('util.network'); var network = new util.network();
97     try {
98         data.stash_retrieve();
99         var target = data.marked_record_for_hold_transfer;
100         if (!target) {
101             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.destination_needed.label');
102             alert(m);
103             return;
104         }
105         var robj = network.simple_request('TRANSFER_TITLE_HOLDS',[ ses(), target, old_targets ]);
106         if (robj == 1) {
107             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.success.label');
108             alert(m);
109         } else {
110             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.failure.label');
111             alert(m);
112         }
113     } catch(E) {
114         alert('Error in cat.util.transfer_title.holds(): ' + E);
115     }
116 }
117
118 cat.util.transfer_specific_title_holds = function(hold_ids,unique_targets) {
119     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
120     JSAN.use('util.network'); var network = new util.network();
121     try {
122         data.stash_retrieve();
123         var target = data.marked_record_for_hold_transfer;
124         if (!target) {
125             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.destination_needed.label');
126             alert(m);
127             return;
128         }
129         if (unique_targets.length > 1) {
130             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.many_bibs.warning');
131             if (! window.confirm(m)) {
132                 return;
133             }
134         }
135         var robj = network.simple_request('TRANSFER_SPECIFIC_TITLE_HOLDS',[ ses(), target, hold_ids ]);
136         if (robj == 1) {
137             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.success.label');
138             alert(m);
139         } else {
140             var m = $("catStrings").getString('staff.cat.opac.title_for_hold_transfer.failure.label');
141             alert(m);
142         }
143     } catch(E) {
144         alert('Error in cat.util.transfer_title.holds(): ' + E);
145     }
146 }
147
148
149 cat.util.transfer_copies = function(params) {
150     JSAN.use('util.error'); var error = new util.error();
151     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
152     JSAN.use('util.network'); var network = new util.network();
153     try {
154         data.stash_retrieve();
155         if (!data.marked_volume) {
156             alert($("catStrings").getString('staff.cat.util.transfer_copies.unmarked_volume_alert'));
157             return;
158         }
159         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect UniversalBrowserWrite');
160         var xml = '<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" flex="1" style="overflow: auto">';
161         if (!params.message) {
162             params.message = $("catStrings").getFormattedString('staff.cat.util.transfer_copies.params_message', [data.hash.aou[ params.owning_lib ].shortname(), params.volume_label]);
163             //params.message = 'Transfer items from their original volumes to ';
164             //params.message += data.hash.aou[ params.owning_lib ].shortname() + "'s volume labelled ";
165             //params.message += '"' + params.volume_label + '" on the following record (and change their circ libs to match)?';
166         }
167
168         xml += '<description>' + params.message.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') + '</description>';
169         xml += '<hbox><button label="' + $("catStrings").getString('staff.cat.util.transfer_copies.transfer.label')+ '" name="fancy_submit"/>';
170         xml += '<button label="' + $("catStrings").getString('staff.cat.util.transfer_copies.cancel.label');
171         xml += '" accesskey="'+ $("catStrings").getString('staff.cat.util.transfer_copies.cancel.accesskey') +'" name="fancy_cancel"/></hbox>';
172         xml += '<iframe style="overflow: scroll" flex="1" src="' + urls.XUL_BIB_BRIEF + '?docid=' + params.docid + '"/>';
173         xml += '</vbox>';
174         //data.temp_transfer = xml; data.stash('temp_transfer');
175         JSAN.use('util.window'); var win = new util.window();
176         var fancy_prompt_data = win.open(
177             urls.XUL_FANCY_PROMPT,
178             //+ '?xml_in_stash=temp_transfer'
179             //+ '&title=' + window.escape('Item Transfer'),
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 copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ params.copy_ids ]);
188
189         for (var i = 0; i < copies.length; i++) {
190             copies[i].call_number( data.marked_volume );
191             copies[i].circ_lib( params.owning_lib );
192             copies[i].ischanged( 1 );
193         }
194
195         var robj = network.simple_request(
196             'FM_ACP_FLESHED_BATCH_UPDATE', 
197             [ ses(), copies, true ], 
198             null,
199             {
200                 'title' : $("catStrings").getString('staff.cat.util.transfer_copies.override_transfer_failure'),
201                 'overridable_events' : [
202                     1208 /* TITLE_LAST_COPY */,
203                     1227 /* COPY_DELETE_WARNING */,
204                 ]
205             }
206         );
207         
208         if (typeof robj.ilsevent != 'undefined') {
209             throw(robj);
210         } else {
211             alert($("catStrings").getString('staff.cat.util.transfer_copies.successful_transfer'));
212         }
213
214     } catch(E) {
215         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.transfer_copies.transfer_error'),E);
216     }
217 }
218
219 cat.util.spawn_spine_editor = function(selection_list) {
220     JSAN.use('util.error'); var error = new util.error();
221     try {
222         JSAN.use('util.functional');
223         xulG.new_tab(
224             xulG.url_prefix( urls.XUL_SPINE_LABEL ),
225             { 'tab_name' : $("catStrings").getString('staff.cat.util.spine_editor.tab_name') },
226             {
227                 'barcodes' : util.functional.map_list( selection_list, function(o){return o.barcode;}) 
228             }
229         );
230     } catch(E) {
231         error.standard_unexpected_error_alert($("catStrings").getString('staff.cat.util.spine_editor.spine_editor_error'),E);
232     }
233 }
234
235 cat.util.show_in_opac = function(selection_list) {
236     JSAN.use('util.error'); var error = new util.error();
237     JSAN.use('util.network'); var network = new util.network();
238     var doc_id; var seen = {};
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( urls.opac_rdetail ) + '?r=' + doc_id;
258             var content_params = { 
259                 'session' : ses(),
260                 'authtime' : ses('authtime'),
261                 'opac_url' : opac_url,
262             };
263             xulG.new_tab(
264                 xulG.url_prefix(urls.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(urls.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     win.open(
301         xulG.url_prefix(urls.XUL_RECORD_BUCKETS_QUICK),
302         '_blank',
303         'chrome,resizable,modal,center',
304         {
305             record_ids: record_ids 
306         }
307     );
308 }
309
310 cat.util.spawn_copy_editor = function(params) {
311     try {
312         if (!params.copy_ids && !params.copies) return;
313         if (params.copy_ids && params.copy_ids.length == 0) return;
314         if (params.copies && params.copies.length == 0) return;
315         if (params.copy_ids) params.copy_ids = js2JSON(params.copy_ids); // legacy
316         if (!params.caller_handles_update) params.handle_update = 1; // legacy
317
318         var obj = {};
319         JSAN.use('util.network'); obj.network = new util.network();
320         JSAN.use('util.error'); obj.error = new util.error();
321     
322         var title = '';
323         if (params.copy_ids && params.copy_ids.length > 1 && params.edit == 1)
324             title = $("catStrings").getString('staff.cat.util.copy_editor.batch_edit');
325         else if(params.copies && params.copies.length > 1 && params.edit == 1)
326             title = $("catStrings").getString('staff.cat.util.copy_editor.batch_view');
327         else if(params.copy_ids && params.copy_ids.length == 1)
328             title = $("catStrings").getString('staff.cat.util.copy_editor.edit');
329         else
330             title = $("catStrings").getString('staff.cat.util.copy_editor.view');
331
332         JSAN.use('util.window'); var win = new util.window();
333         var my_xulG = win.open(
334             (urls.XUL_COPY_EDITOR),
335             title,
336             'chrome,modal,resizable',
337             params
338         );
339         if (!my_xulG.copies && params.edit) {
340         } else {
341             return my_xulG.copies;
342         }
343         return [];
344     } catch(E) {
345         JSAN.use('util.error'); var error = new util.error();
346         error.standard_unexpected_error_alert('error in cat.util.spawn_copy_editor',E);
347     }
348 }
349
350 cat.util.mark_item_damaged = function(copy_ids) {
351     var error;
352     try {
353         JSAN.use('util.error'); error = new util.error();
354         JSAN.use('util.functional'); JSAN.use('util.date');
355         JSAN.use('util.network'); var network = new util.network();
356         if (!copy_ids) { return; }
357         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
358         if (copy_ids.length < 1) { return; }
359         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
360         if (typeof copies.ilsevent != 'undefined') throw(copies);
361         var magic_status = false;
362         for (var i = 0; i < copies.length; i++) {
363             var status = copies[i].status(); if (typeof status == 'object') status = status.id();
364             if (typeof my_constants.magical_statuses[ status ] != 'undefined') 
365                 if (my_constants.magical_statuses[ status ].block_mark_item_damaged) magic_status = true;
366         }
367         if (magic_status) {
368         
369             error.yns_alert($("catStrings").getString('staff.cat.util.mark_item_damaged.af_message'),
370                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_title'),
371                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_ok_label'), null, null,
372                 $("catStrings").getString('staff.cat.util.mark_item_damaged.af_confirm_action'));
373
374         } else {
375
376             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(", ")]),
377                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_title'),
378                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_ok_label'),
379                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_cancel_label'), null,
380                 $("catStrings").getString('staff.cat.util.mark_item_damaged.md_confirm_action'));
381
382             if (r == 0) {
383                 var count = 0;
384                 for (var i = 0; i < copies.length; i++) {
385                     try {
386
387                         var my_circ = network.simple_request('FM_CIRC_RETRIEVE_VIA_COPY',[ses(),copies[i].id(),1]);
388                         if (typeof my_circ.ilsevent == 'undefined') { 
389                             JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.stash_retrieve();
390                             my_circ = my_circ[0];
391                             if (typeof my_circ != 'undefined') {
392                                 if (! my_circ.checkin_time() ) {
393                                     var due_date = my_circ.due_date() ? util.date.formatted_date( my_circ.due_date(), '%F' ) : null;
394                                     var auto_checkin = String( data.hash.aous['circ.auto_checkin_on_mark_damage'] ) == 'true';
395                                     /* 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. */
396                                     auto_checkin = true; 
397                                     JSAN.use('patron.util');
398                                     var patron_obj = patron.util.retrieve_fleshed_au_via_id( ses(), my_circ.usr() );
399                                     var patron_name = patron.util.format_name( patron_obj ) + ' : ' + patron_obj.card().barcode();
400                                     var msg = $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.item_circulating_to_patron', [ 
401                                         copies[i].barcode(),
402                                         patron_name,
403                                         util.date.formatted_date( my_circ.due_date(), '%{localized}' )]);
404                                     JSAN.use('util.date'); var today = util.date.formatted_date(new Date(),'%F');
405                                     var r2 = auto_checkin ? 1 : error.yns_alert(
406                                         msg,
407                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.title'),
408                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.no_checkin'),
409                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.normal_checkin'),
410                                         due_date ? (today > due_date ? document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.forgiving_checkin') : null) : null,
411                                         document.getElementById('catStrings').getString('staff.cat.util.mark_item_damaged.checkin.confirm_action')
412                                     );
413                                     JSAN.use('circ.util');
414                                     switch(r2) {
415                                         case 1:
416                                             circ.util.checkin_via_barcode( ses(), { 'barcode' : copies[i].barcode(), 'noop' : 1 } );
417                                         break;
418                                         case 2:
419                                             circ.util.checkin_via_barcode( ses(), { 'barcode' : copies[i].barcode(), 'noop' : 1 }, due_date );
420                                         break;
421                                     }
422                                 }
423                             }
424                         }
425
426                         var robj = network.simple_request('MARK_ITEM_DAMAGED',[ses(),copies[i].id()]);
427                         if (typeof robj.ilsevent != 'undefined') {
428                             switch(robj.textcode) {
429                                 case 'DAMAGE_CHARGE' :
430                                     var params = {};
431                                     JSAN.use('util.money');
432                                     var circ_obj = robj.payload.circ;
433                                     var patron_obj = circ_obj.usr();
434                                     JSAN.use('patron.util'); 
435                                     var patron_name = patron.util.format_name( patron_obj ) + ' : ' + patron_obj.card().barcode(); 
436                                     var r1 = error.yns_alert( 
437                                         $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.charge_patron_prompt.message', [  
438                                             copies[i].barcode(),  
439                                             patron_name,  
440                                             util.date.formatted_date( circ_obj.checkin_time(), '%{localized}' ),
441                                             util.money.sanitize(robj.payload.charge) ]), 
442                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.title'), 
443                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.ok_label'), 
444                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.change_amount_label'), 
445                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.cancel_label'), 
446                                         $("catStrings").getString('staff.cat.util.mark_item_damaged.charge_patron_prompt.confirm_action')); 
447                                     if (r1 == 0) {
448                                         params.apply_fines = 'apply';
449                                     } else if (r1 == 1) { 
450                                         JSAN.use('util.window'); var win = new util.window();
451                                         var my_xulG = win.open(
452                                             urls.XUL_PATRON_BILL_WIZARD,
453                                             'billwizard',
454                                             'chrome,resizable,modal',
455                                             { 
456                                                 'patron' : patron_obj, 
457                                                 'patron_id' : patron_obj.id(), 
458                                                 'circ' : circ_obj, 
459                                                 'xact_id' : circ_obj.id(), 
460                                                 'do_not_process_bill' : true,
461                                                 /* 'override_default_billing_type' : 7, FIXME: maybe reintroduce this with an org setting for the specific btype? */
462                                                 'override_default_price' : util.money.sanitize( robj.payload.charge ) 
463                                             }
464                                         );
465
466                                         params.apply_fines = my_xulG.proceed ? 'apply' : 'noapply';
467                                         if (my_xulG.proceed) {
468                                             params.override_amount = my_xulG.amount;
469                                             params.override_btype = my_xulG.cbt_id;
470                                             params.override_note = my_xulG.note;
471                                         }
472                                     } else {
473                                         params.apply_fines = 'noapply';
474                                     }
475                                     robj = network.simple_request('MARK_ITEM_DAMAGED',[ ses(), copies[i].id(), params ]);
476                                     if (typeof robj.ilsevent != 'undefined') { throw(robj); }
477                                     break;
478                                 default: throw(robj);
479                             }
480                         }
481                         count++;
482                     } catch(E) {
483                         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.marking_error', [copies[i].barcode()]),E);
484                     }
485                 }
486                 alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_damaged.one_item_damaged') :
487                     $("catStrings").getFormattedString('staff.cat.util.mark_item_damaged.multiple_item_damaged', [count]));
488             }
489         }
490
491     } catch(E) {
492         if (error) error.standard_unexpected_error_alert('cat.util.mark_item_damaged',E); else alert('FIXME: ' + E);
493     }
494 }
495
496 cat.util.mark_item_missing = function(copy_ids) {
497     var error;
498     try {
499         JSAN.use('util.error'); error = new util.error();
500         JSAN.use('util.functional');
501         JSAN.use('util.network'); var network = new util.network();
502         if (!copy_ids) { return; }
503         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
504         if (copy_ids.length < 1) { return; }
505         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
506         if (typeof copies.ilsevent != 'undefined') throw(copies);
507         var magic_status = false;
508         for (var i = 0; i < copies.length; i++) {
509             var status = copies[i].status(); if (typeof status == 'object') status = status.id();
510             if (typeof my_constants.magical_statuses[ status ] != 'undefined') 
511                 if (my_constants.magical_statuses[ status ].block_mark_item_action) magic_status = true;
512         }
513         if (magic_status) {
514         
515             error.yns_alert($("catStrings").getString('staff.cat.util.mark_item_missing.af_message'),
516                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_title'),
517                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_ok_label'), null, null,
518                 $("catStrings").getString('staff.cat.util.mark_item_missing.af_confirm_action'));
519
520         } else {
521
522             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(", ")]),
523                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_title'),
524                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_ok_label'),
525                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_cancel_label'), null,
526                 $("catStrings").getString('staff.cat.util.mark_item_missing.ms_confirm_action'));
527
528             if (r == 0) {
529                 var count = 0;
530                 for (var i = 0; i < copies.length; i++) {
531                     try {
532                         var robj = network.simple_request('MARK_ITEM_MISSING',[ses(),copies[i].id()]);
533                         if (typeof robj.ilsevent != 'undefined') throw(robj);
534                         count++;
535                     } catch(E) {
536                         error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing.marking_error', [copies[i].barcode()]),E);
537                     }
538                 }
539                 alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_missing.one_item_missing') :
540                     $("catStrings").getFormattedString('staff.cat.util.mark_item_missing.multiple_item_missing', [count]));
541             }
542         }
543
544     } catch(E) {
545         if (error) error.standard_unexpected_error_alert('cat.util.mark_item_missing',E); else alert('FIXME: ' + E);
546     }
547 }
548
549 cat.util.fast_item_add = function(doc_id,cn_label,cp_barcode) {
550     var error;
551     JSAN.use('OpenILS.data'); var data = new OpenILS.data();
552     try {
553
554         JSAN.use('util.error'); error = new util.error();
555         JSAN.use('util.network'); var network = new util.network();
556
557         var acn_blob = network.simple_request(
558             'FM_ACN_FIND_OR_CREATE',
559             [ ses(), cn_label, doc_id, ses('ws_ou') ]
560         );
561
562         if (typeof acn_blob.ilsevent != 'undefined') {
563             error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.volume_copy_creator.stash_and_close.problem_with_volume', [cn]), acn_blob);
564             return;
565         }
566
567         // Get the default copy status; default to available if unset, per 1.6
568         var fast_ccs = data.hash.aous['cat.default_copy_status_fast'] || 0;
569
570         var copy_obj = new acp();
571         copy_obj.id( -1 );
572         copy_obj.isnew('1');
573         copy_obj.barcode( cp_barcode );
574         copy_obj.call_number( acn_blob.acn_id );
575         copy_obj.circ_lib( ses('ws_ou') );
576         /* FIXME -- use constants */
577         copy_obj.deposit(0);
578         copy_obj.price(0);
579         copy_obj.deposit_amount(0);
580         copy_obj.fine_level(2); // Normal
581         copy_obj.loan_duration(2); // Normal
582         copy_obj.location(1); // Stacks
583         copy_obj.status(fast_ccs);
584         copy_obj.circulate(get_db_true());
585         copy_obj.holdable(get_db_true());
586         copy_obj.opac_visible(get_db_true());
587         copy_obj.ref(get_db_false());
588
589         JSAN.use('util.window'); var win = new util.window();
590         JSAN.use('cat.util');
591
592         var unified_interface = String( data.hash.aous['ui.unified_volume_copy_editor'] ) == 'true';
593         if (unified_interface) {
594             var horizontal_interface = String( data.hash.aous['ui.cat.volume_copy_editor.horizontal'] ) == 'true';
595             var url = window.xulG.url_prefix( horizontal_interface ? urls.XUL_VOLUME_COPY_CREATOR_HORIZONTAL : urls.XUL_VOLUME_COPY_CREATOR );
596             var w = xulG.set_tab(
597                 url,
598                 {
599                     'tab_name' : document.getElementById('offlineStrings').getFormattedString(
600                         'cat.bib_record',
601                         [ doc_id ]
602                     )
603                 },
604                 {
605                     'doc_id' : doc_id, 
606                     'existing_copies' : [ copy_obj ],
607                     'load_opac_when_done' : true,
608                     'labels_in_new_tab' : true
609                 }
610             );
611
612         } else {
613             return cat.util.spawn_copy_editor( { 'handle_update' : 1, 'edit' : 1, 'docid' : doc_id, 'copies' : [ copy_obj ] });
614         }
615
616     } catch(E) {
617         if (error) error.standard_unexpected_error_alert('cat.util.fast_item_add',E); else alert('FIXME: ' + E);
618     }
619 }
620
621 cat.util.make_bookable = function(copy_ids) {
622     if (!copy_ids) { return; }
623     copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
624     if (copy_ids.length < 1) { return; }
625     var results = fieldmapper.standardRequest(
626         ["open-ils.booking", "open-ils.booking.resources.create_from_copies"],
627         [ses(), copy_ids]
628     );
629     if (results == null) {
630         alert(document.getElementById("catStrings").getString(
631             "staff.cat.copy_browser.make_bookable.create_failed_silent"
632         ));
633     }
634     else if (typeof results.ilsevent != "undefined") {
635         alert(document.getElementById("catStrings").getFormattedString(
636             "staff.cat.copy_browser.make_bookable.create_failed",
637             [results.ilsevent, results.textcode, results.desc, results.debug]
638         ));
639     }
640     return results;
641 }
642
643 cat.util.edit_new_brsrc = function(brsrc_list) {
644     /* Spawn new tab to allow editing new resources. */
645     try {
646         xulG.resultant_brsrc = brsrc_list.map(function(o) { return o[0]; });
647         xulG.new_tab(
648             urls.XUL_BROWSER + "?url=" + window.escape(
649                 xulG.url_prefix("/eg/conify/global/booking/resource")
650             ), {
651                 "tab_name": offlineStrings.getString(
652                     "menu.cmd_booking_resource.tab"
653                  ),
654                 "browser" : true
655             }, {
656                 "no_xulG": false,
657                 "show_print_button": false,
658                 "show_nav_buttons": true,
659                 "passthru_content_params": xulG
660             }
661         );
662     } catch(E) {
663         alert(
664             document.getElementById("catStrings").getFormattedString(
665                 "staff.cat.copy_browser.make_bookable.newtab_failed"
666             ), E
667         );
668     }
669 }
670
671 cat.util.edit_new_bresv = function(booking_results) {
672     /* Spawn new tab to allow editing new reservations. */
673     try {
674         if (xulG.auth == undefined) {
675             xulG.auth = {"session": {"key": ses()}};
676         }
677         xulG.bresv_interface_opts = {"booking_results": booking_results};
678         xulG.new_tab(
679             xulG.url_prefix("/eg/booking/reservation"),
680             {
681                 "tab_name": offlineStrings.getString(
682                     "menu.cmd_booking_reservation.tab"
683                  ),
684                 "browser" : false
685             }, xulG
686         );
687     } catch(E) {
688         alert(
689             document.getElementById("catStrings").getString(
690                 "staff.cat.copy_browser.make_bookable.newtab_failed"
691             ) + E
692         );
693     }
694 }
695
696 cat.util.batch_edit_volumes = function(fleshed_volumes) {
697     try {
698         if (!fleshed_volumes || fleshed_volumes.length < 1) { return false; }
699
700         JSAN.use('util.functional');
701         JSAN.use('util.network'); var net = new util.network();
702         JSAN.use('util.window'); var win = new util.window();
703
704         var can_edit = net.simple_request(
705             'PERM_MULTI_ORG_CHECK',
706             [
707                 ses(),
708                 ses('staff_id'),
709                 util.functional.map_list(
710                     fleshed_volumes,
711                     function(v) {
712                         return v.owning_lib();
713                     }
714                 ),
715                 ['UPDATE_VOLUME']
716             ]
717         );
718         if (!can_edit) {
719             alert(document.getElementById('catStrings').getString('staff.cat.edit_volume.permission_error'));
720             return false;
721         }
722         var title;
723         if (fleshed_volumes.length == 1) {
724             title = document.getElementById('catStrings').getString('staff.cat.edit_volume.title');
725         } else {
726             title = document.getElementById('catStrings').getString('staff.cat.edit_volume.title.plural');
727         }
728
729         function clone_list(o) {
730             var list = JSON2js( js2JSON( o ) );
731             // now that it is safe to clear copies, let's do so, otherwise may get an error from volume edit method
732             for (var i = 0; i < list.length; i++) { list[i].copies( [] ); } 
733             return list;
734         }
735
736         var my_xulG = win.open(
737             xulG.url_prefix(urls.XUL_VOLUME_EDITOR),
738             title,
739             'chrome,modal,resizable',
740             { 'volumes' : clone_list( fleshed_volumes ) }
741         );
742
743         if (typeof my_xulG.update_these_volumes == 'undefined') { return false; }
744
745         var volumes = util.functional.filter_list(
746             my_xulG.volumes,
747             function(v) {
748                 return get_bool( v.ischanged() );
749             }
750         );
751
752         if (volumes.length < 1) { return false; }
753
754         volumes = util.functional.map_list( volumes, function(o){
755             if (typeof o.suffix() == 'object') { o.suffix( o.suffix().id() ); }
756             if (typeof o.prefix() == 'object') { o.prefix( o.prefix().id() ); }
757             if (typeof o.label_class() == 'object') { o.label_class( o.label_class().id() ); }
758             return o;
759         });
760
761         var r = net.simple_request(
762             'FM_ACN_TREE_UPDATE',
763             [ ses(), volumes, false, { 'auto_merge_vols' : my_xulG.auto_merge } ],
764             null,
765             {
766                 'title' : document.getElementById('catStrings').getString('staff.cat.edit_volumes.override.confirm'),
767                 'overridable_events' : [
768                     1705 /* VOLUME_LABEL_EXISTS */
769                 ],
770                 'text' : {
771                     '1705' : function(r) {
772                         var payload_acn = util.functional.find_id_object_in_list( volumes, r.payload );
773                         return document.getElementById('catStrings').getFormattedString('staff.cat.edit_volumes.label_exists.details',[payload_acn.label()]);
774                     }
775                 }
776             }
777         );
778         if (!r) { throw('Update method returned null or false.'); }
779         if (typeof r.ilsevent != 'undefined') {
780             if (r.ilsevent == 1705 /* VOLUME_LABEL_EXISTS */) {
781                /* not overriden, but otherwise handled, so ignore */
782                 return false;
783             } else {
784                 throw(r);
785             }
786         }
787
788         return true;
789
790     } catch(E) {
791         alert('Error in cat.util.batch_edit_volumes: ' + E);
792         return false;
793     }
794 }
795
796 cat.util.render_fine_level = function(value) {
797     var text;
798     switch(Number(value)){
799         case 1: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.low"); break;
800         case 2: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.normal"); break;
801         case 3: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.fine_level.high"); break; 
802     }
803     return text;
804 }
805 cat.util.render_loan_duration = function(value) {
806     var text;
807     switch(Number(value)){
808         case 1: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.short"); break;
809         case 2: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.normal"); break;
810         case 3: text = document.getElementById("catStrings").getString("staff.cat.copy_editor.field.loan_duration.extended"); break;
811     }
812     return text;
813 }
814
815 cat.util.mark_item_as_missing_pieces = function(copy_ids) {
816     var error;
817     try {
818         JSAN.use('util.error'); error = new util.error();
819         JSAN.use('util.functional'); JSAN.use('util.date');
820         JSAN.use('util.network'); var network = new util.network();
821         JSAN.use('util.print'); var print = new util.print();
822         JSAN.use('util.window'); var win = new util.window();
823         if (!copy_ids) { return; }
824         copy_ids = util.functional.filter_list( copy_ids, function(o) { return o != null; } );
825         if (copy_ids.length < 1) { return; }
826         var copies = network.simple_request('FM_ACP_FLESHED_BATCH_RETRIEVE.authoritative', [ copy_ids ]);
827         if (typeof copies.ilsevent != 'undefined') throw(copies);
828
829         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(", ")]),
830             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_title'),
831             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_ok_label'),
832             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_cancel_label'), null,
833             $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.ms_confirm_action'));
834
835         if (r == 0) {
836             var count = 0;
837             JSAN.use('cat.util');
838             for (var i = 0; i < copies.length; i++) {
839                 try {
840                     var robj = network.simple_request('MARK_ITEM_MISSING_PIECES',[ses(),copies[i].id()]);
841                     if (typeof robj.ilsevent != 'undefined') {
842                         if (robj.ilsevent == 0 /* SUCCESS */) {
843                             count++;
844                             // Print Slip
845                             if (robj.payload && robj.payload.slip) {
846                                 print.simple( robj.payload.slip.template_output().data() );
847                             }
848                             // Item Note
849                             cat.util.spawn_copy_editor( { 'copy_ids' : [ copies[i].id() ], 'edit' : 1 } );
850                             // Patron Message
851                             var my_xulG = win.open(
852                                 urls.XUL_NEW_STANDING_PENALTY,
853                                 'new_standing_penalty',
854                                 'chrome,resizable,modal',
855                                 {}
856                             );
857                             if (my_xulG.id) {
858                                 var penalty = new ausp();
859                                 penalty.usr( robj.payload.circ.usr() );
860                                 penalty.isnew( 1 );
861                                 penalty.standing_penalty( my_xulG.id );
862                                 penalty.org_unit( ses('ws_ou') );
863                                 penalty.note( my_xulG.note );
864                                 network.simple_request(
865                                     'FM_AUSP_APPLY',
866                                     [ ses(), penalty ]
867                                 );
868                             }
869                             // Patron Letter
870
871                             var txt_file = new util.file('letter.txt');
872                             txt_file.write_content('truncate',robj.payload.letter.template_output().data());
873                             var text_path = '"' + txt_file._file.path + '"';
874                             txt_file.close();
875
876                             var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces['nsIPrefBranch']);
877                             var key = 'oils.text_editor.external.cmd';
878                             var has_key = prefs.prefHasUserValue(key);
879                             var oils_external_letter_opener_cmd = has_key ? prefs.getCharPref(key) : 'C:\\Windows\\notepad.exe %letter.txt%';
880
881                             var cmd = oils_external_letter_opener_cmd.replace('%letter.txt%',text_path);
882
883                             var file = new util.file('letter.bat');
884                             file.write_content('truncate+exec',cmd);
885                             file.close();
886                             file = new util.file('letter.bat');
887
888                             dump('letter exec: ' + cmd + '\n');
889                             var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
890                             process.init(file._file);
891
892                             var args = [];
893
894                             dump('process.run = ' + process.run(false, args, args.length) + '\n');
895
896                             file.close();
897
898                         } else if (robj.ilsevent == 1500 /* ACTION_CIRCULATION_NOT_FOUND */) {
899                             alert( $("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.circ_not_found',[ copies[i].barcode() ]) );
900                         } else {
901                             throw(robj);
902                         }
903                     } else {
904                         throw(robj);
905                     }
906                 } catch(E) {
907                     error.standard_unexpected_error_alert($("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.marking_error', [copies[i].barcode()]),E);
908                 }
909             }
910             /*alert(count == 1 ? $("catStrings").getString('staff.cat.util.mark_item_missing_pieces.one_item_missing_pieces') :
911                 $("catStrings").getFormattedString('staff.cat.util.mark_item_missing_pieces.multiple_item_missing_pieces', [count]));*/
912         }
913
914         return true;
915     } catch(E) {
916         alert('Error in cat.util.mark_item_as_missing_pieces: ' + E);
917         return false;
918     }
919 }
920
921 dump('exiting cat/util.js\n');