1 /* -----------------------------------------------------------------
2 * Copyright (C) 2008 Equinox Software, Inc.
3 * Bill Erickson <erickson@esilibrary.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 ----------------------------------------------------------------- */
21 var STAFF_SES_PARAM = 'ses';
22 var PATRON_BARCODE_COOKIE = 'pbcc';
24 var itemBarcode = null;
25 var itemsOutTemplate = null;
26 var isRenewal = false;
27 var pendingXact = false;
28 var patronTimeout = 600000; /* 10 minutes */
32 var successfulItems = {};
33 var scanTimeout = 800;
35 var patronBarcodeRegex;
39 function selfckInit() {
41 var staff = grabUser(cookieManager.read(STAFF_SES_PARAM) || cgi.param(STAFF_SES_PARAM));
45 orgUnit = findOrgUnitSN(cgi.param('l')) || globalOrgTree;
47 var t = fetchOrgSettingDefault(orgUnit.id(), 'circ.selfcheck.patron_login_timeout');
48 patronTimeout = (t) ? parseInt(t) * 1000 : patronTimeout;
50 var reg = fetchOrgSettingDefault(orgUnit.id(), 'opac.barcode_regex');
51 if(reg) patronBarcodeRegex = new RegExp(reg);
54 // should not happen when behind the proxy
55 return alert('Staff must login');
58 unHideMe($('selfck-patron-login-container'));
59 $('selfck-patron-login-input').focus();
61 $('selfck-patron-login-input').onkeypress = function(evt) {
62 if(userPressedEnter(evt))
66 $('selfck-item-barcode-input').onkeypress = selfckItemBarcodeKeypress;
68 // for debugging, allow passing the user barcode via param
69 var urlbc = new CGI().param('patron');
71 selfckPatronLogin(urlbc);
75 printWrapper = $('selfck-print-items-list');
76 printTemplate = printWrapper.removeChild($n(printWrapper, 'selfck-print-items-template'));
77 itemsOutTemplate = $('selfck-items-out-tbody').removeChild($('selfck-items-out-row'));
79 selfckTryPatronCookie();
81 // selfckMkDummyCirc(); // testing only
85 function selfckSetupPrinter() {
87 netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
88 netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
89 netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesRead');
90 netscape.security.PrivilegeManager.enablePrivilege('UniversalPreferencesWrite');
91 var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
93 pref.setBoolPref('print.always_print_silent', true);
99 function selfckTryPatronCookie() {
100 var pb = cookieManager.read(PATRON_BARCODE_COOKIE);
102 cookieManager.write(PATRON_BARCODE_COOKIE, '');
103 $('selfck-patron-login-input').value = pb;
109 function selfckItemBarcodeKeypress(evt) {
110 if(userPressedEnter(evt)) {
111 clearTimeout(scanTimeoutId);
114 /* If scanTimeout milliseconds have passed and there is
115 still data in the input box, it's a likely indication
116 of a partial scan. Select the text so the next scan
117 will replace the value */
118 clearTimeout(scanTimeoutId);
119 scanTimeoutId = setTimeout(
121 if($('selfck-item-barcode-input').value) {
122 $('selfck-item-barcode-input').select();
131 * Start the logout timer
133 function selfckStartTimer() {
134 timerId = setTimeout(
136 selfckLogoutPatron();
144 * Reset the logout timer
146 function selfckResetTimer() {
147 clearTimeout(timerId);
152 * Clears fields and "logs out" the patron by reloading the page
154 function selfckLogoutPatron() {
155 $('selfck-item-barcode-input').value = ''; // prevent browser caching
156 $('selfck-patron-login-input').value = '';
160 function() { location.href = location.href; },
167 * Fetches the user by barcode and displays the item barcode input
170 function selfckPatronLogin(barcode) {
171 barcode = barcode || $('selfck-patron-login-input').value;
174 var bcReq = new Request(
175 'open-ils.actor:open-ils.actor.user.fleshed.retrieve_by_barcode',
176 G.user.session, barcode);
178 bcReq.request.alertEvent = false;
180 bcReq.callback(function(r) {
181 patron = r.getResultObject();
182 if(checkILSEvent(patron)) {
183 if(patron.textcode == 'ACTOR_USER_NOT_FOUND') {
184 unHideMe($('selfck-patron-not-found'));
185 $('selfck-patron-login-input').select();
188 return alert(patron.textcode);
190 $('selfck-patron-login-input').value = ''; // reset the input
191 hideMe($('selfck-patron-login-container'));
192 unHideMe($('selfck-patron-checkout-container'));
193 $('selfck-patron-name-span').appendChild(text(patron.usrname()));
194 $('selfck-item-barcode-input').focus();
201 * If a user barcode was scanned into the item barcode
202 * input, log out the current user and log in the new user
204 function selfckCheckPatronBarcode(itemBc) {
205 if(patronBarcodeRegex) {
206 if(itemBc.match(patronBarcodeRegex)) {
207 cookieManager.write(PATRON_BARCODE_COOKIE, itemBc, -1);
208 selfckLogoutPatron();
216 * Sends the checkout request
218 function selfckCheckout() {
219 if(pendingXact) return;
224 removeChildren($('selfck-event-time'));
225 removeChildren($('selfck-event-span'));
227 itemBarcode = $('selfck-item-barcode-input').value;
228 if(!itemBarcode) return;
230 if(selfckCheckPatronBarcode(itemBarcode))
233 if (itemBarcode in successfulItems) {
234 selfckShowMsgNode({textcode:'dupe-barcode'});
235 $('selfck-item-barcode-input').select();
240 var coReq = new Request(
241 'open-ils.circ:open-ils.circ.checkout.full',
242 G.user.session, {patron_id:patron.id(), copy_barcode:itemBarcode});
244 coReq.request.alertEvent = false;
245 coReq.callback(selfckHandleCoResult);
250 * Handles the resulting event. If the item is already checked out,
251 * attempts renewal. Any other events will display a message
253 function selfckHandleCoResult(r) {
257 evt = r.getResultObject();
260 selfckShowMsgNode({textcode:'UNKNOWN'});
261 appendClear($('selfck-errors'), text(E.toString()));
265 if(evt.textcode == 'SUCCESS') {
266 selfckDislplayCheckout(evt);
267 selfckShowMsgNode(evt);
268 successfulItems[itemBarcode] = 1;
270 } else if(evt.textcode == 'OPEN_CIRCULATION_EXISTS') {
275 selfckShowMsgNode(evt);
276 $('selfck-item-barcode-input').select();
281 * Display event text in the messages block
283 function selfckShowMsgNode(evt) {
284 var code = evt.textcode;
285 var msgspan = $('selfck-event-span');
287 // if we're not explicitly handling the event, just say "copy cannot circ"
288 if(!$('selfck-event-' + code))
289 code = 'COPY_CIRC_NOT_ALLOWED';
291 appendClear($('selfck-event-time'), text(new Date().toLocaleString()));
292 appendClear($('selfck-event-span'), text($('selfck-event-' + code).innerHTML));
296 * Renders a row in the checkouts table for the current circulation
298 function selfckDislplayCheckout(evt) {
299 unHideMe($('selfck-items-out-table-wrapper'));
301 var template = itemsOutTemplate.cloneNode(true);
302 var copy = evt.payload.copy;
303 var record = evt.payload.record;
304 var circ = evt.payload.circ;
307 var pic = $n(template, 'selfck.jacket');
308 pic.setAttribute('src', '../ac/jacket/small/'+cleanISBN(record.isbn()));
310 $n(template, 'selfck.barcode').appendChild(text(copy.barcode()));
311 $n(template, 'selfck.title').appendChild(text(record.title()));
312 $n(template, 'selfck.author').appendChild(text(record.author()));
313 $n(template, 'selfck.due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
314 $n(template, 'selfck.remaining').appendChild(text(circ.renewal_remaining()));
316 hideMe($n(template, 'selfck.cotype_co'));
317 unHideMe($n(template, 'selfck.cotype_rn'));
320 $('selfck-items-out-tbody').appendChild(template);
321 $('selfck-item-barcode-input').value = '';
324 // flesh out the printable version of the page as well
325 var ptemplate = printTemplate.cloneNode(true);
326 $n(ptemplate, 'title').appendChild(text(record.title()));
327 $n(ptemplate, 'barcode').appendChild(text(copy.barcode()));
328 $n(ptemplate, 'due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
329 printWrapper.appendChild(ptemplate);
335 * Checks to see if this item is checked out to the current patron. If so,
336 * this sends the renewal request.
338 function selfckRenew() {
340 // first, make sure the item is checked out to this patron
341 var detailReq = new Request(
342 'open-ils.circ:open-ils.circ.copy_details.retrieve.barcode',
343 G.user.session, itemBarcode);
347 var details = r.getResultObject();
348 if(details.circ.usr() == patron.id()) {
349 // OK, this is our item, renew it
351 var rnReq = new Request(
352 'open-ils.circ:open-ils.circ.renew',
353 G.user.session, {copy_barcode:itemBarcode});
354 rnReq.request.alertEvent = false;
355 rnReq.callback(selfckHandleCoResult);
365 * Sets the print date and prints the page
367 function selfckPrint() {
368 for(var x in successfulItems) { // make sure we've checked out at least one item
369 appendClear($('selfck-print-date'), text(new Date().toLocaleString()));
377 * Test method for generating dummy data in the checkout tables
379 function selfckMkDummyCirc() {
380 unHideMe($('selfck-items-out-table'));
382 var template = itemsOutTemplate.cloneNode(true);
383 $n(template, 'selfck.barcode').appendChild(text('123456789'));
384 $n(template, 'selfck.title').appendChild(text('Test Title'));
385 $n(template, 'selfck.author').appendChild(text('Test Author'));
386 $n(template, 'selfck.due_date').appendChild(text('2008-08-01'));
387 $n(template, 'selfck.remaining').appendChild(text('1'));
388 $('selfck-items-out-tbody').appendChild(template);
390 // flesh out the printable version of the page as well
391 var ptemplate = printTemplate.cloneNode(true);
392 $n(ptemplate, 'title').appendChild(text('Test Title'));
393 $n(ptemplate, 'barcode').appendChild(text('123456789'));
394 $n(ptemplate, 'due_date').appendChild(text('2008-08-01'));
395 printWrapper.appendChild(ptemplate);