]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/opac/skin/default/js/holds.js
changed API for highest_org to return -1 instead of null
[working/Evergreen.git] / Open-ILS / web / opac / skin / default / js / holds.js
1 var holdsOrgSelectorBuilt = false;
2 var holdArgs;
3
4 /* 
5 note: metarecord holds have a holdable_formats field that contains
6 item_type(s)-item_forms(s)-language
7 item_form and language are optional - if language exist and no 
8 item_form is specified, use item_type(s)--language
9 */
10
11 var noEmailMessage;
12 var noEmailMessageXUL;
13
14 function holdsHandleStaff() {
15         swapCanvas($('xulholds_box'));
16         $('xul_recipient_barcode').focus();
17         $('xul_recipient_barcode').onkeypress = function(evt) 
18                 {if(userPressedEnter(evt)) { _holdsHandleStaff(); } };
19         $('xul_recipient_barcode_submit').onclick = _holdsHandleStaff;
20         $('xul_recipient_me').onclick = _holdsHandleStaffMe;
21 }
22
23 function _holdsHandleStaffMe() {
24         holdArgs.recipient = G.user;
25         holdsDrawEditor();
26 }
27
28 function _holdsHandleStaff() {
29         var barcode = $('xul_recipient_barcode').value;
30         var user = grabUserByBarcode( G.user.session, barcode );
31
32         var evt;
33         if(evt = checkILSEvent(user)) {
34                 alertILSEvent(user);
35                 return;
36         }
37
38         if(!barcode || !user) {
39                 alertId('holds_invalid_recipient', barcode);
40                 return
41         }
42
43         holdArgs.recipient = user;
44         holdsDrawEditor();
45 }
46
47
48
49 /** args:
50   * record, volume, copy (ids)
51   * request, recipient, editHold (objects)
52   */
53
54 function holdsDrawEditor(args) {
55
56         holdArgs = (args) ? args : holdArgs;
57
58     if(!noEmailMessage)
59         noEmailMessage = $('holds_email').removeChild($('holds.no_email'));
60
61     if(!noEmailMessageXUL)
62         noEmailMessageXUL = $('holds_email').removeChild($('holds.no_email.xul'));
63
64         if(isXUL() && holdArgs.recipient == null 
65                         && holdArgs.editHold == null) {
66                 holdsHandleStaff();
67                 return;
68         }
69
70         if(!holdArgs.recipient) holdArgs.recipient = G.user;
71         if(!holdArgs.requestor) holdArgs.requestor = G.user;
72
73         if(!(holdArgs.requestor && holdArgs.requestor.session)) {
74                 detachAllEvt('common','locationChanged');
75                 attachEvt('common','loggedIn', holdsDrawEditor)
76                 initLogin();
77                 return;
78         }
79
80         if(holdArgs.editHold) // flesh the args with the existing hold 
81                 holdArgsFromHold(holdArgs.editHold, holdArgs);
82
83         holdsDrawWindow();
84 }
85
86
87 // updates the edit window with the existing hold's data 
88 function _holdsUpdateEditHold() {
89
90         var hold = holdArgs.editHold;
91         var status = holdArgs.status;
92
93         var orgsel = $('holds_org_selector');
94         setSelector(orgsel, hold.pickup_lib());
95
96         if( hold.capture_time() || status > 2 )
97                 orgsel.disabled = true;
98         else    
99                 orgsel.disabled = false;
100
101
102         $('holds_submit').onclick = holdsEditHold;
103         $('holds_update').onclick = holdsEditHold;
104
105         if(hold.phone_notify()) {
106                 $('holds_enable_phone').checked = true;
107                 $('holds_phone').value = hold.phone_notify();
108
109         } else {
110                 $('holds_phone').disabled = true;
111                 $('holds_enable_phone').checked = false;
112         }
113
114         if(isTrue(hold.email_notify())) {
115                 $('holds_enable_email').checked = true;
116
117         } else {
118                 $('holds_enable_email').checked = false;
119         }
120 }
121
122 function holdsEditHold() {
123         var hold = holdsBuildHoldFromWindow();
124         if(!hold) return;
125         holdsUpdate(hold);
126         showCanvas();
127         if(holdArgs.onComplete)
128                 holdArgs.onComplete(hold);
129 }
130
131 function holdArgsFromHold(hold, oargs) {
132         var args = (oargs) ? oargs : {};
133         args.type = hold.hold_type();
134         var target = hold.target();
135
136         switch(args.type) {
137                 case 'M':
138                         args.metarecord = target;
139                         break;
140                 case 'T':
141                         args.record = target;
142                         break;
143                 case 'V':
144                         args.volume = target;
145                         break;
146                 case 'C':
147                         args.copy = target;
148                         break;
149         }
150         return args;
151 }
152
153 function holdFetchObjects(hold, doneCallback) {
154
155         var args = (hold) ? holdArgsFromHold(hold) : holdArgs;
156
157         var type = args.type;
158
159         if( type == 'C' ) {
160
161                 if( args.copyObject ) {
162
163                         args.copy = args.copyObject.id();
164                         args.volume = args.copyObject.call_number();
165                         _h_set_vol(args, doneCallback);
166
167                 } else {
168                         var creq = new Request(FETCH_COPY, args.copy);
169
170                         creq.callback(
171                                 function(r) {
172                                         var cp = r.getResultObject();
173                                         args.copyObject = cp;
174                                         args.volume = args.copyObject.call_number();
175                                         _h_set_vol(args, doneCallback);
176                                 }
177                         );
178                         creq.send();
179                 }
180         } else {
181                 if( type == 'V' ) {
182                         _h_set_vol(args, doneCallback);
183
184                 } else {
185                         if( type == 'T' ) {
186                                 _h_set_rec(args, doneCallback);
187                         } else {
188                                 _h_set_rec_descriptors(args, doneCallback);
189                         }
190                 }
191         }
192
193         return args;
194 }
195
196 function _h_set_vol(args, doneCallback) {
197
198         if( args.volumeObject ) {
199                 args.volume = args.volumeObject.id();
200                 args.record = args.volumeObject.record();
201                 _h_set_rec(args, doneCallback);
202
203         } else {
204
205                 var vreq = new Request(FETCH_VOLUME, args.volume);
206                 vreq.callback(
207                         function(r) {
208                                 var vol = r.getResultObject();
209                                 args.volumeObject = vol;
210                                 args.record = vol.record();
211                                 _h_set_rec(args, doneCallback);
212                         }
213                 );
214                 vreq.send();
215         }
216 }
217
218 function _h_set_rec(args, doneCallback) {
219
220         if(args.recordObject) 
221                 args.record = args.recordObject.doc_id();
222         else 
223                 args.recordObject = findRecord( args.record, 'T' );
224         
225         if( args.type == 'T' || args.type == 'M' ) 
226                 _h_set_rec_descriptors(args, doneCallback);
227         else 
228                 if(doneCallback) doneCallback(args);
229 }
230
231
232 function _h_set_rec_descriptors(args, doneCallback) {
233
234         // grab the list of record desciptors attached to this records metarecord 
235         if( ! args.recordDescriptors )  {
236                 var params = { record: args.record };
237
238                 if( ! args.record ) {
239                         if( args.metarecord )
240                                 params = { metarecord : args.metarecord };
241                         else 
242                                 params = { metarecord : args.metarecordObject.doc_id() };
243                 }
244
245                 var req = new Request(FETCH_MR_DESCRIPTORS, params );
246                 req.callback(
247                         function(r) {
248                                 var data = r.getResultObject();
249                                 args.recordDescriptors = data.descriptors;
250                                 args.metarecord = data.metarecord;
251                                 if( args.type == 'M' && ! args.metarecordObject) 
252                                         args.metarecordObject = findRecord(args.metarecord, 'M');       
253                                  
254                                 if(doneCallback) doneCallback(args);
255                         }
256                 );
257                 req.send();
258
259         } else {
260                 if(doneCallback) doneCallback(args);
261         }
262
263         return args;
264 }
265
266
267
268 function holdsDrawWindow() {
269         swapCanvas($('holds_box'));
270         $('holds_cancel').onclick = function(){ runEvt('common', 'holdUpdateCanceled'), showCanvas() };
271         $('holds_submit').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
272         $('holds_update').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
273         holdFetchObjects(null, 
274                 function(){
275                         __holdsDrawWindow();
276
277                         if(holdArgs.editHold) {
278                                 hideMe($('holds_submit'));
279                                 unHideMe($('holds_update'));
280                                 var req = new Request(FETCH_HOLD_STATUS, 
281                                         G.user.session, holdArgs.editHold.id());
282                                 req.send(true);
283                                 holdArgs.status = req.result();
284                                 _holdsUpdateEditHold();
285                         }  
286                 }
287         );
288 }
289
290 function __holdsDrawWindow() {
291
292         var rec = holdArgs.recordObject;
293         var vol = holdArgs.volumeObject;
294         var copy = holdArgs.copyObject;
295         var mr = holdArgs.metarecordObject;
296
297         rec = (rec) ? rec : mr;
298
299         if(!holdsOrgSelectorBuilt) {
300                 holdsBuildOrgSelector(null,0);
301                 holdsOrgSelectorBuilt = true;
302                 var selector = $('holds_org_selector');
303
304                 /*
305                 var o_loc = findOrgUnit(getOrigLocation());
306                 var t = findOrgType(o_loc.ou_type());
307                 if( t.can_have_users() ) 
308                         setSelector(selector, o_loc.id());
309                 else 
310                 */
311
312                 setSelector(selector, holdArgs.recipient.home_ou());
313         
314         }
315
316         /*
317         if(isXUL()) {
318                 var dsel = $('holds_depth_selector');
319                 unHideMe($('holds_depth_selector_row'));
320                 if(dsel.getElementsByTagName('option').length == 0) {
321                         var types = globalOrgTypes;
322                         var depth = findOrgDepth(G.user.ws_ou());
323                         iterate(types, 
324                                 function(t) {
325                                         if(t.depth() > depth) return;
326                                         insertSelectorVal(dsel, -1, t.opac_label(), t.depth());
327                                 }
328                         );
329                 }
330         }
331         */
332
333         appendClear($('holds_recipient'), text(
334                 holdArgs.recipient.family_name() + ', ' +  
335                         holdArgs.recipient.first_given_name()));
336         appendClear($('holds_title'), text(rec.title()));
337         appendClear($('holds_author'), text(rec.author()));
338
339         if( holdArgs.type == 'V' || holdArgs.type == 'C' ) {
340
341                 unHideMe($('holds_type_row'));
342                 unHideMe($('holds_cn_row'));
343                 appendClear($('holds_cn'), text(holdArgs.volumeObject.label()));
344
345                 if( holdArgs.type == 'V'  ) {
346                         unHideMe($('holds_is_cn'));
347                         hideMe($('holds_is_copy'));
348
349                 } else {
350                         hideMe($('holds_is_cn'));
351                         unHideMe($('holds_is_copy'));
352                         unHideMe($('holds_copy_row'));
353                         appendClear($('holds_copy'), text(holdArgs.copyObject.barcode()));
354                 }
355
356         } else {
357                 hideMe($('holds_type_row'));
358                 hideMe($('holds_copy_row'));
359                 hideMe($('holds_cn_row'));
360         }
361
362         removeChildren($('holds_format'));
363
364         var mods_formats = rec.types_of_resource();
365         var formats;
366
367         if(holdArgs.recordDescriptors)
368                 formats = holdArgs.recordDescriptors[0].item_type();
369
370         if( holdArgs.type == 'T' ) {
371                 var desc = grep( holdArgs.recordDescriptors,
372                         function(i) {
373                                 return (i.record() == holdArgs.record); 
374                         }
375                 );
376                 formats = desc[0].item_type();
377         }
378
379         if( holdArgs.type == 'M' ) {
380                 var data = holdsParseMRFormats(holdArgs.editHold.holdable_formats());
381                 mods_formats = data.mods_formats;
382                 formats = data.formats;
383         }
384
385
386         for( var i in mods_formats ) {
387                 var res = mods_formats[i];
388                 var img = elem("img");
389                 setResourcePic(img, res);
390                 $('holds_format').appendChild(img);
391                 if(formats)
392                         $('holds_format').appendChild(text(' '+ MARCTypeToFriendly(formats[i]) +' '));
393                 else
394                         $('holds_format').appendChild(text(' '+ mods_formats[i] +' '));
395                 $('holds_format').appendChild(elem('br'));
396         }
397
398
399         $('holds_phone').value = holdArgs.recipient.day_phone();
400         appendClear( $('holds_email'), text(holdArgs.recipient.email()));
401
402         var pref = G.user.prefs[PREF_HOLD_NOTIFY];
403
404         if(pref) {
405                 if( ! pref.match(/email/i) ) 
406                         $('holds_enable_email').checked = false;
407
408                 if( ! pref.match(/phone/i) ) {
409                         $('holds_phone').disabled = true;
410                         $('holds_enable_phone').checked = false;
411                 }
412         }
413
414     //if(!G.user.email()) {
415     if(!holdArgs.recipient.email()) {
416                 $('holds_enable_email').checked = false;        
417                 $('holds_enable_email').disabled = true;
418         var message;
419         if(isXUL()) {
420             message = noEmailMessageXUL.cloneNode(true);
421                 appendClear($('holds_email'), message);
422         } else {
423             message = noEmailMessage.cloneNode(true);
424                 appendClear($('holds_email'), message);
425             $('holds.no_email.my_account').setAttribute('href', buildOPACLink({page:MYOPAC},null,true));
426         }
427         unHideMe(message);
428     }
429
430         if(!$('holds_phone').value) 
431                 $('holds_enable_phone').checked = false;        
432
433         appendClear($('holds_physical_desc'), text(rec.physical_description()));
434
435         if(holdArgs.type == 'M') hideMe($('hold_physical_desc_row'));
436
437         holdsSetFormatSelector();
438 }
439
440 function holdsParseMRFormats(str) {
441         var data = str.split(/-/);      
442
443         var formats = [];
444         var mods_formats = [];
445
446         for( var i = 0; i < data[0].length; i++ ) {
447                 formats.push( data[0].charAt(i) );
448                 mods_formats.push( MARCFormatToMods( formats[i] ) );
449         }
450         
451         formats = uniquify(formats);
452         mods_formats = uniquify(mods_formats);
453
454         return {
455                 formats                 : formats,
456                 mods_formats    : mods_formats,
457                 lang                            : data[2],
458                 largeprint              : data[1]
459         };
460 }
461
462
463 function holdsSetFormatSelector() {
464         var type = holdArgs.type;
465         if( type == 'C' || type == 'V' || holdArgs.editHold ) return;
466
467         var data                                = holdsGetFormats();
468         var avail_formats       = data.avail_formats;
469         var sel_formats = data.sel_formats;
470         holdArgs.language = data.lang;
471
472         unHideMe($('holds_alt_formats_row_extras'));
473         var selector = $('hold_alt_form_selector');
474
475         for( var i = 0; i < avail_formats.length; i++ ) {
476                 var form = avail_formats[i];
477                 unHideMe(findSelectorOptByValue(selector, form));
478         }
479 }
480
481
482 function holdsGetFormats() {
483
484         var lang;
485         var formats = [];
486         var sformats = []; // selected formats 
487
488         var type = holdArgs.type;
489         var desc = holdArgs.recordDescriptors;
490         var rec = holdArgs.record;
491         var mrec = holdArgs.metarecord;
492
493         if( type == 'T' ) {
494
495                 for( var i = 0; i < desc.length; i++ ) {
496                         var d = desc[i];
497                         if( d.record() == holdArgs.record ) {
498                                 lang = d.item_lang();
499                                 holdArgs.myFormat =  _t_f_2_format(d.item_type(), d.item_form());
500                                 sformats.push(holdArgs.myFormat);
501                                 break;
502                         }
503                 }
504         }
505
506         for( var i = 0; i < desc.length; i++ ) {
507                 var d = desc[i];
508                 if( d.item_lang() != lang ) continue;
509                 formats.push( _t_f_2_format(d.item_type(), d.item_form()));
510         }
511
512         formats = uniquify(formats);
513
514         return {
515                 lang : lang,
516                 avail_formats : formats, 
517                 sel_formats : sformats
518         };
519 }
520
521
522
523 function _t_f_2_format(type, form) {
524         if( form == 'd' ) return 'at-d';
525         return (type == 'a' || type == 't') ? 'at' : 
526                 ( type == 'i' || type == 'g' || type == 'j' ) ? type : null;
527 }
528
529 function holdsSetSelectedFormats() {
530
531         var cn = $('holds_alt_formats_row').className;
532         if( cn && cn.match(/hide_me/) ) return;
533
534         var selector = $('hold_alt_form_selector');
535         var vals = getSelectedList(selector);
536
537         if(vals.length == 0) return;
538
539         var fstring = "";
540
541         if( contains(vals, 'at-d') ) {
542                 if( contains(vals, 'at') )
543                         fstring = 'at';
544                 else 
545                         fstring = 'at-d';
546         } else {
547                 if( contains(vals, 'at') )
548                         fstring = 'at';
549         }
550
551         for( var i = 0; i < vals.length; i++ ) {
552                 var val = vals[i];
553                 if( !val.match(/at/) ) fstring = val + fstring;
554         }
555
556         if( holdArgs.language ) {
557                 if( fstring.match(/-/) )
558                         fstring = fstring + '-' + holdArgs.language;
559                 else
560                         fstring = fstring + '--' + holdArgs.language;
561         }
562
563
564         return fstring;
565 }
566
567
568 function holdsCheckPossibility(pickuplib, hold, recurse) {
569
570         var args = { 
571                 titleid : holdArgs.record,
572                 volume_id : holdArgs.volume,
573                 copy_id : holdArgs.copy,
574                 hold_type : holdArgs.type,
575                 patronid : holdArgs.recipient.id(),
576                 depth : 0, 
577                 pickup_lib : pickuplib 
578         };
579
580         if(recurse) {
581                 /* if we're calling create again (recursing), 
582                         we know that the hold possibility check already succeeded */
583                 holdHandleCreateResponse({_recurse:true, _hold:hold}, true );
584
585         } else {
586                 _debug("hold possible args = "+js2JSON(args));
587         
588                 var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );
589         
590                 req.request.alertEvent = false;
591                 req.request._hold = hold;
592                 req.request._recurse = recurse;
593                 req.callback(holdHandleCreateResponse);
594                 req.send();
595         }
596 }
597
598
599 function holdsBuildOrgSelector(node) {
600
601         if(!node) node = globalOrgTree;
602
603         var selector = $('holds_org_selector');
604         var index = selector.options.length;
605
606         var type = findOrgType(node.ou_type());
607         var indent = type.depth() - 1;
608         var opt = setSelectorVal( selector, index, node.name(), node.id(), null, indent );
609         if(!type.can_have_users()) {
610                 opt.disabled = true;
611                 addCSSClass(opt, 'disabled_option');
612         }
613         
614         for( var i in node.children() ) {
615                 var child = node.children()[i];
616                 if(child) holdsBuildOrgSelector(child);
617         }
618 }
619
620 function holdsBuildHoldFromWindow() {
621
622         var org = getSelectorVal($('holds_org_selector'));
623         var node = findOrgUnit(org);
624         var ntype = findOrgType(node.ou_type());
625         if(!ntype.can_have_users()) {
626                 alertId('holds_pick_good_org');
627                 return;
628         }
629
630         var hold = new ahr();
631         if(holdArgs.editHold) {
632                 hold = holdArgs.editHold;
633                 holdArgs.editHold = null;
634         }
635
636         if( $('holds_enable_phone').checked ) {
637                 var phone = $('holds_phone').value;
638                 if( !phone || !phone.match(REGEX_PHONE) ) {
639                         alert($('holds_bad_phone').innerHTML);
640                         return null;
641                 }
642                 hold.phone_notify(phone);
643
644         } else {
645                 hold.phone_notify("");
646         }
647
648         if( $('holds_enable_email').checked ) 
649                 hold.email_notify(1);
650         else
651                 hold.email_notify(0);
652
653         var target;
654
655         switch(holdArgs.type) {
656                 case 'M':
657                         target = holdArgs.metarecord; break;
658                 case 'T':
659                         target = holdArgs.record; break;
660                 case 'V':
661                         target = holdArgs.volume; break;
662                 case 'C':
663                         target = holdArgs.copy; break;
664         }
665
666
667
668         hold.pickup_lib(org); 
669         //hold.request_lib(org); 
670         hold.requestor(holdArgs.requestor.id());
671         hold.usr(holdArgs.recipient.id());
672         hold.target(target);
673         hold.hold_type(holdArgs.type);
674
675         //check for alternate hold formats 
676         var fstring = holdsSetSelectedFormats();
677         if(fstring) { 
678                 hold.hold_type('M'); 
679                 hold.holdable_formats(fstring);
680                 hold.target(holdArgs.metarecord);
681         }
682         return hold;
683 }
684         
685 function holdsPlaceHold(hold, recurse) {
686         if(!hold) return;
687         swapCanvas($('check_holds_box'));
688         holdsCheckPossibility(hold.pickup_lib(), hold, recurse);
689 }
690
691
692 function holdHandleCreateResponse(r, recurse) {
693
694         if(!recurse) {
695                 var res = r.getResultObject();
696                 if(!res || checkILSEvent(res) ) {
697                         if(!res) {
698                                 alert($('hold_not_allowed').innerHTML);
699                         } else {
700                                 if( res.textcode == 'PATRON_BARRED' ) {
701                                         alertId('hold_failed_patron_barred');
702                         } else {
703                                         alert($('hold_not_allowed').innerHTML);
704                                 }
705                         }
706                         swapCanvas($('holds_box'));
707                         return;
708                 }
709         }       
710
711         holdCreateHold(r._recurse, r._hold);
712 }
713
714
715 function holdCreateHold( recurse, hold ) {
716         var method = CREATE_HOLD;
717         if(recurse) method = CREATE_HOLD_OVERRIDE;
718         var req = new Request( method, holdArgs.requestor.session, hold );
719         req.request.alertEvent = false;
720         req.send(true);
721         var res = req.result();
722         holdProcessResult(hold, res, recurse);
723         
724         showCanvas();
725
726         runEvt('common', 'holdUpdated');
727 }
728
729
730 function holdProcessResult( hold, res, recurse ) {
731
732         if( res == '1' ) {
733                 alert($('holds_success').innerHTML);
734                 holdArgs = null;
735
736         } else {
737
738                 if( recurse ) {
739                         alert($('holds_failure').innerHTML);
740                         return;
741                 }
742
743                 if( grep(res, function(e) { return (e.textcode == 'HOLD_EXISTS'); }) ) {
744                         if( fetchPermOrgs('HOLD_EXISTS.override')[0] != -1 ) {
745                                 if( confirm($('hold_dup_exists_override').innerHTML) ) {
746                                         return holdsPlaceHold(hold, true);
747                                 }
748
749                         } else {
750                                 return alert($('hold_dup_exists').innerHTML);
751                         }
752                 }
753
754                 alert($('holds_failure').innerHTML);
755         }
756 }
757
758
759 function holdsCancel(holdid, user) {
760         if(!user) user = G.user;
761         var req = new Request(CANCEL_HOLD, user.session, holdid);
762         req.send(true);
763         return req.result();
764         runEvt('common', 'holdUpdated');
765 }
766
767 function holdsUpdate(hold, user) {
768         if(!user) user = G.user;
769         var req = new Request(UPDATE_HOLD, user.session, hold);
770         req.send(true);
771         var x = req.result(); // cause an exception if there is one 
772         runEvt('common', 'holdUpdated');
773 }
774
775