--- /dev/null
+load_lib('catalog/record_type.js');\r
+load_lib('circ/circ_groups.js');\r
+load_lib('JSON_v1.js');\r
+\r
+\r
+try {\r
+ if( environment.copy ) {\r
+ environment.copy.fetchBestHold = function() {\r
+ var key = scratchKey();\r
+ environment.copy.__OILS_FUNC_fetch_best_hold(scratchPad(key));\r
+ var val = getScratch(key);\r
+ return (val) ? val : null;\r
+ }\r
+ }\r
+} catch(e) {}\r
+\r
+\r
+/* ----------------------------------------------------------------------------- \r
+ Collect all of the global variables\r
+ ----------------------------------------------------------------------------- */\r
+\r
+/* the global result object. Any data returned to the \r
+ caller must be put into this object. */\r
+var result = environment.result = {};\r
+result.event = 'SUCCESS';\r
+result.events = [];\r
+result.fatalEvents = [];\r
+result.infoEvents = [];\r
+\r
+\r
+/* Pull in any variables passed in from the calling process */\r
+var copy = environment.copy;\r
+var volume = environment.volume;\r
+var title = environment.title;\r
+var recDescriptor = environment.titleDescriptor;\r
+var patron = environment.patron;\r
+var patronItemsOut = environment.patronItemsOut;\r
+var patronOverdueCount = environment.patronOverdueCount;\r
+var patronFines = environment.patronFines;\r
+var isRenewal = environment.isRenewal;\r
+var isPrecat = environment.isPrecat;\r
+var currentLocation = environment.location;\r
+var holdRequestLib = environment.requestLib;\r
+var holdPickupLib = environment.pickupLib; /* hold pickup lib */\r
+var requestor = environment.requestor || patron;\r
+var newHold = environment.newHold;\r
+\r
+\r
+\r
+/* create some new vars based on the data we have wherever possible */\r
+var patronProfile;\r
+var copyStatus;\r
+var marcXMLDoc;\r
+\r
+if( patron && patron.profile ) \r
+ patronProfile = patron.profile.name;\r
+if( copy && copy.status ) \r
+ copyStatus = copy.status.name;\r
+if( title && title.marc )\r
+ marcXMLDoc = new XML(title.marc);\r
+\r
+\r
+\r
+/* copy the group tree into some other useful data structures */\r
+var groupTree = environment.groupTree;\r
+var groupList = {};\r
+var groupIDList = {};\r
+flattenGroupTree(groupTree);\r
+\r
+\r
+\r
+\r
+\r
+\r
+/* ----------------------------------------------------------------------------- \r
+ Define all of the utility functions\r
+ ----------------------------------------------------------------------------- */\r
+\r
+\r
+\r
+/* useful functions for creating wrappers around system functions */\r
+var __scratchKey = 0;\r
+var __SCRATCH = {};\r
+function scratchKey() { return '_' + __scratchKey++; };\r
+function scratchPad(key) { return '__SCRATCH.'+ key; }\r
+function getScratch(key) { return __SCRATCH[ key ]; }\r
+function scratchClear() { for( var o in __SCRATCH ) __SCRATCH[o] = null; }\r
+\r
+\r
+/* note: returns false if the value is 'f' or 'F' ... */\r
+function isTrue(d) {\r
+ if( d && \r
+ d != "0" && \r
+ d != "f" &&\r
+ d != "F" )\r
+ return true;\r
+ return false;\r
+}\r
+\r
+/* Utility function for iterating over array */\r
+function iterate( arr, callback ) {\r
+ for( var i = 0; i < arr.length; i++ ) \r
+ callback(arr[i]);\r
+}\r
+\r
+\r
+/**\r
+ * returns a list of items that when passed to the callback \r
+ * 'func' returned true returns null if none were found\r
+ */\r
+function grep( arr, func ) {\r
+ var results = [];\r
+ iterate( arr, \r
+ function(d) {\r
+ if( func(d) ) \r
+ results.push(d);\r
+ }\r
+ );\r
+ if(results.length > 0) \r
+ return results;\r
+ return null;\r
+}\r
+\r
+\r
+\r
+function flattenGroupTree(node) {\r
+ if(!node) return null;\r
+ groupList[node.name] = node;\r
+ groupIDList[node.id] = node;\r
+ iterate( node.children,\r
+ function(n) {\r
+ flattenGroupTree(n);\r
+ }\r
+ );\r
+}\r
+\r
+\r
+\r
+/**\r
+ * Returns true if 'child' is equal or descends from 'parent'\r
+ * @param parent The name of the parent group\r
+ * @param child The name of the child group\r
+ */\r
+function isGroupDescendant( parent, child ) {\r
+ log_debug("checking descendant p="+parent + " c=" + child);\r
+ return __isGroupDescendant(\r
+ groupList[parent],\r
+ groupList[child]);\r
+}\r
+\r
+function isGroupDescendantId( parentName, childId ) {\r
+ log_debug("checking descendant ID p="+parentName + " c=" + childId);\r
+ return __isGroupDescendant(\r
+ groupList[parentName],\r
+ groupIDList[childId]);\r
+}\r
+\r
+\r
+/**\r
+ * Returns true if 'child' is equal or descends from 'parent'\r
+ * @param parent The node of the parent group\r
+ * @param child The node of the child group\r
+ */\r
+function __isGroupDescendant( parent, child ) {\r
+ if(!(parent && child)) return false;\r
+ if (parent.id == child.id) return true;\r
+ var node = child;\r
+ while( (node = groupIDList[node.parent]) ) {\r
+ if( node.id == parent.id ) \r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+\r
+function getMARCItemType() {\r
+ if( copy &&\r
+ copy.circ_as_type &&\r
+ copy.circ_as_type != 'undef' )\r
+ return copy.circ_as_type;\r
+ \r
+ return (marcXMLDoc) ? extractFixedField(marcXMLDoc, 'Type') : "";\r
+}\r
+\r
+\r
+function isOrgDescendent( parentName, childId ) {\r
+ var key = scratchKey();\r
+ __OILS_FUNC_isOrgDescendent(scratchPad(key), parentName, childId);\r
+ var val = getScratch(key);\r
+ if( val == '1' ) return true;\r
+ return false;\r
+}\r
+\r
+/* returns the number of unfulfilled holds open on this user */\r
+function userHoldCount(userid) {\r
+ var key = scratchKey();\r
+ __OILS_FUNC_userHoldCount(scratchPad(key), userid);\r
+ return getScratch(key);\r
+}\r
+\r
+function hasCommonAncestor( org1, org2, depth ) {\r
+ var key = scratchKey();\r
+ __OILS_FUNC_hasCommonAncestor(scratchPad(key), org1, org2, depth);\r
+ var val = getScratch(key);\r
+ if( val == '1' ) return true;\r
+ return false;\r
+}\r
+\r
+/* returns a dictionary of circmod : count for checked out items */\r
+function checkoutsByCircModifier(userid) {\r
+ var key = scratchKey();\r
+ __OILS_FUNC_userCircsByCircmod(scratchPad(key), userid);\r
+ var val = getScratch(key);\r
+ return (val) ? val : {};\r
+}\r
+\r
+/* useful for testing */\r
+function die(msg) {\r
+ log_error("die(): "+msg);\r
+ log_stderr("die(): "+msg);\r
+ var foo = null;\r
+ var baz = foo.bar;\r
+}\r
+\r
+\r
+\r
+/* logs a load of info */\r
+function log_vars( prefix ) {\r
+ var str = prefix + ' : ';\r
+\r
+ if(patron) {\r
+ str += ' Patron=' + patron.id;\r
+ str += ', Patron_Username='+ patron.usrname;\r
+ str += ', Patron_Profile_Group='+ patronProfile;\r
+ str += ', Patron_Fines=' + patronFines;\r
+ str += ', Patron_OverdueCount=' + patronOverdueCount;\r
+ str += ', Patron_Items_Out=' + patronItemsOut;\r
+\r
+ try {\r
+ str += ', Patron_Barcode=' + patron.card.barcode;\r
+ str += ', Patron_Library=' + patron.home_ou.name;\r
+ } catch(e) {}\r
+ }\r
+\r
+ if(requestor.id != patron.id) \r
+ str+= ' Requestor='+requestor.usrname;\r
+\r
+ if(copy) {\r
+ str += ', Copy=' + copy.id;\r
+ str += ', Copy_Barcode=' + copy.barcode;\r
+ str += ', Copy_status=' + copyStatus;\r
+ str += (copy.circ_modifier) ? ', Circ_Mod=' + copy.circ_modifier : '';\r
+\r
+ try {\r
+ str += ', Circ_Lib=' + copy.circ_lib.shortname;\r
+ str += ', Copy_location=' + copy.location.name;\r
+ } catch(e) {}\r
+ }\r
+\r
+ if(volume) {\r
+ str += ', Item_Owning_lib=' + volume.owning_lib;\r
+ str += ', Volume=' + volume.id;\r
+ }\r
+\r
+ if(title) str += ', Record=' + title.id;\r
+\r
+ if(recDescriptor) {\r
+ str += ', Record_Descriptor=' + recDescriptor.id;\r
+ str += ', Item_Type=' + recDescriptor.item_type;\r
+ str += ', Item_Form=' + recDescriptor.item_form;\r
+ str += ', Item_Lang=' + recDescriptor.item_lang;\r
+ str += ', Item_Audience=' + recDescriptor.audience;\r
+ }\r
+\r
+ str += ', Is_Renewal: ' + ( (isTrue(isRenewal)) ? "yes" : "no" );\r
+ str += ', Is_Precat: ' + ( (isTrue(isPrecat)) ? "yes" : "no" );\r
+ str += (holdRequestLib) ? ', Hold_request_lib=' + holdRequestLib.shortname : '';\r
+ str += (holdPickupLib) ? ', Hold_Pickup_Lib=' + holdPickupLib : '';\r
+\r
+ log_info(str);\r
+}\r
+\r
+\r
+\r
+/**\r
+ * Returns config information for the requested group. If \r
+ * no config info exists for the requested group, then this\r
+ * function searches up the tree to find the config info \r
+ * for the nearest ancestor\r
+ * @param The name of the group who's config info to return\r
+ */\r
+function findGroupConfig(name) {\r
+ if(!name) return null;\r
+ var node = groupList[name];\r
+ do {\r
+ if( GROUP_CONFIG[node.name] ) {\r
+ debugGroupConfig(name, node.name, GROUP_CONFIG[node.name]);\r
+ return GROUP_CONFIG[node.name];\r
+ }\r
+ } while( (node = groupIDList[node.parent]) );\r
+ return null;\r
+}\r
+\r
+\r
+/** prints out the settings for the given group config **/\r
+function debugGroupConfig(name, foundName, config) {\r
+ if(!config) return;\r
+ var str = "findGroupConfig('"+name+"'): returning config info for '"+ foundName +"': ";\r
+ for( var i in config ) \r
+ str += i + '=' + config[i] + ' ';\r
+ log_debug(str);\r
+}\r
+\r
+\r
+/* custom functions for Windsor libraries */\r
+\r
+function isValidPatron(patronProfile) {\r
+ var valid_patrons = ['Faculty', 'Graduate', 'Undergraduate', 'Staff members', 'Readers'];\r
+ for (var i = 0; i < valid_patrons.length; i++) {\r
+ if (valid_patrons[i] == patronProfile) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+}\r
+\r