]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/opac/skin/default/js/holds.js
748f98c27e6f264ca684a4150cb3bc99c7eb330d
[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 var holdTargetTypeMap = {
15     M : 'metarecord',
16     T : 'record',
17     V : 'volume',
18     I : 'issuance',
19     C : 'copy'
20 };
21
22
23
24 function holdsHandleStaff() {
25
26     // if we know the recipient's barcode, use it
27     if(xulG.patron_barcode) return _holdsHandleStaff();
28
29         swapCanvas($('xulholds_box'));
30         $('xul_recipient_barcode').focus();
31         $('xul_recipient_barcode').onkeypress = function(evt) 
32                 {if(userPressedEnter(evt)) { _holdsHandleStaff(); } };
33         $('xul_recipient_barcode_submit').onclick = _holdsHandleStaff;
34         $('xul_recipient_me').onclick = _holdsHandleStaffMe;
35
36         $('xul_recipient_barcode').onkeyup = function(evt) {
37         if($('xul_recipient_barcode').value == '') 
38             $('xul_recipient_me').disabled = false;
39         else
40             $('xul_recipient_me').disabled = true;
41     };
42 }
43
44 $('holds_frozen_thaw_input').onchange = 
45         function(){holdsVerifyThawDateUI('holds_frozen_thaw_input');}
46 $('holds_frozen_thaw_input').onkeyup = 
47         function(){holdsVerifyThawDateUI('holds_frozen_thaw_input');}
48
49 function _holdsHandleStaffMe() {
50         holdArgs.recipient = G.user;
51         holdsDrawEditor();
52 }
53
54 function _holdsHandleStaff() {
55         var barcode = xulG.patron_barcode || $('xul_recipient_barcode').value;
56         var user = grabUserByBarcode( G.user.session, barcode );
57
58         var evt;
59         if(evt = checkILSEvent(user)) {
60                 alertILSEvent(user);
61                 return;
62         }
63
64         if(!barcode || !user) {
65                 alertId('holds_invalid_recipient', barcode);
66                 return
67         }
68
69         grabUserPrefs(user);
70
71         holdArgs.recipient = user;
72         holdsDrawEditor();
73 }
74
75
76
77 /** args:
78   * record, volume, copy (ids)
79   * request, recipient, editHold (objects)
80   */
81
82 function holdsDrawEditor(args) {
83
84         holdArgs = (args) ? args : holdArgs;
85
86     if(!noEmailMessage)
87         noEmailMessage = $('holds_email').removeChild($('holds.no_email'));
88
89     if(!noEmailMessageXUL)
90         noEmailMessageXUL = $('holds_email').removeChild($('holds.no_email.xul'));
91
92         if(isXUL() && holdArgs.recipient == null 
93                         && holdArgs.editHold == null) {
94                 holdsHandleStaff();
95                 return;
96         }
97
98         if(!holdArgs.recipient) holdArgs.recipient = G.user;
99         if(!holdArgs.requestor) holdArgs.requestor = G.user;
100
101         if(!(holdArgs.requestor && holdArgs.requestor.session)) {
102                 detachAllEvt('common','locationChanged');
103                 attachEvt('common','loggedIn', holdsDrawEditor)
104                 initLogin();
105                 return;
106         }
107
108         if(holdArgs.editHold) // flesh the args with the existing hold 
109                 holdArgsFromHold(holdArgs.editHold, holdArgs);
110
111         holdsDrawWindow();
112 }
113
114
115 // updates the edit window with the existing hold's data 
116 function _holdsUpdateEditHold() {
117
118         var hold = holdArgs.editHold;
119         var qstats = holdArgs.status;
120
121         var orgsel = $('holds_org_selector');
122     var frozenbox = $('holds_frozen_chkbox');
123
124         setSelector(orgsel, hold.pickup_lib());
125
126         if( hold.capture_time() || qstats.status > 2 ) {
127         frozenbox.disabled = true;
128         $('holds_frozen_thaw_input').disabled = true;
129         if(qstats.status == 3) {
130             // no pickup lib changes while in-transit
131                     orgsel.disabled = true;
132         } else {
133             var orgs = fetchPermOrgs('UPDATE_PICKUP_LIB_FROM_HOLDS_SHELF');
134             if(orgs[0] == -1)
135                         orgsel.disabled = true;
136         }
137     } else {
138                 orgsel.disabled = false;
139         frozenbox.disabled = false;
140     }
141
142
143         $('holds_submit').onclick = holdsEditHold;
144         $('holds_update').onclick = holdsEditHold;
145
146         if(hold.phone_notify()) {
147                 $('holds_enable_phone').checked = true;
148                 $('holds_phone').value = hold.phone_notify();
149
150         } else {
151                 $('holds_phone').disabled = true;
152                 $('holds_enable_phone').checked = false;
153         }
154
155         if(isTrue(hold.email_notify())) {
156                 $('holds_enable_email').checked = true;
157
158         } else {
159                 $('holds_enable_email').checked = false;
160         }
161
162     dijit.byId('holds_expire_time').setValue(dojo.date.stamp.fromISOString(hold.expire_time()));
163
164     /* populate the hold freezing info */
165     if(!frozenbox.disabled && isTrue(hold.frozen())) {
166         frozenbox.checked = true;
167         unHideMe($('hold_frozen_thaw_row'));
168         if(hold.thaw_date()) {
169             dijit.byId('holds_frozen_thaw_input').setValue(dojo.date.stamp.fromISOString(hold.thaw_date()));
170         } else {
171             dijit.byId('holds_frozen_thaw_input').setValue('');
172         }
173     } else {
174         frozenbox.checked = false;
175         dijit.byId('holds_frozen_thaw_input').setValue('');
176         hideMe($('hold_frozen_thaw_row'));
177     }
178 }
179
180 function holdsEditHold() {
181         var hold = holdsBuildHoldFromWindow();
182         if(!hold) return;
183         holdsUpdate(hold);
184         showCanvas();
185         if(holdArgs.onComplete)
186                 holdArgs.onComplete(hold);
187 }
188
189 function holdArgsFromHold(hold, oargs) {
190         var args = (oargs) ? oargs : {};
191         args.type = hold.hold_type();
192         var target = hold.target();
193     args[holdTargetTypeMap[args.type]] = target;
194         return args;
195 }
196
197 function holdFetchObjects(hold, doneCallback) {
198
199         var args = (hold) ? holdArgsFromHold(hold) : holdArgs;
200
201         var type = args.type;
202
203         if( type == 'C' ) {
204
205                 if( args.copyObject ) {
206
207                         args.copy = args.copyObject.id();
208                         args.volume = args.copyObject.call_number();
209                         _h_set_vol(args, doneCallback);
210
211                 } else {
212                         var creq = new Request(FETCH_COPY, args.copy);
213
214                         creq.callback(
215                                 function(r) {
216                                         var cp = r.getResultObject();
217                                         args.copyObject = cp;
218                                         args.volume = args.copyObject.call_number();
219                                         _h_set_vol(args, doneCallback);
220                                 }
221                         );
222                         creq.send();
223                 }
224         } else {
225                 if( type == 'V' ) {
226                         _h_set_vol(args, doneCallback);
227
228         } else if( type == 'I' ) {
229             _h_set_issuance(args, doneCallback);
230
231                 } else {
232                         if( type == 'T' ) {
233                                 _h_set_rec(args, doneCallback);
234                         } else {
235                                 _h_set_rec_descriptors(args, doneCallback);
236                         }
237                 }
238         }
239
240         return args;
241 }
242
243 function _h_set_vol(args, doneCallback) {
244
245         if( args.volumeObject ) {
246                 args.volume = args.volumeObject.id();
247                 args.record = args.volumeObject.record();
248                 _h_set_rec(args, doneCallback);
249
250         } else {
251
252                 var vreq = new Request(FETCH_VOLUME, args.volume);
253                 vreq.callback(
254                         function(r) {
255                                 var vol = r.getResultObject();
256                                 args.volumeObject = vol;
257                                 args.record = vol.record();
258                                 _h_set_rec(args, doneCallback);
259                         }
260                 );
261                 vreq.send();
262         }
263 }
264
265 function _h_set_issuance(args, doneCallback) {
266
267         if( args.issuanceObject ) {
268                 args.issuance = args.issuanceObject.id();
269                 args.record = args.issuanceObject.subscription().record_entry();
270                 _h_set_rec(args, doneCallback);
271
272         } else {
273
274                 var vreq = new Request(FETCH_ISSUANCE, [args.issuance]);
275                 vreq.callback(
276                         function(r) {
277                                 var issuance = r.getResultObject()[0];
278                                 args.issuanceObject = issuance;
279                                 args.record = issuance.subscription().record_entry();
280                                 _h_set_rec(args, doneCallback);
281                         }
282                 );
283                 vreq.send();
284         }
285 }
286
287 function _h_set_rec(args, doneCallback) {
288
289         if(args.recordObject) 
290                 args.record = args.recordObject.doc_id();
291         else 
292                 args.recordObject = findRecord( args.record, 'T' );
293         
294         if( args.type == 'T' || args.type == 'M' ) 
295                 _h_set_rec_descriptors(args, doneCallback);
296         else 
297                 if(doneCallback) doneCallback(args);
298 }
299
300
301 function _h_set_rec_descriptors(args, doneCallback) {
302
303     if( ! args.pickup_lib )
304         args.pickup_lib = getSelectorVal($('holds_org_selector'));
305
306     if(args.pickup_lib === null)
307         args.pickup_lib = holdArgs.recipient.home_ou();
308
309         // grab the list of record desciptors attached to this records metarecord 
310         if( ! args.recordDescriptors )  {
311                 var params = { pickup_lib: args.pickup_lib };
312
313         if (args.type == 'M') {
314                 if( !args.metarecord && args.record) {
315                 params.metarecord = args.metarecord = args.record;
316                 delete(args.record);
317                 } else {
318                                 params.metarecord = args.metarecordObject.doc_id();
319                 }
320         } else {
321                 params.record = args.record;
322         }
323
324                 if( ! args.record ) {
325                         if( args.metarecord )
326                                 params.metarecord = args.metarecord;
327                         else 
328                                 params.metarecord = args.metarecordObject.doc_id();
329                 }
330
331                 var req = new Request(FETCH_MR_DESCRIPTORS, params );
332                 req.callback(
333                         function(r) {
334                                 var data = r.getResultObject();
335                                 holdArgs.recordDescriptors = args.recordDescriptors = data.descriptors;
336                                 holdArgs.metarecord = args.metarecord = data.metarecord;
337                                 if( args.type == 'M' && ! args.metarecordObject) 
338                                         holdArgs.metarecordObject = args.metarecordObject = findRecord(args.metarecord, 'M');   
339
340                                 if(doneCallback) doneCallback(args);
341                         }
342                 );
343                 req.send();
344
345         } else {
346                 if(doneCallback) doneCallback(args);
347         }
348
349         return args;
350 }
351
352
353
354 function holdsDrawWindow() {
355         swapCanvas($('holds_box'));
356         $('holds_cancel').onclick = function(){ runEvt('common', 'holdUpdateCanceled'), showCanvas() };
357         $('holds_submit').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
358         $('holds_update').onclick = function(){holdsPlaceHold(holdsBuildHoldFromWindow())};
359     $('holds_org_selector').onchange = function(){holdsDrawWindow()};
360         holdFetchObjects(null, 
361                 function(){
362                         __holdsDrawWindow();
363
364                         if(holdArgs.editHold) {
365                                 hideMe($('holds_submit'));
366                                 unHideMe($('holds_update'));
367                                 var req = new Request(FETCH_HOLD_STATUS, 
368                                         G.user.session, holdArgs.editHold.id());
369                                 req.send(true);
370                                 holdArgs.status = req.result();
371                                 _holdsUpdateEditHold();
372                         }  
373                 }
374         );
375 }
376
377 function __holdsDrawWindow() {
378
379         var rec = holdArgs.recordObject;
380         var vol = holdArgs.volumeObject;
381         var copy = holdArgs.copyObject;
382         var mr = holdArgs.metarecordObject;
383
384         rec = (rec) ? rec : mr;
385
386         if(!holdsOrgSelectorBuilt) {
387                 holdsBuildOrgSelector(null,0);
388                 holdsOrgSelectorBuilt = true;
389                 var selector = $('holds_org_selector');
390
391                 /*
392                 var o_loc = findOrgUnit(getOrigLocation());
393                 var t = findOrgType(o_loc.ou_type());
394                 if( t.can_have_users() ) 
395                         setSelector(selector, o_loc.id());
396                 else 
397                 */
398
399                 setSelector(selector, holdArgs.recipient.home_ou());
400         
401         }
402
403         /*
404         if(isXUL()) {
405                 var dsel = $('holds_depth_selector');
406                 unHideMe($('holds_depth_selector_row'));
407                 if(dsel.getElementsByTagName('option').length == 0) {
408                         var types = globalOrgTypes;
409                         var depth = findOrgDepth(G.user.ws_ou());
410                         iterate(types, 
411                                 function(t) {
412                                         if(t.depth() > depth) return;
413                                         insertSelectorVal(dsel, -1, t.opac_label(), t.depth());
414                                 }
415                         );
416                 }
417         }
418         */
419
420         appendClear($('holds_recipient'), text(
421                 holdArgs.recipient.family_name() + ', ' +  
422                         holdArgs.recipient.first_given_name()));
423         appendClear($('holds_title'), text(rec.title()));
424         appendClear($('holds_author'), text(rec.author()));
425
426     if( holdArgs.type == 'I' ) {
427                 unHideMe($('holds_type_row'));
428         unHideMe($('holds_is_issuance'));
429         unHideMe($('holds_issuance_row'));
430         appendClear($('holds_issuance_label'), text(holdArgs.issuanceObject.label()));
431
432     } else if( holdArgs.type == 'V' || holdArgs.type == 'C' ) {
433
434                 unHideMe($('holds_type_row'));
435                 unHideMe($('holds_cn_row'));
436                 appendClear($('holds_cn'), text(holdArgs.volumeObject.label()));
437
438                 if( holdArgs.type == 'V'  ) {
439                         unHideMe($('holds_is_cn'));
440                         hideMe($('holds_is_copy'));
441
442                 } else {
443                         hideMe($('holds_is_cn'));
444                         unHideMe($('holds_is_copy'));
445                         unHideMe($('holds_copy_row'));
446                         appendClear($('holds_copy'), text(holdArgs.copyObject.barcode()));
447                 }
448
449         } else {
450                 hideMe($('holds_type_row'));
451                 hideMe($('holds_copy_row'));
452                 hideMe($('holds_cn_row'));
453                 hideMe($('holds_issuance_row'));
454         }
455
456         removeChildren($('holds_format'));
457
458         var mods_formats = rec.types_of_resource();
459         var formats;
460
461         if(holdArgs.recordDescriptors)
462                 formats = holdArgs.recordDescriptors[0].item_type();
463
464         if( holdArgs.type == 'T' ) {
465                 var desc = grep( holdArgs.recordDescriptors,
466                         function(i) {
467                                 return (i.record() == holdArgs.record); 
468                         }
469                 );
470                 formats = desc[0].item_type();
471         }
472
473         if( holdArgs.type == 'M' ) {
474                 var mr_formats;
475                 if(holdArgs.editHold){
476                         mr_formats = holdArgs.editHold.holdable_formats();
477                 }else{
478                         mr_formats = ''; // collect the item_type()s from all holdArgs.recordDescriptors
479                         for(var desc in holdArgs.recordDescriptors){
480                 if (!holdArgs.recordDescriptors[desc].item_type()) continue;
481                                 mr_formats += holdArgs.recordDescriptors[desc].item_type();
482                         }
483
484             var first_form = 1;
485                         for(var desc in holdArgs.recordDescriptors){
486                 if (!holdArgs.recordDescriptors[desc].item_form()) continue;
487                 if (first_form) {
488                     mr_formats += '-';
489                     first_form = 0;
490                 }
491                                 mr_formats += holdArgs.recordDescriptors[desc].item_form();
492                         }
493
494
495                 }
496                 
497                 var data = holdsParseMRFormats(mr_formats);
498                 mods_formats = data.mods_formats;
499                 formats = data.formats;
500         }
501
502
503         for( var i in mods_formats ) {
504                 var res = mods_formats[i];
505                 var img = elem("img");
506                 setResourcePic(img, res);
507                 $('holds_format').appendChild(img);
508                 if(formats)
509                         $('holds_format').appendChild(text(' '+ MARCTypeToFriendly(formats[i]) +' '));
510                 else
511                         $('holds_format').appendChild(text(' '+ mods_formats[i] +' '));
512                 $('holds_format').appendChild(elem('br'));
513         }
514
515
516         $('holds_phone').value = holdArgs.recipient.day_phone();
517         appendClear( $('holds_email'), text(holdArgs.recipient.email()));
518
519         var pref = holdArgs.recipient.prefs[PREF_HOLD_NOTIFY];
520
521         if(pref) {
522                 if( ! pref.match(/email/i) ) {
523                         $('holds_enable_email').checked = false;
524                 } else {
525                         $('holds_enable_email').checked = true;
526                 }
527
528                 if( ! pref.match(/phone/i) ) {
529                         $('holds_phone').disabled = true;
530                         $('holds_enable_phone').checked = false;
531                 } else {
532                         $('holds_phone').disabled = false;
533                         $('holds_enable_phone').checked = true;
534                 }
535         }
536
537     if(!holdArgs.recipient.email()) {
538                 $('holds_enable_email').checked = false;        
539                 $('holds_enable_email').disabled = true;
540         var message;
541         if(isXUL()) {
542             message = noEmailMessageXUL.cloneNode(true);
543                 appendClear($('holds_email'), message);
544         } else {
545             message = noEmailMessage.cloneNode(true);
546                 appendClear($('holds_email'), message);
547             $('holds.no_email.my_account').setAttribute('href', buildOPACLink({page:MYOPAC},null,true));
548         }
549         unHideMe(message);
550     }
551
552         if(!$('holds_phone').value) 
553                 $('holds_enable_phone').checked = false;        
554
555         appendClear($('holds_physical_desc'), text(rec.physical_description()));
556
557         if(holdArgs.type == 'M') hideMe($('hold_physical_desc_row'));
558
559         holdsSetFormatSelector();
560
561     $('holds_frozen_chkbox').checked = false;
562     hideMe($('hold_frozen_thaw_row'));
563
564     var interval = fetchOrgSettingDefault(holdArgs.recipient.home_ou(), 'circ.hold_expire_interval');
565     var secs = 0;
566     if(interval) {
567         secs = interval_to_seconds(interval);
568         var expire = new Date();
569         expire.setTime(expire.getTime() + Number(secs + '000'));
570         dijit.byId('holds_expire_time').setValue(expire);
571     }
572 }
573
574 function holdsParseMRFormats(str) {
575         var data = str.split(/-/);      
576
577         var formats = [];
578         var mods_formats = [];
579
580         for( var i = 0; i < data[0].length; i++ ) {
581                 formats.push( data[0].charAt(i) );
582                 mods_formats.push( MARCFormatToMods( formats[i] ) );
583         }
584         
585         formats = uniquify(formats);
586         mods_formats = uniquify(mods_formats);
587
588         return {
589                 formats                 : formats,
590                 mods_formats    : mods_formats,
591                 lang                            : data[2],
592                 largeprint              : data[1]
593         };
594 }
595
596
597 function holdsSetFormatSelector() {
598         var type = holdArgs.type;
599         if( type == 'C' || type == 'V' || type == "I" || holdArgs.editHold ) return;
600
601         var data                                = holdsGetFormats();
602         var avail_formats       = data.avail_formats;
603         var sel_formats = data.sel_formats;
604         holdArgs.language = data.lang;
605         if( type=='M'){         
606                 hideMe($('holds_alt_formats_row_extras'));
607                 unHideMe($('holds_alt_formats_row'));   
608         }else{
609                 unHideMe($('holds_alt_formats_row_extras'));
610         }
611
612         var selector = $('hold_alt_form_selector');
613
614     for( var i = 0; i < selector.options.length; i++ ) {
615         if (selector.options[i].className.indexOf('hide_me') == -1)
616             hideMe(selector.options[i]);
617     }
618
619         for( var i = 0; i < avail_formats.length; i++ ) {
620                 var form = avail_formats[i];
621                 var opt = findFormatSelectorOptByParts(selector,form);
622         if (!opt) continue;
623                 if(type=='M') opt.selected=true;
624                 unHideMe(opt);
625         }
626 }
627
628 function findFormatSelectorOptByParts( sel, val ) {
629     var parts = val.split('-');
630     for( var i = 0; i < sel.options.length; i++ ) {
631         var opt = sel.options[i];
632         var oval = opt.value;
633         var oparts = oval.split('-');
634         if( oparts[0].indexOf(parts[0]) > -1 && (!parts[1] || oparts[1].indexOf(parts[1]) > -1) ) return opt;
635     }
636     return null;
637 }
638
639 function holdsGetFormats() {
640
641         var lang;
642         var formats = [];
643         var sformats = []; // selected formats 
644
645         var type = holdArgs.type;
646         var desc = holdArgs.recordDescriptors;
647         var rec = holdArgs.record;
648         var mrec = holdArgs.metarecord;
649
650
651         if( type == 'T') {
652
653                 for( var i = 0; i < desc.length; i++ ) {
654                         var d = desc[i];
655                         if( d.record() == holdArgs.record ) {
656                                 lang = d.item_lang();
657                                 holdArgs.myFormat =  _t_f_2_format(d.item_type(), d.item_form());
658                                 sformats.push(holdArgs.myFormat);
659                                 break;
660                         }
661                 }
662
663         for( var i = 0; i < desc.length; i++ ) {
664                 var d = desc[i];
665                     if( type == 'T' && d.item_lang() != lang ) continue;
666                 formats.push( _t_f_2_format(d.item_type(), d.item_form()));
667             }
668
669         } else if( type =='M') {
670
671         // All available formats are selected by default in MR holds
672         for( var i = 0; i < desc.length; i++ ) {
673                 var d = desc[i];
674                     var _tmp_f = _t_f_2_format(d.item_type(), d.item_form());
675                 formats.push( _tmp_f );
676                 sformats.push( _tmp_f );
677         }
678         }
679
680         formats = uniquify(formats);
681         sformats = uniquify(sformats);
682
683         return {
684                 lang : lang,
685                 avail_formats : formats, 
686                 sel_formats : sformats
687         };
688 }
689
690
691
692 function _t_f_2_format(type, form) {
693         if( (type == 'a' || type == 't') && form == 's' ) return 'at-s';
694         if( form == 'd' ) return 'at-d';
695         return (type == 'a' || type == 't') ? 'at' : type;
696 }
697
698 function holdsSetSelectedFormats() {
699
700         var cn = $('holds_alt_formats_row').className;
701         if( cn && cn.match(/hide_me/) ) return;
702
703         var selector = $('hold_alt_form_selector');
704         var vals = getSelectedList(selector);
705
706         if(vals.length == 0) return;
707
708         var fstring = "";
709
710         if( contains(vals, 'at-d') || contains(vals, 'at-s')) {
711                 if( contains(vals, 'at') ) {
712                         fstring = 'at';
713                 } else if (contains(vals, 'at-s') && contains(vals, 'at-d')) {
714                         fstring = 'at-sd';
715                 } else if (!contains(vals, 'at-s')) {
716                         fstring = 'at-d';
717         } else {
718                         fstring = 'at-s';
719                 }
720         }
721
722         for( var i = 0; i < vals.length; i++ ) {
723                 var val = vals[i];
724                 if( !val.match(/at/) ) fstring = val + fstring;
725         }
726
727         if( holdArgs.language ) {
728                 if( fstring.match(/-/) )
729                         fstring = fstring + '-' + holdArgs.language;
730                 else
731                         fstring = fstring + '--' + holdArgs.language;
732         }
733
734
735         return fstring;
736 }
737
738
739 function holdsCheckPossibility(pickuplib, hold, recurse) {
740
741         var args = { 
742                 titleid : holdArgs.record,
743                 mrid : holdArgs.metarecord,
744                 volume_id : holdArgs.volume,
745                 issuanceid : holdArgs.issuance,
746                 copy_id : holdArgs.copy,
747                 hold_type : holdArgs.type,
748                 patronid : holdArgs.recipient.id(),
749                 depth : 0, 
750                 pickup_lib : pickuplib 
751         };
752
753         if(recurse) {
754                 /* if we're calling create again (recursing), 
755                         we know that the hold possibility check already succeeded */
756                 holdHandleCreateResponse({_recurse:true, _hold:hold}, true );
757
758         } else {
759                 _debug("hold possible args = "+js2JSON(args));
760         
761                 var req = new Request(CHECK_HOLD_POSSIBLE, G.user.session, args );
762         
763                 req.request.alertEvent = false;
764                 req.request._hold = hold;
765                 req.request._recurse = recurse;
766                 req.callback(holdHandleCreateResponse);
767                 req.send();
768         }
769 }
770
771
772 function holdsBuildOrgSelector(node) {
773
774         if(!node) node = globalOrgTree;
775         if(!isTrue(node.opac_visible())) return;
776
777         var render_this_org = true;
778         var orgHiding = checkOrgHiding(); // value here is cached so not too painful with the recursion
779         if (orgHiding) {
780                 if (node.id() == globalOrgTree.id()) {
781                         node = orgHiding.org; // top of tree = org hiding context org
782                 }
783                 if ( ! orgIsMine( orgHiding.org, node, orgHiding.depth ) ) {
784                         render_this_org = false;
785                 }
786         }
787
788         if (render_this_org) {
789                 var selector = $('holds_org_selector');
790                 var index = selector.options.length;
791
792                 var type = findOrgType(node.ou_type());
793                 var indent = type.depth() - 1;
794
795                 var opt = setSelectorVal( selector, index, node.name(), node.id(), null, indent );
796                 if(!type.can_have_users()) {
797                         opt.disabled = true;
798                         addCSSClass(opt, 'disabled_option');
799                 }
800         }
801         
802         for( var i in node.children() ) {
803                 var child = node.children()[i];
804                 if(child) holdsBuildOrgSelector(child);
805         }
806 }
807
808 function holdsBuildHoldFromWindow() {
809
810         var org = getSelectorVal($('holds_org_selector'));
811         var node = findOrgUnit(org);
812         var ntype = findOrgType(node.ou_type());
813         if(!ntype.can_have_users()) {
814                 alertId('holds_pick_good_org');
815                 return;
816         }
817
818     fieldmapper.IDL.load(['ahr']);
819         var hold = new ahr();
820         if(holdArgs.editHold) {
821                 hold = holdArgs.editHold;
822                 holdArgs.editHold = null;
823         }
824
825         if( $('holds_enable_phone').checked ) {
826                 var phone = $('holds_phone').value;
827                 if( !phone || !phone.match(REGEX_PHONE) ) {
828                         alert($('holds_bad_phone').innerHTML);
829                         return null;
830                 }
831                 hold.phone_notify(phone);
832
833         } else {
834                 hold.phone_notify("");
835         }
836
837         if( $('holds_enable_email').checked ) 
838                 hold.email_notify(1);
839         else
840                 hold.email_notify(0);
841
842         var target = holdArgs[holdTargetTypeMap[holdArgs.type]];
843
844         hold.pickup_lib(org); 
845         //hold.request_lib(org); 
846         hold.requestor(holdArgs.requestor.id());
847         hold.usr(holdArgs.recipient.id());
848         hold.target(target);
849         hold.hold_type(holdArgs.type);
850
851     var expDate = dijit.byId('holds_expire_time').getValue();
852     if(expDate) {
853         var expireDate = dojo.date.stamp.toISOString(expDate);
854         expireDate = holdsVerifyThawDate(expireDate); 
855         if(expireDate)
856             hold.expire_time(expireDate);
857         else 
858             return;
859     }
860
861     // see if this hold should be frozen and for how long
862     if($('holds_frozen_chkbox').checked) {
863         hold.frozen('t');
864         unHideMe($('hold_frozen_thaw_row'));
865         var thawDate = dijit.byId('holds_frozen_thaw_input').attr('value');
866         if(thawDate) {
867             thawDate = dojo.date.stamp.toISOString(thawDate);
868             thawDate = holdsVerifyThawDate(thawDate); 
869             if(thawDate) 
870                 hold.thaw_date(thawDate);
871             else
872                 return;
873         } else {
874             hold.thaw_date(null);
875         }
876     } else {
877         hold.frozen('f');
878         hold.thaw_date(null);
879     }
880
881         //check for alternate hold formats 
882         var fstring = holdsSetSelectedFormats();
883         if(fstring) { 
884                 hold.hold_type('M'); 
885                 hold.holdable_formats(fstring);
886                 hold.target(holdArgs.metarecord);
887         }
888         return hold;
889 }
890         
891 function holdsPlaceHold(hold, recurse) {
892         if(!hold) return;
893         swapCanvas($('check_holds_box'));
894         holdsCheckPossibility(hold.pickup_lib(), hold, recurse);
895 }
896
897
898 function holdHandleCreateResponse(r, recurse) {
899
900         if(!recurse) {
901                 var res = r.getResultObject();
902                 if(checkILSEvent(res) || res.success != 1) {
903                         if(res.success != 1) {
904                                 alert($('hold_not_allowed').innerHTML);
905                         } else {
906                                 if( res.textcode == 'PATRON_BARRED' ) {
907                                         alertId('hold_failed_patron_barred');
908                         } else {
909                                         alert($('hold_not_allowed').innerHTML);
910                                 }
911                         }
912                         swapCanvas($('holds_box'));
913                         return;
914                 }
915         r._hold.selection_depth(res.depth);
916         }       
917
918         holdCreateHold(r._recurse, r._hold);
919 }
920
921
922 function holdCreateHold( recurse, hold ) {
923         var method = CREATE_HOLD;
924         if(recurse) method = CREATE_HOLD_OVERRIDE;
925         var req = new Request( method, holdArgs.requestor.session, hold );
926         req.request.alertEvent = false;
927         req.send(true);
928         var res = req.result();
929         holdProcessResult(hold, res, recurse);
930         
931         showCanvas();
932
933         runEvt('common', 'holdUpdated');
934 }
935
936
937 function holdProcessResult( hold, res, recurse ) {
938
939         if( res && res > -1 ) {
940                 alert($('holds_success').innerHTML);
941                 holdArgs = null;
942         if(isXUL() && typeof xulG.opac_hold_placed == 'function')
943             xulG.opac_hold_placed(res);
944
945         } else {
946
947                 if( recurse ) {
948                         alert($('holds_failure').innerHTML);
949                         return;
950                 }
951
952                 if( grep(res, function(e) { return (e.textcode == 'HOLD_EXISTS'); }) ) {
953                         if( fetchPermOrgs('HOLD_EXISTS.override')[0] != -1 ) {
954                                 if( confirm($('hold_dup_exists_override').innerHTML) ) {
955                                         return holdsPlaceHold(hold, true);
956                                 }
957                 return;
958
959                         } else {
960                                 return alert($('hold_dup_exists').innerHTML);
961                         }
962                 }
963
964                 if( grep(res, function(e) { return (e.textcode == 'HOLD_ITEM_CHECKED_OUT'); }) ) {
965                         if( fetchPermOrgs('HOLD_ITEM_CHECKED_OUT.override')[0] != -1 ) {
966                                 if( confirm($('hold_checked_out_override').innerHTML) ) {
967                                         return holdsPlaceHold(hold, true);
968                                 }
969                 return;
970
971                         } else {
972                                 return alert($('hold_checked_out').innerHTML);
973                         }
974                 }
975
976
977                 alert($('holds_failure').innerHTML);
978         }
979 }
980
981
982 function holdsCancel(holdid, user) {
983         if(!user) user = G.user;
984         var req = new Request(CANCEL_HOLD, user.session, holdid, /* Patron via OPAC */ 6);
985         req.send(true);
986         return req.result();
987         runEvt('common', 'holdUpdated');
988 }
989
990 function holdsUpdate(hold, user) {
991         if(!user) user = G.user;
992         var req = new Request(UPDATE_HOLD, user.session, hold);
993         req.send(true);
994         var x = req.result(); // cause an exception if there is one 
995         runEvt('common', 'holdUpdated');
996 }
997
998 /* verify that the thaw date is valid and after today */
999 function holdsVerifyThawDate(dateString, isGreater) {
1000     thawDate = dojo.date.stamp.fromISOString(dateString);
1001     if(thawDate) {
1002         if(isGreater) {
1003             if(dojo.date.compare(thawDate) > 0) {
1004                 return dojo.date.stamp.toISOString(thawDate);
1005             }
1006         } else {
1007             return dojo.date.stamp.toISOString(thawDate);
1008         }
1009     }
1010     return null;
1011 }
1012
1013 function holdsVerifyThawDateUI(element) {
1014     value = dojo.date.stamp.toISOString(dijit.byId(element).getValue());
1015
1016     if(!value) {
1017         removeCSSClass($(element), 'invalid_field');
1018         return;
1019     }
1020
1021     if(!holdsVerifyThawDate(value, true)) {
1022         addCSSClass($(element), 'invalid_field');
1023     } else {
1024         removeCSSClass($(element), 'invalid_field');
1025     }
1026 }
1027