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