protecting against non-existent group in descendent check
[Evergreen.git] / Open-ILS / src / javascript / backend / circ / circ_lib.js
1 load_lib('catalog/record_type.js');
2 load_lib('circ/circ_groups.js');
3 load_lib('JSON_v1.js');
4
5
6 try {
7         if( environment.copy ) {
8                 environment.copy.fetchBestHold = function() {
9                         var key = scratchKey();
10                         environment.copy.__OILS_FUNC_fetch_best_hold(scratchPad(key));
11                         var val = getScratch(key);
12                         return (val) ? val : null;
13                 }
14         }
15 } catch(e) {}
16
17
18 /* ----------------------------------------------------------------------------- 
19         Collect all of the global variables
20         ----------------------------------------------------------------------------- */
21
22 /* the global result object.  Any data returned to the 
23         caller must be put into this object.  */
24 var result                              = environment.result = {};
25 result.event                    = 'SUCCESS';
26 result.events                   = [];
27 result.fatalEvents      = [];
28 result.infoEvents               = [];
29
30
31 /* Pull in any variables passed in from the calling process */
32 var copy                                        = environment.copy;
33 var volume                              = environment.volume;
34 var title                               = environment.title;
35 var recDescriptor               = environment.titleDescriptor;
36 var patron                              = environment.patron;
37 var patronItemsOut      = environment.patronItemsOut;
38 var patronOverdueCount  = environment.patronOverdueCount;
39 var patronFines         = environment.patronFines;
40 var isRenewal                   = environment.isRenewal;
41 var isPrecat                    = environment.isPrecat;
42 var currentLocation     = environment.location;
43 var holdRequestLib      = environment.requestLib;
44 var holdPickupLib       = environment.pickupLib; /* hold pickup lib */
45 var requestor = environment.requestor || patron;
46 var newHold = environment.newHold;
47
48
49
50 /* create some new vars based on the data we have wherever possible */
51 var patronProfile;
52 var copyStatus;
53 var marcXMLDoc;
54
55 if( patron && patron.profile ) 
56         patronProfile = patron.profile.name;
57 if( copy && copy.status ) 
58         copyStatus = copy.status.name;
59 if( title && title.marc )
60         marcXMLDoc = new XML(title.marc);
61
62
63
64 /* copy the group tree into some other useful data structures */
65 var groupTree           = environment.groupTree;
66 var groupList           = {};
67 var groupIDList = {};
68 flattenGroupTree(groupTree);
69
70
71
72
73
74
75 /* ----------------------------------------------------------------------------- 
76         Define all of the utility functions
77         ----------------------------------------------------------------------------- */
78
79
80
81 /* useful functions for creating wrappers around system functions */
82 var __scratchKey = 0;
83 var __SCRATCH = {};
84 function scratchKey()           { return '_' + __scratchKey++; };
85 function scratchPad(key)        { return '__SCRATCH.'+ key; }
86 function getScratch(key)        { return __SCRATCH[ key ]; }
87 function scratchClear()         { for( var o in __SCRATCH ) __SCRATCH[o] = null; }
88
89
90 /* note: returns false if the value is 'f' or 'F' ... */
91 function isTrue(d) {
92         if(     d && 
93                         d != "0" && 
94                         d != "f" &&
95                         d != "F" )
96                         return true;
97         return false;
98 }
99
100 /* Utility function for iterating over array */
101 function iterate( arr, callback ) {
102         for( var i = 0; i < arr.length; i++ ) 
103                 callback(arr[i]);
104 }
105
106
107 /**
108   * returns a list of items that when passed to the callback 
109   * 'func' returned true returns null if none were found
110   */
111 function grep( arr, func ) {
112         var results = [];
113         iterate( arr, 
114                 function(d) {
115                         if( func(d) ) 
116                                 results.push(d);
117                 }
118         );
119         if(results.length > 0)  
120                 return results;
121         return null;
122 }
123
124
125
126 function flattenGroupTree(node) {
127         if(!node) return null;
128         groupList[node.name] = node;
129         groupIDList[node.id] = node;
130         iterate( node.children,
131                 function(n) {
132                         flattenGroupTree(n);
133                 }
134         );
135 }
136
137
138
139 /**
140   * Returns true if 'child' is equal or descends from 'parent'
141   * @param parent The name of the parent group
142   * @param child The name of the child group
143   */
144 function isGroupDescendant( parent, child ) {
145         log_debug("checking descendant p="+parent + " c=" + child);
146         return __isGroupDescendant(
147                 groupList[parent],
148                 groupList[child]);
149 }
150
151 function isGroupDescendantId( parentName, childId ) {
152         log_debug("checking descendant ID p="+parentName + " c=" + childId);
153         return __isGroupDescendant(
154                 groupList[parentName],
155                 groupIDList[childId]);
156 }
157
158
159 /**
160   * Returns true if 'child' is equal or descends from 'parent'
161   * @param parent The node of the parent group
162   * @param child The node of the child group
163   */
164 function __isGroupDescendant( parent, child ) {
165     if(!(parent && child)) return false;
166         if (parent.id == child.id) return true;
167         var node = child;
168         while( (node = groupIDList[node.parent]) ) {
169                 if( node.id == parent.id ) 
170                         return true;
171         }
172         return false;
173 }
174
175
176 function getMARCItemType() {
177         if(     copy &&
178                         copy.circ_as_type &&
179                         copy.circ_as_type != 'undef' )
180                 return copy.circ_as_type;
181         
182         return (marcXMLDoc) ? extractFixedField(marcXMLDoc, 'Type') : "";
183 }
184
185
186 function isOrgDescendent( parentName, childId ) {
187         var key = scratchKey();
188         __OILS_FUNC_isOrgDescendent(scratchPad(key), parentName, childId);
189         var val = getScratch(key);
190         if( val == '1' ) return true;
191         return false;
192 }
193
194 /* returns the number of unfulfilled holds open on this user */
195 function userHoldCount(userid) {
196    var key = scratchKey();
197    __OILS_FUNC_userHoldCount(scratchPad(key), userid);
198    return getScratch(key);
199 }
200
201 function hasCommonAncestor( org1, org2, depth ) {
202         var key = scratchKey();
203         __OILS_FUNC_hasCommonAncestor(scratchPad(key), org1, org2, depth);
204         var val = getScratch(key);
205         if( val == '1' ) return true;
206         return false;
207 }
208
209 /* returns a dictionary of circmod : count for checked out items */
210 function checkoutsByCircModifier(userid) {
211     var key = scratchKey();
212     __OILS_FUNC_userCircsByCircmod(scratchPad(key), userid);
213     var val = getScratch(key);
214     return (val) ? val : {};
215 }
216
217 /* useful for testing */
218 function die(msg) {
219         log_error("die(): "+msg);
220         log_stderr("die(): "+msg);
221         var foo = null;
222         var baz = foo.bar;
223 }
224
225
226
227 /* logs a load of info */
228 function log_vars( prefix ) {
229         var str = prefix + ' : ';
230
231         if(patron) {
232                 str += ' Patron=' + patron.id;
233                 str += ', Patron_Username='+ patron.usrname;
234                 str += ', Patron_Profile_Group='+ patronProfile;
235                 str += ', Patron_Fines='        + patronFines;
236                 str += ', Patron_OverdueCount=' + patronOverdueCount;
237                 str += ', Patron_Items_Out=' + patronItemsOut;
238
239                 try {
240                         str += ', Patron_Barcode='      + patron.card.barcode;
241                         str += ', Patron_Library='      + patron.home_ou.name;
242                 } catch(e) {}
243         }
244
245     if(requestor.id != patron.id) 
246         str+= ' Requestor='+requestor.usrname;
247
248         if(copy)        {
249                 str += ', Copy=' + copy.id;
250                 str += ', Copy_Barcode=' + copy.barcode;
251                 str += ', Copy_status=' + copyStatus;
252       str += (copy.circ_modifier) ? ', Circ_Mod=' + copy.circ_modifier : '';
253
254                 try {
255                         str += ', Circ_Lib=' + copy.circ_lib.shortname;
256                         str += ', Copy_location=' + copy.location.name;
257                 } catch(e) {}
258         }
259
260         if(volume) {
261         str += ', Item_Owning_lib=' + volume.owning_lib;
262         str += ', Volume='      + volume.id;
263     }
264
265         if(title) str += ', Record='    + title.id;
266
267         if(recDescriptor)       {
268                 str += ', Record_Descriptor=' + recDescriptor.id;
269                 str += ', Item_Type='                   + recDescriptor.item_type;
270                 str += ', Item_Form='                   + recDescriptor.item_form;
271                 str += ', Item_Lang='                   + recDescriptor.item_lang;
272                 str += ', Item_Audience='               + recDescriptor.audience;
273         }
274
275         str += ', Is_Renewal: ' + ( (isTrue(isRenewal)) ? "yes" : "no" );
276         str += ', Is_Precat: '  + ( (isTrue(isPrecat)) ? "yes" : "no" );
277         str += (holdRequestLib) ? ', Hold_request_lib=' + holdRequestLib.shortname : '';
278     str += (holdPickupLib) ? ', Hold_Pickup_Lib=' + holdPickupLib : '';
279
280         log_info(str);
281 }
282
283
284
285 /**
286   * Returns config information for the requested group.  If 
287   * no config info exists for the requested group, then this
288   * function searches up the tree to find the config info 
289   * for the nearest ancestor
290   * @param The name of the group who's config info to return
291   */
292 function findGroupConfig(name) {
293         if(!name) return null;
294         var node = groupList[name];
295         do {
296                 if( GROUP_CONFIG[node.name] ) {
297                         debugGroupConfig(name, node.name, GROUP_CONFIG[node.name]);
298                         return GROUP_CONFIG[node.name];
299                 }
300         } while( (node = groupIDList[node.parent]) );
301         return null;
302 }
303
304
305 /** prints out the settings for the given group config **/
306 function debugGroupConfig(name, foundName, config) {
307         if(!config) return;
308         var str = "findGroupConfig('"+name+"'): returning config info for '"+ foundName +"': ";
309         for( var i in config ) 
310                 str += i + '=' + config[i] + '  ';
311         log_debug(str);
312 }
313
314