--- /dev/null
+dojo.require('dojo.date.locale');\r
+dojo.require('dojo.date.stamp');\r
+dojo.require('dijit.form.CheckBox');\r
+dojo.require('dijit.form.NumberSpinner');\r
+dojo.require('openils.CGI');\r
+dojo.require('openils.Util');\r
+dojo.require('openils.User');\r
+dojo.require('openils.Event');\r
+dojo.require('openils.widget.ProgressDialog');\r
+dojo.require('openils.widget.OrgUnitFilteringSelect');\r
+\r
+dojo.requireLocalization('openils.circ', 'selfcheck');\r
+var localeStrings = dojo.i18n.getLocalization('openils.circ', 'selfcheck');\r
+var selfCheckMgr;\r
+var itemsOutCirc = [];\r
+var itemsOutMod = [];\r
+var itemsOutCopy = [];\r
+var TIMEOUT = 45; // logout timer\r
+\r
+\r
+const SET_BARCODE_REGEX = 'opac.barcode_regex';\r
+const SET_PATRON_TIMEOUT = 'circ.selfcheck.patron_login_timeout';\r
+const SET_AUTO_OVERRIDE_EVENTS = 'circ.selfcheck.auto_override_checkout_events';\r
+const SET_PATRON_PASSWORD_REQUIRED = 'circ.selfcheck.patron_password_required';\r
+const SET_AUTO_RENEW_INTERVAL = 'circ.checkout_auto_renew_age';\r
+const SET_WORKSTATION_REQUIRED = 'circ.selfcheck.workstation_required';\r
+const SET_ALERT_POPUP = 'circ.selfcheck.alert.popup';\r
+const SET_ALERT_SOUND = 'circ.selfcheck.alert.sound';\r
+const SET_CC_PAYMENT_ALLOWED = 'credit.payments.allow';\r
+// This setting only comes into play if COPY_NOT_AVAILABLE is in the SET_AUTO_OVERRIDE_EVENTS list\r
+const SET_BLOCK_CHECKOUT_ON_COPY_STATUS = 'circ.selfcheck.block_checkout_on_copy_status';\r
+\r
+function SelfCheckManager() {\r
+ selfCheckMgr = this;\r
+ switchTo('step1');\r
+ \r
+ this.timer = null;\r
+ this.cgi = new openils.CGI();\r
+ this.staff = null; \r
+ this.workstation = null;\r
+ this.authtoken = null;\r
+\r
+ this.patron = null; \r
+ this.patronBarcodeRegex = null;\r
+\r
+ this.checkouts = [];\r
+ this.itemsOut = [];\r
+\r
+ // During renewals, keep track of the ID of the previous circulation. \r
+ // Previous circ is used for tracking failed renewals (for receipts).\r
+ this.prevCirc = null;\r
+\r
+ // current item barcode\r
+ this.itemBarcode = null; \r
+\r
+ // are we currently performing a renewal?\r
+ this.isRenewal = false; \r
+\r
+ // dict of org unit settings for "here"\r
+ this.orgSettings = {};\r
+\r
+ // Construct a mock checkout for debugging purposes\r
+ if(this.mockCheckouts = this.cgi.param('mock-circ')) {\r
+\r
+ this.mockCheckout = {\r
+ payload : {\r
+ record : new fieldmapper.mvr(),\r
+ copy : new fieldmapper.acp(),\r
+ circ : new fieldmapper.circ()\r
+ }\r
+ };\r
+\r
+ this.mockCheckout.payload.record.title('Jazz improvisation for guitar');\r
+ this.mockCheckout.payload.record.author('Wise, Les');\r
+ this.mockCheckout.payload.record.isbn('0634033565');\r
+ this.mockCheckout.payload.copy.barcode('123456789');\r
+ this.mockCheckout.payload.circ.renewal_remaining(1);\r
+ this.mockCheckout.payload.circ.parent_circ(1);\r
+ this.mockCheckout.payload.circ.due_date('2012-12-21');\r
+ }\r
+\r
+ this.initPrinter();\r
+}\r
+\r
+SelfCheckManager.prototype.keepMeLoggedIn = function() {\r
+ //alert(this.timer);\r
+ if(this.timer) try {clearTimeout(this.timer)} catch(e){}\r
+ this.timer = setTimeout('selfCheckMgr.logoutPatron();', TIMEOUT*1000);\r
+}\r
+\r
+/**\r
+ * Fetch the org-unit settings, initialize the display, etc.\r
+ */\r
+SelfCheckManager.prototype.init = function() {\r
+ this.staff = openils.User.user;\r
+ this.workstation = openils.User.workstation;\r
+ this.authtoken = openils.User.authtoken;\r
+ this.loadOrgSettings();\r
+\r
+ this.circTbody = dojo.byId('oils-selfck-circ-tbody');\r
+ this.itemsOutTbody = dojo.byId('oils-selfck-circ-out-tbody');\r
+\r
+ // workstation is required but none provided\r
+ if(this.orgSettings[SET_WORKSTATION_REQUIRED] && !this.workstation) {\r
+ if(confirm(dojo.string.substitute(localeStrings.WORKSTATION_REQUIRED))) {\r
+ this.registerWorkstation();\r
+ }\r
+ return;\r
+ }\r
+ \r
+ var self = this;\r
+ // connect onclick handlers to the various navigation links\r
+ var linkHandlers = {\r
+ 'oils-selfck-hold-details-link' : function() { self.drawHoldsPage(true); },\r
+ 'oils-selfck-view-fines-link' : function() { self.drawFinesPage(); openils.Util.show('oils-selfck-fines-tbody'); openils.Util.hide('pay_fines'); },\r
+ 'oils-selfck-pay-fines-link' : function() {\r
+ switchTo('step3','step3c');\r
+ openils.Util.hide('oils-selfck-fines-tbody');\r
+ openils.Util.show('pay_fines');\r
+ self.keepMeLoggedIn();\r
+ self.drawPayFinesPage(\r
+ self.patron,\r
+ self.getSelectedFinesTotal(),\r
+ self.getSelectedFineTransactions(),\r
+ function(resp) {\r
+ var evt = openils.Event.parse(resp);\r
+ if(evt) {\r
+ var message = evt + '';\r
+ if(evt.textcode == 'CREDIT_PROCESSOR_DECLINED_TRANSACTION' && evt.payload)\r
+ message += '\n' + evt.payload.error_message;\r
+ self.handleAlert(message, true, 'payment-failure');\r
+ return;\r
+ }\r
+ self.patron.last_xact_id(resp.last_xact_id);\r
+ self.printPaymentReceipt(\r
+ resp,\r
+ function() {\r
+ self.updateFinesSummary();\r
+ self.drawFinesPage();\r
+ }\r
+ );\r
+ }\r
+ );\r
+ },\r
+ //'oils-selfck-nav-home' : function() { self.drawCircPage(); },\r
+ 'oils-selfck-nav-logout' : function() { self.logoutPatron(); },\r
+ 'oils-selfck-nav-logout-print' : function() { self.logoutPatron(true); },\r
+ 'oils-selfck-items-out-details-link' : function() { self.drawItemsOutPage(); },\r
+ //'oils-selfck-print-list-link' : function() { self.printList(); }\r
+ }\r
+\r
+ for(var id in linkHandlers) {\r
+ //var obj1 = dojo.byId(id);\r
+ //obj1.onclick = linkHandlers[id];\r
+ dojo.connect(dojo.byId(id), 'onclick', linkHandlers[id]);\r
+ }\r
+\r
+\r
+ if(this.cgi.param('patron')) {\r
+ \r
+ // Patron barcode via cgi param. Mainly used for debugging and\r
+ // only works if password is not required by policy\r
+ this.loginPatron(this.cgi.param('patron'));\r
+\r
+ } else {\r
+ this.drawLoginPage();\r
+ }\r
+\r
+ /**\r
+ * To test printing, pass a URL param of 'testprint'. The value for the param\r
+ * should be a JSON string like so: [{circ:<circ_id>}, ...]\r
+ */\r
+ var testPrint = this.cgi.param('testprint');\r
+ if(testPrint) {\r
+ this.checkouts = JSON2js(testPrint);\r
+ this.printSessionReceipt();\r
+ this.checkouts = [];\r
+ }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.getSelectedFinesTotal = function() {\r
+ var total = 0;\r
+ dojo.forEach(\r
+ dojo.query("[name=selector]", this.finesTbody),\r
+ function(input) {\r
+ if(input.checked)\r
+ total += Number(input.balance_owed);\r
+ }\r
+ );\r
+ return total.toFixed(2);\r
+};\r
+\r
+SelfCheckManager.prototype.getSelectedFineTransactions = function() {\r
+ return dojo.query("[name=selector]", this.finesTbody).\r
+ filter(function (o) { return o.checked }).\r
+ map(\r
+ function (o) {\r
+ return [\r
+ o.getAttribute("xact"),\r
+ Number(o.balance_owed).toFixed(2)\r
+ ];\r
+ }\r
+ );\r
+};\r
+\r
+/**\r
+ * Registers a new workstion\r
+ */\r
+SelfCheckManager.prototype.registerWorkstation = function() {\r
+ \r
+ oilsSelfckWsDialog.show();\r
+\r
+ new openils.User().buildPermOrgSelector(\r
+ 'REGISTER_WORKSTATION', \r
+ oilsSelfckWsLocSelector, \r
+ this.staff.home_ou()\r
+ );\r
+\r
+\r
+ var self = this;\r
+ dojo.connect(oilsSelfckWsSubmit, 'onClick', \r
+\r
+ function() {\r
+ oilsSelfckWsDialog.hide();\r
+ var name = oilsSelfckWsLocSelector.attr('displayedValue') + '-' + oilsSelfckWsName.attr('value');\r
+\r
+ var res = fieldmapper.standardRequest(\r
+ ['open-ils.actor', 'open-ils.actor.workstation.register'],\r
+ { params : [\r
+ self.authtoken, name, oilsSelfckWsLocSelector.attr('value')\r
+ ]\r
+ }\r
+ );\r
+\r
+ if(evt = openils.Event.parse(res)) {\r
+ if(evt.textcode == 'WORKSTATION_NAME_EXISTS') {\r
+ if(confirm(localeStrings.WORKSTATION_EXISTS)) {\r
+ location.href = location.href.replace(/\?.*/, '') + '?ws=' + name;\r
+ } else {\r
+ self.registerWorkstation();\r
+ }\r
+ return;\r
+ } else {\r
+ alert(evt);\r
+ }\r
+ } else {\r
+ location.href = location.href.replace(/\?.*/, '') + '?ws=' + name;\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+/**\r
+ * Loads the org unit settings\r
+ */\r
+SelfCheckManager.prototype.loadOrgSettings = function() {\r
+\r
+ var settings = fieldmapper.aou.fetchOrgSettingBatch(\r
+ this.staff.ws_ou(), [\r
+ SET_BARCODE_REGEX,\r
+ SET_PATRON_TIMEOUT,\r
+ SET_ALERT_POPUP,\r
+ SET_ALERT_SOUND,\r
+ SET_AUTO_OVERRIDE_EVENTS,\r
+ SET_BLOCK_CHECKOUT_ON_COPY_STATUS,\r
+ SET_PATRON_PASSWORD_REQUIRED,\r
+ SET_AUTO_RENEW_INTERVAL,\r
+ SET_WORKSTATION_REQUIRED,\r
+ SET_CC_PAYMENT_ALLOWED\r
+ ]\r
+ );\r
+\r
+ for(k in settings) {\r
+ if(settings[k])\r
+ this.orgSettings[k] = settings[k].value;\r
+ }\r
+\r
+ if(settings[SET_BARCODE_REGEX]) \r
+ this.patronBarcodeRegex = new RegExp(settings[SET_BARCODE_REGEX].value);\r
+}\r
+\r
+SelfCheckManager.prototype.drawLoginPage = function() {\r
+ var self = this;\r
+ var bcHandler = function(barcode) {\r
+ // handle patron barcode entry\r
+\r
+ if(self.orgSettings[SET_PATRON_PASSWORD_REQUIRED]) {\r
+ \r
+ // password is required. wire up the scan box to read it\r
+ self.updateScanBox({\r
+ msg : 'Please enter your password', // TODO i18n \r
+ handler : function(pw) { self.loginPatron(barcode, pw); },\r
+ password : true\r
+ });\r
+\r
+ } else {\r
+ // password is not required, go ahead and login\r
+ self.loginPatron(barcode);\r
+ }\r
+ };\r
+\r
+ this.updateScanBox({\r
+ msg : 'Please log in with your library barcode.', // TODO\r
+ handler : bcHandler\r
+ });\r
+ \r
+ var txtBox = (dojo.byId('step2').style.display=='none') ? 'patron-login-username' : 'patron-login-password';\r
+ try{var a=dojo.byId(txtBox);a.focus();a.select();}catch(e){}\r
+}\r
+\r
+/**\r
+ * Login the patron. \r
+ */\r
+SelfCheckManager.prototype.loginPatron = function(barcode, passwd) {\r
+ \r
+ //if(this.orgSettings[SET_PATRON_PASSWORD_REQUIRED]) { // password always reqired, per KCLS - fail safe\r
+ if(!passwd) {\r
+ // would only happen in dev/debug mode when using the patron= param\r
+ alert('password required by org setting. remove patron= from URL'); \r
+ return;\r
+ }\r
+\r
+ // patron password is required. Verify it.\r
+\r
+ var res = fieldmapper.standardRequest(\r
+ ['open-ils.actor', 'open-ils.actor.verify_user_password'],\r
+ {params : [this.authtoken, barcode, null, hex_md5(passwd)]}\r
+ );\r
+\r
+ if(res == 0) {\r
+ // user-not-found results in login failure\r
+ this.handleAlert(\r
+ dojo.string.substitute(localeStrings.LOGIN_FAILED, [barcode]),\r
+ false, 'login-failure'\r
+ );\r
+ this.drawLoginPage();\r
+ openils.Util.show('back_to_login');\r
+ return;\r
+ }\r
+ //} \r
+\r
+ // retrieve the fleshed user by barcode\r
+ this.patron = fieldmapper.standardRequest(\r
+ ['open-ils.actor', 'open-ils.actor.user.fleshed.retrieve_by_barcode'],\r
+ {params : [this.authtoken, barcode]}\r
+ );\r
+\r
+ var evt = openils.Event.parse(this.patron);\r
+ if(evt) {\r
+ this.handleAlert(\r
+ dojo.string.substitute(localeStrings.LOGIN_FAILED, [barcode]),\r
+ false, 'login-failure'\r
+ );\r
+ this.drawLoginPage();\r
+ openils.Util.show('back_to_login');\r
+\r
+ } else {\r
+\r
+ //this.handleAlert('', true, 'login-success');\r
+ dojo.byId('user_name').innerHTML = \r
+ dojo.string.substitute(localeStrings.WELCOME_BANNER, [this.patron.first_given_name()]);\r
+ dojo.byId('oils-selfck-status-div').innerHTML = '';\r
+ dojo.byId('oils-selfck-status-div2').innerHTML = '';\r
+ dojo.byId('oils-selfck-status-div3').innerHTML = '';\r
+ openils.Util.hide('back_to_login');\r
+ this.drawCircPage();\r
+ }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.handleAlert = function(message, shouldPopup, sound) {\r
+ console.log("Handling alert " + message);\r
+\r
+ dojo.byId('oils-selfck-status-div').innerHTML = message;\r
+ if(!this.patron){\r
+ dojo.byId('oils-selfck-status-div2').innerHTML = message;\r
+ dojo.byId('oils-selfck-status-div3').innerHTML = message;\r
+ }\r
+ \r
+ if(shouldPopup && this.orgSettings[SET_ALERT_POPUP]) \r
+ alert(message);\r
+\r
+ if(this.orgSettings[SET_ALERT_SOUND])\r
+ openils.Util.playAudioUrl(SelfCheckManager.audioConfig[sound]);\r
+}\r
+\r
+\r
+/**\r
+ * Manages the main input box\r
+ * @param msg The context message to display with the box\r
+ * @param clearOnly Don't update the context message, just clear the value and re-focus\r
+ * @param handler Optional "on-enter" handler. \r
+ */\r
+SelfCheckManager.prototype.updateScanBox = function(args) {\r
+ args = args || {};\r
+\r
+ if(args.select) {\r
+ selfckScanBox.domNode.select();\r
+ } else {\r
+ selfckScanBox.attr('value', '');\r
+ }\r
+\r
+ if(args.password) {\r
+ selfckScanBox.domNode.setAttribute('type', 'password');\r
+ } else {\r
+ selfckScanBox.domNode.setAttribute('type', '');\r
+ }\r
+\r
+ if(args.value)\r
+ selfckScanBox.attr('value', args.value);\r
+\r
+ if(args.msg) \r
+ dojo.byId('oils-selfck-scan-text').innerHTML = args.msg;\r
+\r
+ if(selfckScanBox._lastHandler && (args.handler || args.clearHandler)) {\r
+ dojo.disconnect(selfckScanBox._lastHandler);\r
+ }\r
+\r
+ if(args.handler) {\r
+\r
+ selfckScanBox._lastHandler = dojo.connect(\r
+ selfckScanBox, \r
+ 'onKeyDown', \r
+ function(e) {\r
+ if(e.keyCode != dojo.keys.ENTER) \r
+ return;\r
+ args.handler(selfckScanBox.attr('value'));\r
+ }\r
+ );\r
+ }\r
+\r
+ selfckScanBox.focus();\r
+}\r
+\r
+/**\r
+ * Sets up the checkout/renewal interface\r
+ */\r
+SelfCheckManager.prototype.drawCircPage = function() {\r
+ this.keepMeLoggedIn();\r
+ openils.Util.show('oils-selfck-circ-tbody', 'table-row-group');\r
+ switchTo('step3');\r
+\r
+ var self = this;\r
+ this.updateScanBox({\r
+ msg : 'Please enter an item barcode', // TODO i18n\r
+ handler : function(barcode) { \r
+ openils.Util.show('oils-selfck-fines-tbody'); \r
+ openils.Util.hide('pay_fines'); switchTo('step3'); \r
+ self.checkout(barcode); }\r
+ });\r
+\r
+ if(!this.circTemplate)\r
+ this.circTemplate = this.circTbody.removeChild(dojo.byId('oils-selfck-circ-row'));\r
+\r
+ // fines summary\r
+ this.updateFinesSummary();\r
+\r
+ // holds summary\r
+ this.updateHoldsSummary();\r
+\r
+ // items out summary\r
+ this.updateCircSummary();\r
+\r
+ // render mock checkouts for debugging?\r
+ if(this.mockCheckouts) {\r
+ for(var i in [1,2,3]) \r
+ this.displayCheckout(this.mockCheckout, 'checkout');\r
+ }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.updateFinesSummary = function() {\r
+ var self = this; \r
+\r
+ // fines summary\r
+ fieldmapper.standardRequest(\r
+ ['open-ils.actor', 'open-ils.actor.user.fines.summary'],\r
+ { async : true,\r
+ params : [this.authtoken, this.patron.id()],\r
+ oncomplete : function(r) {\r
+ var summary = openils.Util.readResponse(r);\r
+ var finesSum = dojo.byId('acct_fines');\r
+ var bal = summary.balance_owed();\r
+ var bal2 = parseFloat(bal);\r
+ \r
+ if(bal2>0) {finesSum.style.color="red"; openils.Util.show('oils-selfck-pay-fines-link');}\r
+ finesSum.innerHTML = dojo.string.substitute(localeStrings.TOTAL_FINES_ACCOUNT, [bal2.toFixed(2)]);\r
+ self.creditPayableBalance = bal2+'';\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.drawItemsOutPage = function() {\r
+ this.keepMeLoggedIn();\r
+ switchTo('step3','step3d');\r
+\r
+ if(!this.outTemplate)\r
+ this.outTemplate = this.itemsOutTbody.removeChild(dojo.byId('oils-selfck-circ-out-row'));\r
+ while(this.itemsOutTbody.childNodes[0])\r
+ this.itemsOutTbody.removeChild(this.itemsOutTbody.childNodes[0]);\r
+\r
+ progressDialog.show(true);\r
+ var self = this;\r
+ \r
+ fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.actor.user.checked_out.atomic'],\r
+ {\r
+ async : true,\r
+ params : [this.authtoken, this.patron.id()],\r
+ oncomplete : function(r) {\r
+ var resp = openils.Util.readResponse(r);\r
+\r
+ var circs = resp.sort(\r
+ function(a, b) {\r
+ if(a.circ.due_date() > b.circ.due_date())\r
+ return -1;\r
+ return 1;\r
+ }\r
+ );\r
+\r
+ self.itemsOut = [];\r
+ dojo.forEach(circs,\r
+ function(circ) {\r
+ self.itemsOut.push(circ.circ.id());\r
+ handleCheckedItems(circ);\r
+ }\r
+ );\r
+ progressDialog.hide();\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+function handleCheckedItems(circ) {\r
+ var self = selfCheckMgr;\r
+ var row = self.outTemplate.cloneNode(true);\r
+ \r
+ self.byName(row,'barcode').innerHTML = circ.copy.barcode();\r
+ self.byName(row,'title').innerHTML = circ.record.title();\r
+ self.byName(row,'author').innerHTML = circ.record.author();\r
+ if(dojo.date.stamp.fromISOString(circ.circ.due_date())<(new Date())) self.byName(row,'due_date').style.color="red";\r
+ self.byName(row,'due_date').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(circ.circ.due_date()), {selector: 'date', fullYear: true});\r
+ self.byName(row,'format').innerHTML = circ.record.types_of_resource()[0];\r
+ \r
+ self.itemsOutTbody.appendChild(row);\r
+}\r
+\r
+SelfCheckManager.prototype.goToTab = function(name) {\r
+ this.tabName = name;\r
+\r
+ openils.Util.hide('oils-selfck-fines-page');\r
+ openils.Util.hide('oils-selfck-payment-page');\r
+ openils.Util.hide('oils-selfck-holds-page');\r
+ openils.Util.hide('oils-selfck-circ-page');\r
+ openils.Util.hide('oils-selfck-pay-fines-link');\r
+ \r
+ switch(name) {\r
+ case 'checkout':\r
+ openils.Util.show('oils-selfck-circ-page');\r
+ break;\r
+ case 'items_out':\r
+ openils.Util.show('oils-selfck-circ-page');\r
+ break;\r
+ case 'holds':\r
+ openils.Util.show('oils-selfck-holds-page');\r
+ break;\r
+ case 'fines':\r
+ openils.Util.show('oils-selfck-fines-page');\r
+ break;\r
+ case 'payment':\r
+ openils.Util.show('oils-selfck-payment-page');\r
+ break;\r
+ }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.printList = function(which) {\r
+ this.keepMeLoggedIn();\r
+ switch(which) {\r
+ case 'checkout':\r
+ this.printSessionReceipt();\r
+ break;\r
+ case 'items_out':\r
+ this.printItemsOutReceipt();\r
+ break;\r
+ case 'holds':\r
+ this.printHoldsReceipt();\r
+ break;\r
+ case 'fines':\r
+ this.printFinesReceipt();\r
+ break;\r
+ }\r
+}\r
+\r
+SelfCheckManager.prototype.updateHoldsSummary = function() {\r
+ if(!this.holdsSummary) {\r
+ var summary = fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.holds.user_summary'],\r
+ {params : [this.authtoken, this.patron.id()]}\r
+ );\r
+\r
+ this.holdsSummary = {};\r
+ this.holdsSummary.ready = Number(summary['4']);\r
+ this.holdsSummary.total = 0;\r
+\r
+ for(var i in summary)\r
+ this.holdsSummary.total += Number(summary[i]);\r
+ }\r
+\r
+ dojo.byId('oils-selfck-holds-total').innerHTML =dojo.string.substitute("${0}) Item"+(this.holdsSummary.total==1?"":"s"),[this.holdsSummary.total]);\r
+ dojo.byId('oils-selfck-holds-ready').innerHTML =dojo.string.substitute("${0}) Item"+(this.holdsSummary.ready==1?"":"s"),[this.holdsSummary.ready]);\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.updateCircSummary = function(increment) {\r
+ if(!this.circSummary) {\r
+\r
+ var summary = fieldmapper.standardRequest(\r
+ ['open-ils.actor', 'open-ils.actor.user.checked_out.count'],\r
+ {params : [this.authtoken, this.patron.id()]}\r
+ );\r
+\r
+ this.circSummary = {\r
+ total : Number(summary.out) + Number(summary.overdue),\r
+ overdue : Number(summary.overdue),\r
+ session : 0\r
+ };\r
+ }\r
+\r
+ if(increment) {\r
+ // local checkout occurred. Add to the total and the session.\r
+ this.circSummary.total += 1;\r
+ this.circSummary.session += 1;\r
+ }\r
+\r
+ dojo.byId('oils-selfck-circ-account-total').innerHTML = dojo.string.substitute("${0}) Item"+(this.circSummary.total==1?"":"s"), [this.circSummary.total]);\r
+\r
+ /*\r
+ dojo.byId('oils-selfck-circ-session-total').innerHTML = \r
+ dojo.string.substitute(\r
+ localeStrings.TOTAL_ITEMS_SESSION, \r
+ [this.circSummary.session]\r
+ );\r
+ */\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.drawHoldsPage = function(bool) {\r
+ this.keepMeLoggedIn();\r
+ if(bool) switchTo('step3','step3f'); else switchTo('step3','step3e');\r
+\r
+ this.holdTbody = dojo.byId('oils-selfck-hold-tbody');\r
+ this.readyTbody = dojo.byId('oils-selfck-rdy-tbody');\r
+ if(!this.readyTemplate)\r
+ this.readyTemplate = this.readyTbody.removeChild(dojo.byId('oils-selfck-rdy-row'));\r
+ if(!this.holdTemplate)\r
+ this.holdTemplate = this.holdTbody.removeChild(dojo.byId('oils-selfck-hold-row'));\r
+ while(this.holdTbody.childNodes[0])\r
+ this.holdTbody.removeChild(this.holdTbody.childNodes[0]);\r
+ while(this.readyTbody.childNodes[0])\r
+ this.readyTbody.removeChild(this.readyTbody.childNodes[0]);\r
+\r
+ progressDialog.show(true);\r
+\r
+ var self = this;\r
+ fieldmapper.standardRequest( // fetch the hold IDs\r
+\r
+ ['open-ils.circ', 'open-ils.circ.holds.id_list.retrieve'],\r
+ { async : true,\r
+ params : [this.authtoken, this.patron.id()],\r
+\r
+ oncomplete : function(r) { \r
+ var ids = openils.Util.readResponse(r);\r
+ if(!ids || ids.length == 0) {\r
+ progressDialog.hide();\r
+ return;\r
+ }\r
+\r
+ fieldmapper.standardRequest( // fetch the hold objects with fleshed details\r
+ ['open-ils.circ', 'open-ils.circ.hold.details.batch.retrieve'],\r
+ { async : true,\r
+ params : [self.authtoken, ids],\r
+\r
+ onresponse : function(rr) {\r
+ progressDialog.hide(); \r
+ self.drawHolds(openils.Util.readResponse(rr));\r
+ }\r
+ }\r
+ );\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+/**\r
+ * Fetch and add a single hold to the list of holds\r
+ */\r
+SelfCheckManager.prototype.drawHolds = function(holds) {\r
+ //this.keepMeLoggedIn();\r
+ this.holds = holds;\r
+ progressDialog.hide();\r
+ \r
+ var data = holds;\r
+ if(!data) return;\r
+ var row = this.holdTemplate.cloneNode(true);\r
+ var row2 = this.readyTemplate.cloneNode(true);\r
+\r
+ //if(data.mvr.isbn()) {\r
+ // this.byName(row, 'jacket').setAttribute('src', '/opac/extras/ac/jacket/small/' + data.mvr.isbn());\r
+ //}\r
+ \r
+ if(data.status == 4) {\r
+ this.byName(row2, 'title').innerHTML = data.mvr.title();\r
+ this.byName(row2, 'format').innerHTML = data.mvr.types_of_resource()[0];\r
+ this.byName(row2, 'lib').innerHTML = fieldmapper.aou.findOrgUnit(data.hold.pickup_lib()).name();\r
+ if(dojo.date.stamp.fromISOString(data.hold.capture_time())<(new Date())) this.byName(row2, 'date').style.color="red";\r
+ this.byName(row2, 'date').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(data.hold.capture_time()), {selector: 'date', fullYear: true});\r
+ this.readyTbody.appendChild(row2);\r
+ } else {\r
+\r
+ this.byName(row, 'title').innerHTML = data.mvr.title();\r
+ this.byName(row, 'author').innerHTML = data.mvr.author();\r
+ this.byName(row, 'format').innerHTML = data.mvr.types_of_resource()[0];\r
+\r
+ // hold is still pending\r
+ this.byName(row, 'status').innerHTML = dojo.string.substitute(localeStrings.HOLD_STATUS_WAITING,[data.queue_position, data.potential_copies]);\r
+ this.holdTbody.appendChild(row);\r
+ }\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.drawFinesPage = function() {\r
+ this.keepMeLoggedIn();\r
+ // TODO add option to hid scanBox\r
+ // this.updateScanBox(...)\r
+\r
+ //this.goToTab('fines');\r
+ switchTo('step3','step3c');\r
+ progressDialog.show(true);\r
+\r
+ //if(this.creditPayableBalance > 0 && this.orgSettings[SET_CC_PAYMENT_ALLOWED])\r
+ // openils.Util.show('oils-selfck-pay-fines-link', 'inline');\r
+ \r
+\r
+ this.finesTbody = dojo.byId('oils-selfck-fines-tbody');\r
+ if(!this.finesTemplate)\r
+ this.finesTemplate = this.finesTbody.removeChild(dojo.byId('oils-selfck-fines-row'));\r
+ while(this.finesTbody.childNodes[0])\r
+ this.finesTbody.removeChild(this.finesTbody.childNodes[0]);\r
+\r
+/*\r
+ // when user clicks on a selector checkbox, update the total owed\r
+ var updateSelected = function() {\r
+ var total = 0;\r
+ dojo.forEach(\r
+ dojo.query('[name=selector]', this.finesTbody),\r
+ function(input) {\r
+ if(input.checked)\r
+ total += Number(input.getAttribute('balance_owed'));\r
+ }\r
+ );\r
+\r
+ total = total.toFixed(2);\r
+ dojo.byId('oils-selfck-selected-total').innerHTML = \r
+ dojo.string.substitute(localeStrings.TOTAL_FINES_SELECTED, [total]);\r
+ }\r
+\r
+ // wire up the batch on/off selector\r
+ var sel = dojo.byId('oils-selfck-fines-selector');\r
+ sel.onchange = function() {\r
+ dojo.forEach(\r
+ dojo.query('[name=selector]', this.finesTbody),\r
+ function(input) {\r
+ input.checked = sel.checked;\r
+ }\r
+ );\r
+ };\r
+*/\r
+ var self = this;\r
+ var handler = function(dataList) {\r
+\r
+ self.finesCount = dataList.length;\r
+ self.finesData = dataList;\r
+\r
+ for(var i in dataList) {\r
+\r
+ var data = dataList[i];\r
+ var row = self.finesTemplate.cloneNode(true);\r
+ var type = data.transaction.xact_type();\r
+\r
+ if(type == 'circulation') {\r
+ self.byName(row, 'title').innerHTML = data.record.title();\r
+ if(dojo.date.stamp.fromISOString(data.circ.due_date())<(new Date())) self.byName(row, 'due_date').style.color="red";\r
+ self.byName(row, 'due_date').innerHTML = dojo.date.locale.format(dojo.date.stamp.fromISOString(data.circ.due_date()), {selector: 'date', fullYear: true});\r
+ self.byName(row, 'date_return').innerHTML = (data.circ.checkin_time())?dojo.date.locale.format(dojo.date.stamp.fromISOString(data.circ.checkin_time()), {selector: 'date', fullYear: true}):"";\r
+\r
+ } else if(type == 'grocery') {\r
+ self.byName(row, 'title').innerHTML = (data.transaction.last_billing_type())?("Miscellaneous - "+data.transaction.last_billing_type()):"Miscellaneous"; // Go ahead and head off any confusion around "grocery". TODO i18n\r
+ }\r
+\r
+ //self.byName(row, 'total_owed').innerHTML = data.transaction.total_owed();\r
+ //self.byName(row, 'total_paid').innerHTML = data.transaction.total_paid();\r
+ self.byName(row, 'balance').innerHTML = data.transaction.balance_owed();\r
+ self.byName(row, 'selector').balance_owed = data.transaction.balance_owed();\r
+ self.byName(row, 'selector').setAttribute('xact', data.transaction.id());\r
+/*\r
+ // row selector\r
+ var selector = self.byName(row, 'selector')\r
+ selector.onchange = updateSelected;\r
+ selector.setAttribute('xact', data.transaction.id());\r
+ selector.setAttribute('balance_owed', data.transaction.balance_owed());\r
+ selector.checked = true;\r
+*/\r
+ self.finesTbody.appendChild(row);\r
+ }\r
+\r
+ //updateSelected();\r
+ }\r
+\r
+\r
+ fieldmapper.standardRequest( \r
+ ['open-ils.actor', 'open-ils.actor.user.transactions.have_balance.fleshed'],\r
+ { async : true,\r
+ params : [this.authtoken, this.patron.id()],\r
+ oncomplete : function(r) { \r
+ progressDialog.hide();\r
+ handler(openils.Util.readResponse(r));\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+SelfCheckManager.prototype.checkin = function(barcode, abortTransit) {\r
+ var resp = fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.transit.abort'],\r
+ {params : [this.authtoken, {barcode : barcode}]}\r
+ );\r
+\r
+ // resp == 1 on success\r
+ if(openils.Event.parse(resp))\r
+ return false;\r
+\r
+ var resp = fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.checkin.override'],\r
+ {params : [\r
+ this.authtoken, {\r
+ patron_id : this.patron.id(),\r
+ copy_barcode : barcode,\r
+ noop : true\r
+ }\r
+ ]}\r
+ );\r
+\r
+ if(!resp.length) resp = [resp];\r
+ for(var i = 0; i < resp.length; i++) {\r
+ var tc = openils.Event.parse(resp[i]).textcode;\r
+ if(tc == 'SUCCESS' || tc == 'NO_CHANGE') {\r
+ continue;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+/**\r
+ * Check out a single item. If the item is already checked \r
+ * out to the patron, redirect to renew()\r
+ */\r
+SelfCheckManager.prototype.checkout = function(barcode, override) {\r
+ this.keepMeLoggedIn();\r
+ this.prevCirc = null;\r
+\r
+ if(!barcode) {\r
+ this.updateScanbox(null, true);\r
+ return;\r
+ }\r
+\r
+ if(this.mockCheckouts) {\r
+ // if we're in mock-checkout mode, just insert another\r
+ // fake circ into the table and get out of here.\r
+ this.displayCheckout(this.mockCheckout, 'checkout');\r
+ return;\r
+ }\r
+\r
+ // TODO see if it's a patron barcode\r
+ // TODO see if this item has already been checked out in this session\r
+\r
+ var method = 'open-ils.circ.checkout.full';\r
+ if(override) method += '.override';\r
+\r
+ console.log("Checkout out item " + barcode + " with method " + method);\r
+\r
+ var result = fieldmapper.standardRequest(\r
+ ['open-ils.circ', method],\r
+ {params: [\r
+ this.authtoken, {\r
+ patron_id : this.patron.id(),\r
+ copy_barcode : barcode\r
+ }\r
+ ]}\r
+ );\r
+\r
+ var stat = this.handleXactResult('checkout', barcode, result);\r
+\r
+ if(stat.override) {\r
+ this.checkout(barcode, true);\r
+ } else if(stat.doOver) {\r
+ this.checkout(barcode);\r
+ } else if(stat.renew) {\r
+ this.renew(barcode);\r
+ }\r
+}\r
+\r
+SelfCheckManager.prototype.failPartMessage = function(result) {\r
+ if (result.payload && result.payload.fail_part) {\r
+ var stringKey = "FAIL_PART_" +\r
+ result.payload.fail_part.replace(/\./g, "_");\r
+ return localeStrings[stringKey];\r
+ } else {\r
+ return null;\r
+ }\r
+}\r
+\r
+SelfCheckManager.prototype.handleXactResult = function(action, item, result) {\r
+ var displayText = '';\r
+\r
+ // If true, the display message is important enough to pop up. Whether or not\r
+ // an alert() actually occurs, depends on org unit settings\r
+ var popup = false; \r
+ var sound = ''; // sound file reference\r
+ var payload = result.payload || {};\r
+ var overrideEvents = this.orgSettings[SET_AUTO_OVERRIDE_EVENTS];\r
+ var blockStatuses = this.orgSettings[SET_BLOCK_CHECKOUT_ON_COPY_STATUS];\r
+ result.payload = payload;\r
+ \r
+ if(result.textcode == 'NO_SESSION') {\r
+\r
+ return this.logoutStaff();\r
+\r
+ } else if(result.textcode == 'SUCCESS') {\r
+\r
+ if(action == 'checkout') {\r
+\r
+ displayText = dojo.string.substitute(localeStrings.CHECKOUT_SUCCESS, [item]);\r
+ this.displayCheckout(result, 'checkout');\r
+\r
+ if(payload.holds_fulfilled && payload.holds_fulfilled.length) {\r
+ // A hold was fulfilled, update the hold numbers in the circ summary\r
+ console.log("fulfilled hold " + payload.holds_fulfilled + " during checkout");\r
+ this.holdsSummary = null;\r
+ this.updateHoldsSummary();\r
+ }\r
+\r
+ this.updateCircSummary(true);\r
+\r
+ } else if(action == 'renew') {\r
+\r
+ displayText = dojo.string.substitute(localeStrings.RENEW_SUCCESS, [item]);\r
+ this.displayCheckout(result, 'renew');\r
+ }\r
+\r
+ this.checkouts.push({circ : result.payload.circ.id()});\r
+ sound = 'checkout-success';\r
+ this.updateScanBox();\r
+\r
+ } else if(result.textcode == 'OPEN_CIRCULATION_EXISTS' && action == 'checkout') {\r
+\r
+ // Server says the item is already checked out. If it's checked out to the\r
+ // current user, we may need to renew it. \r
+\r
+ if(payload.old_circ) { \r
+\r
+ /*\r
+ old_circ refers to the previous checkout IFF it's for the same user. \r
+ If no auto-renew interval is not defined, assume we should renew it\r
+ If an auto-renew interval is defined and the payload comes back with\r
+ auto_renew set to true, do the renewal. Otherwise, let the patron know\r
+ the item is already checked out to them. */\r
+\r
+ if( !this.orgSettings[SET_AUTO_RENEW_INTERVAL] ||\r
+ (this.orgSettings[SET_AUTO_RENEW_INTERVAL] && payload.auto_renew) ) {\r
+ this.prevCirc = payload.old_circ.id();\r
+ return { renew : true };\r
+ }\r
+\r
+ popup = false;\r
+ sound = 'checkout-failure';\r
+ displayText = dojo.string.substitute(localeStrings.ALREADY_OUT, [item]);\r
+\r
+ } else {\r
+\r
+ if( // copy is marked lost. if configured to do so, check it in and try again.\r
+ result.payload.copy && \r
+ result.payload.copy.status() == /* LOST */ 3 &&\r
+ overrideEvents && overrideEvents.length &&\r
+ overrideEvents.indexOf('COPY_STATUS_LOST') != -1) {\r
+\r
+ if(this.checkin(item)) {\r
+ return { doOver : true };\r
+ }\r
+ }\r
+\r
+ \r
+ // item is checked out to some other user\r
+ popup = false;\r
+ sound = 'checkout-failure';\r
+ displayText = dojo.string.substitute(localeStrings.OPEN_CIRCULATION_EXISTS, [item]);\r
+ }\r
+\r
+ this.updateScanBox();\r
+\r
+ } else {\r
+\r
+ \r
+ if(overrideEvents && overrideEvents.length) {\r
+ \r
+ // see if the events we received are all in the list of\r
+ // events to override\r
+ \r
+ if(!result.length) result = [result];\r
+ \r
+ var override = true;\r
+ for(var i = 0; i < result.length; i++) {\r
+\r
+ var match = overrideEvents.filter(function(e) { return (e == result[i].textcode); })[0];\r
+\r
+ if(!match) {\r
+ override = false;\r
+ break;\r
+ }\r
+\r
+ if(result[i].textcode == 'COPY_NOT_AVAILABLE' && blockStatuses && blockStatuses.length) {\r
+\r
+ var stat = result[i].payload.status(); // copy status\r
+ if(typeof stat == 'object') stat = stat.id();\r
+\r
+ var match2 = blockStatuses.filter(function(e) { return (e == stat); })[0];\r
+\r
+ if(match2) { // copy is in a blocked status\r
+ override = false;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if(result[i].textcode == 'COPY_IN_TRANSIT') {\r
+ // to override a transit, we have to abort the transit and check it in first\r
+ if(this.checkin(item, true)) {\r
+ return { doOver : true };\r
+ } else {\r
+ override = false;\r
+ }\r
+ }\r
+ }\r
+\r
+ if(override) \r
+ return { override : true };\r
+ }\r
+ \r
+ this.updateScanBox();\r
+ popup = false;\r
+ sound = 'checkout-failure';\r
+\r
+ if(action == 'renew')\r
+ this.checkouts.push({circ : this.prevCirc, renewal_failure : true});\r
+\r
+ if(result.length) \r
+ result = result[0];\r
+\r
+ switch(result.textcode) {\r
+\r
+ // TODO custom handler for blocking penalties\r
+\r
+ case 'MAX_RENEWALS_REACHED' :\r
+ displayText = dojo.string.substitute(\r
+ localeStrings.MAX_RENEWALS, [item]);\r
+ break;\r
+\r
+ case 'ITEM_NOT_CATALOGED' :\r
+ displayText = dojo.string.substitute(\r
+ localeStrings.ITEM_NOT_CATALOGED, [item]);\r
+ break;\r
+\r
+ case 'OPEN_CIRCULATION_EXISTS' :\r
+ displayText = dojo.string.substitute(\r
+ localeStrings.OPEN_CIRCULATION_EXISTS, [item]);\r
+\r
+ break;\r
+\r
+ default:\r
+ console.error('Unhandled event ' + result.textcode);\r
+\r
+ if (!(displayText = this.failPartMessage(result))) {\r
+ if (action == 'checkout' || action == 'renew') {\r
+ displayText = dojo.string.substitute(\r
+ localeStrings.GENERIC_CIRC_FAILURE, [item]);\r
+ } else {\r
+ displayText = dojo.string.substitute(\r
+ localeStrings.UNKNOWN_ERROR, [result.textcode]);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ this.handleAlert(displayText, popup, sound);\r
+ return {};\r
+}\r
+\r
+\r
+/**\r
+ * Renew an item\r
+ */\r
+SelfCheckManager.prototype.renew = function(barcode, override) {\r
+\r
+ var method = 'open-ils.circ.renew';\r
+ if(override) method += '.override';\r
+\r
+ console.log("Renewing item " + barcode + " with method " + method);\r
+\r
+ var result = fieldmapper.standardRequest(\r
+ ['open-ils.circ', method],\r
+ {params: [\r
+ this.authtoken, {\r
+ patron_id : this.patron.id(),\r
+ copy_barcode : barcode\r
+ }\r
+ ]}\r
+ );\r
+\r
+ console.log(js2JSON(result));\r
+\r
+ var stat = this.handleXactResult('renew', barcode, result);\r
+\r
+ if(stat.override)\r
+ this.renew(barcode, true);\r
+}\r
+\r
+/**\r
+ * Display the result of a checkout or renewal in the items out table\r
+ */\r
+SelfCheckManager.prototype.displayCheckout = function(evt, type, itemsOut) {\r
+ var copy = evt.payload.copy;\r
+ var record = evt.payload.record;\r
+ var circ = evt.payload.circ;\r
+ var row = this.circTemplate.cloneNode(true);\r
+\r
+ //if(record.isbn()) {\r
+ // this.byName(row, 'jacket').setAttribute('src', '/opac/extras/ac/jacket/small/' + record.isbn());\r
+ //}\r
+\r
+ this.byName(row, 'barcode').innerHTML = copy.barcode();\r
+ this.byName(row, 'title').innerHTML = record.title();\r
+ //this.byName(row, 'author').innerHTML = record.author();\r
+ //this.byName(row, 'remaining').innerHTML = circ.renewal_remaining();\r
+ openils.Util.show(this.byName(row, type));\r
+\r
+ var date = dojo.date.stamp.fromISOString(circ.due_date());\r
+ this.byName(row, 'due_date').innerHTML = \r
+ dojo.date.locale.format(date, {selector : 'date'});\r
+\r
+ // put new circs at the top of the list\r
+ var tbody = this.circTbody;\r
+ if(itemsOut) tbody = this.itemsOutTbody;\r
+ tbody.insertBefore(row, tbody.getElementsByTagName('tr')[0]);\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.byName = function(node, name) {\r
+ return dojo.query('[name=' + name+']', node)[0];\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.initPrinter = function() {\r
+ try { // Mozilla only\r
+ netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");\r
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');\r
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesRead');\r
+ netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesWrite');\r
+ var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);\r
+ if (pref)\r
+ pref.setBoolPref('print.always_print_silent', true);\r
+ } catch(E) {\r
+ console.log("Unable to initialize auto-printing"); \r
+ }\r
+}\r
+\r
+/**\r
+ * Print a receipt for this session's checkouts\r
+ */\r
+SelfCheckManager.prototype.printSessionReceipt = function(callback) {\r
+ var circIds = [];\r
+ var circCtx = []; // circ context data. in this case, renewal_failure info\r
+\r
+ // collect the circs and failure info\r
+ dojo.forEach(\r
+ this.checkouts, \r
+ function(blob) {\r
+ circIds.push(blob.circ);\r
+ circCtx.push({renewal_failure:blob.renewal_failure});\r
+ }\r
+ );\r
+\r
+ var params = [\r
+ this.authtoken, \r
+ this.staff.ws_ou(),\r
+ null,\r
+ 'format.selfcheck.checkout',\r
+ 'print-on-demand',\r
+ circIds,\r
+ circCtx\r
+ ];\r
+\r
+ var self = this;\r
+ fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.fire_circ_trigger_events'],\r
+ { \r
+ async : true,\r
+ params : params,\r
+ oncomplete : function(r) {\r
+ var resp = openils.Util.readResponse(r);\r
+ var output = resp.template_output();\r
+ if(output) {\r
+ self.printData(output.data(), self.checkouts.length, callback); \r
+ } else {\r
+ var error = resp.error_output();\r
+ if(error) {\r
+ throw new Error("Error creating receipt: " + error.data());\r
+ } else {\r
+ throw new Error("No receipt data returned from server");\r
+ }\r
+ }\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+SelfCheckManager.prototype.printData = function(data, numItems, callback) {\r
+ var win = window.open('', '', 'resizable,width=350,height=250,scrollbars=1'); \r
+ win.document.body.innerHTML = data;\r
+ win.print();\r
+\r
+ /*\r
+ * There is no way to know when the browser is done printing.\r
+ * Make a best guess at when to close the print window by basing\r
+ * the setTimeout wait on the number of items to be printed plus\r
+ * a small buffer\r
+ */\r
+ var sleepTime = 1000;\r
+ if(numItems > 0) \r
+ sleepTime += (numItems / 2) * 1000;\r
+\r
+ setTimeout(\r
+ function() { \r
+ win.close(); // close the print window\r
+ if(callback) callback(); // fire optional post-print callback\r
+ },\r
+ sleepTime \r
+ );\r
+}\r
+\r
+\r
+/**\r
+ * Print a receipt for this user's items out\r
+ */\r
+SelfCheckManager.prototype.printItemsOutReceipt = function(callback) {\r
+ if(!this.itemsOut.length) return;\r
+\r
+ progressDialog.show(true);\r
+\r
+ var params = [\r
+ this.authtoken, \r
+ this.staff.ws_ou(),\r
+ null,\r
+ 'format.selfcheck.items_out',\r
+ 'print-on-demand',\r
+ this.itemsOut\r
+ ];\r
+\r
+ var self = this;\r
+ fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.fire_circ_trigger_events'],\r
+ { \r
+ async : true,\r
+ params : params,\r
+ oncomplete : function(r) {\r
+ progressDialog.hide();\r
+ var resp = openils.Util.readResponse(r);\r
+ var output = resp.template_output();\r
+ if(output) {\r
+ self.printData(output.data(), self.itemsOut.length, callback); \r
+ } else {\r
+ var error = resp.error_output();\r
+ if(error) {\r
+ throw new Error("Error creating receipt: " + error.data());\r
+ } else {\r
+ throw new Error("No receipt data returned from server");\r
+ }\r
+ }\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+/**\r
+ * Print a receipt for this user's items out\r
+ */\r
+SelfCheckManager.prototype.printHoldsReceipt = function(callback) {\r
+ if(!this.holds.length) return;\r
+\r
+ progressDialog.show(true);\r
+\r
+ var holdIds = [];\r
+ var holdData = [];\r
+\r
+ dojo.forEach(this.holds,\r
+ function(data) {\r
+ holdIds.push(data.hold.id());\r
+ if(data.status == 4) {\r
+ holdData.push({ready : true});\r
+ } else {\r
+ holdData.push({\r
+ queue_position : data.queue_position, \r
+ potential_copies : data.potential_copies\r
+ });\r
+ }\r
+ }\r
+ );\r
+\r
+ var params = [\r
+ this.authtoken, \r
+ this.staff.ws_ou(),\r
+ null,\r
+ 'format.selfcheck.holds',\r
+ 'print-on-demand',\r
+ holdIds,\r
+ holdData\r
+ ];\r
+\r
+ var self = this;\r
+ fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.fire_hold_trigger_events'],\r
+ { \r
+ async : true,\r
+ params : params,\r
+ oncomplete : function(r) {\r
+ progressDialog.hide();\r
+ var resp = openils.Util.readResponse(r);\r
+ var output = resp.template_output();\r
+ if(output) {\r
+ self.printData(output.data(), self.holds.length, callback); \r
+ } else {\r
+ var error = resp.error_output();\r
+ if(error) {\r
+ throw new Error("Error creating receipt: " + error.data());\r
+ } else {\r
+ throw new Error("No receipt data returned from server");\r
+ }\r
+ }\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+\r
+SelfCheckManager.prototype.printPaymentReceipt = function(paymentIds, callback) {\r
+ var self = this;\r
+ progressDialog.show(true);\r
+\r
+ fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.money.payment_receipt.print'],\r
+ {\r
+ async : true,\r
+ params : [this.authtoken, paymentIds],\r
+ oncomplete : function(r) {\r
+ var resp = openils.Util.readResponse(r);\r
+ var output = resp.template_output();\r
+ progressDialog.hide();\r
+ if(output) {\r
+ self.printData(output.data(), 1, callback); \r
+ } else {\r
+ var error = resp.error_output();\r
+ if(error) {\r
+ throw new Error("Error creating receipt: " + error.data());\r
+ } else {\r
+ throw new Error("No receipt data returned from server");\r
+ }\r
+ }\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+/**\r
+ * Print a receipt for this user's items out\r
+ */\r
+SelfCheckManager.prototype.printFinesReceipt = function(callback) {\r
+ progressDialog.show(true);\r
+\r
+ var params = [\r
+ this.authtoken, \r
+ this.staff.ws_ou(),\r
+ null,\r
+ 'format.selfcheck.fines',\r
+ 'print-on-demand',\r
+ [this.patron.id()]\r
+ ];\r
+\r
+ var self = this;\r
+ fieldmapper.standardRequest(\r
+ ['open-ils.circ', 'open-ils.circ.fire_user_trigger_events'],\r
+ { \r
+ async : true,\r
+ params : params,\r
+ oncomplete : function(r) {\r
+ progressDialog.hide();\r
+ var resp = openils.Util.readResponse(r);\r
+ var output = resp.template_output();\r
+ if(output) {\r
+ self.printData(output.data(), self.finesCount, callback); \r
+ } else {\r
+ var error = resp.error_output();\r
+ if(error) {\r
+ throw new Error("Error creating receipt: " + error.data());\r
+ } else {\r
+ throw new Error("No receipt data returned from server");\r
+ }\r
+ }\r
+ }\r
+ }\r
+ );\r
+}\r
+\r
+\r
+/**\r
+ * Logout the patron and return to the login page\r
+ */\r
+SelfCheckManager.prototype.logoutPatron = function(print) {\r
+ progressDialog.show(true); // prevent patron from clicking logout link twice\r
+ if(print && this.checkouts.length) {\r
+ this.printSessionReceipt(\r
+ function() {\r
+ location.href = location.href;\r
+ }\r
+ );\r
+ } else {\r
+ location.href = location.href;\r
+ }\r
+}\r
+\r
+\r
+function checkLogin() {\r
+ selfCheckMgr.keepMeLoggedIn();\r
+ if(selfCheckMgr.orgSettings[SET_PATRON_PASSWORD_REQUIRED]) {\r
+ switchTo('step2');\r
+ try{dojo.byId('patron-login-password').focus();}catch(e){}\r
+ } else {\r
+ selfCheckMgr.loginPatron(dojo.byId('patron-login-username').value);\r
+ }\r
+}\r
+\r
+\r
+function cancelLogin() {\r
+ dojo.byId('oils-selfck-status-div').innerHTML = '';\r
+ dojo.byId('oils-selfck-status-div2').innerHTML = '';\r
+ dojo.byId('oils-selfck-status-div3').innerHTML = '';\r
+ dojo.byId('patron-login-password').value = '';\r
+ openils.Util.hide('back_to_login');\r
+ switchTo('step1');\r
+ try {\r
+ dojo.byId('patron-login-username').focus();\r
+ dojo.byId('patron-login-username').select();\r
+ } catch(e) {}\r
+}\r
+\r
+/**\r
+ * Fire up the manager on page load\r
+ */\r
+openils.Util.addOnLoad(\r
+ function() {\r
+ new SelfCheckManager().init();\r
+ openils.Util.registerEnterHandler(dojo.byId('patron-login-username'), function(){checkLogin();});\r
+ openils.Util.registerEnterHandler(dojo.byId('patron-login-password'), function(){selfCheckMgr.loginPatron(dojo.byId('patron-login-username').value,dojo.byId('patron-login-password').value);});\r
+ }\r
+);\r