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;
38 function selfckInit() {
40 var staff = grabUser(cookieManager.read(STAFF_SES_PARAM) || cgi.param(STAFF_SES_PARAM));
43 XXX we need org information (from the proxy?)
44 var t = fetchOrgSettingDefault(1, 'circ.selfcheck.patron_login_timeout');
45 patronTimeout = (t) ? parseInt(t) * 1000 : patronTimeout;
48 var reg = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex');
49 if(reg) patronBarcodeRegex = new RegExp(reg);
52 // should not happen when behind the proxy
53 return alert('Staff must login');
56 unHideMe($('selfck-patron-login-container'));
57 $('selfck-patron-login-input').focus();
59 $('selfck-patron-login-input').onkeypress = function(evt) {
60 if(userPressedEnter(evt))
64 $('selfck-item-barcode-input').onkeypress = selfckItemBarcodeKeypress;
66 // for debugging, allow passing the user barcode via param
67 var urlbc = new CGI().param('patron');
69 selfckPatronLogin(urlbc);
73 printWrapper = $('selfck-print-items-list');
74 printTemplate = printWrapper.removeChild($n(printWrapper, 'selfck-print-items-template'));
75 itemsOutTemplate = $('selfck-items-out-tbody').removeChild($('selfck-items-out-row'));
77 selfckTryPatronCookie();
79 // selfckMkDummyCirc(); // testing only
82 function selfckTryPatronCookie() {
83 var pb = cookieManager.read(PATRON_BARCODE_COOKIE);
85 cookieManager.write(PATRON_BARCODE_COOKIE, '');
86 $('selfck-patron-login-input').value = pb;
92 function selfckItemBarcodeKeypress(evt) {
93 if(userPressedEnter(evt)) {
94 clearTimeout(scanTimeoutId);
97 /* If scanTimeout milliseconds have passed and there is
98 still data in the input box, it's a likely indication
99 of a partial scan. Select the text so the next scan
100 will replace the value */
101 clearTimeout(scanTimeoutId);
102 scanTimeoutId = setTimeout(
104 if($('selfck-item-barcode-input').value) {
105 $('selfck-item-barcode-input').select();
114 * Start the logout timer
116 function selfckStartTimer() {
117 timerId = setTimeout(
119 selfckLogoutPatron();
127 * Reset the logout timer
129 function selfckResetTimer() {
130 clearTimeout(timerId);
135 * Clears fields and "logs out" the patron by reloading the page
137 function selfckLogoutPatron() {
138 $('selfck-item-barcode-input').value = ''; // prevent browser caching
139 $('selfck-patron-login-input').value = '';
143 function() { location.href = location.href; },
150 * Fetches the user by barcode and displays the item barcode input
153 function selfckPatronLogin(barcode) {
154 barcode = barcode || $('selfck-patron-login-input').value;
157 var bcReq = new Request(
158 'open-ils.actor:open-ils.actor.user.fleshed.retrieve_by_barcode',
159 G.user.session, barcode);
161 bcReq.request.alertEvent = false;
163 bcReq.callback(function(r) {
164 patron = r.getResultObject();
165 if(checkILSEvent(patron)) {
166 if(patron.textcode == 'ACTOR_USER_NOT_FOUND') {
167 unHideMe($('selfck-patron-not-found'));
168 $('selfck-patron-login-input').select();
171 return alert(patron.textcode);
173 $('selfck-patron-login-input').value = ''; // reset the input
174 hideMe($('selfck-patron-login-container'));
175 unHideMe($('selfck-patron-checkout-container'));
176 $('selfck-patron-name-span').appendChild(text(patron.usrname()));
177 $('selfck-item-barcode-input').focus();
184 * If a user barcode was scanned into the item barcode
185 * input, log out the current user and log in the new user
187 function selfckCheckPatronBarcode(itemBc) {
188 if(patronBarcodeRegex) {
189 if(itemBc.match(patronBarcodeRegex)) {
190 cookieManager.write(PATRON_BARCODE_COOKIE, itemBc, -1);
191 selfckLogoutPatron();
199 * Sends the checkout request
201 function selfckCheckout() {
202 if(pendingXact) return;
207 removeChildren($('selfck-event-time'));
208 removeChildren($('selfck-event-span'));
210 itemBarcode = $('selfck-item-barcode-input').value;
211 if(!itemBarcode) return;
213 if(selfckCheckPatronBarcode(itemBarcode))
216 if (itemBarcode in successfulItems) {
217 selfckShowMsgNode({textcode:'dupe-barcode'});
218 $('selfck-item-barcode-input').select();
223 var coReq = new Request(
224 'open-ils.circ:open-ils.circ.checkout.full',
225 G.user.session, {patron_id:patron.id(), copy_barcode:itemBarcode});
227 coReq.request.alertEvent = false;
228 coReq.callback(selfckHandleCoResult);
233 * Handles the resulting event. If the item is already checked out,
234 * attempts renewal. Any other events will display a message
236 function selfckHandleCoResult(r) {
237 var evt = r.getResultObject();
239 if(evt.textcode == 'SUCCESS') {
240 selfckDislplayCheckout(evt);
241 selfckShowMsgNode(evt);
242 successfulItems[itemBarcode] = 1;
244 } else if(evt.textcode == 'OPEN_CIRCULATION_EXISTS') {
249 selfckShowMsgNode(evt);
250 $('selfck-item-barcode-input').select();
255 * Display event text in the messages block
257 function selfckShowMsgNode(evt) {
258 var code = evt.textcode;
259 var msgspan = $('selfck-event-span');
261 // if we're not explicitly handling the event, just say "copy cannot circ"
262 if(!$('selfck-event-' + code))
263 code = 'COPY_CIRC_NOT_ALLOWED';
265 appendClear($('selfck-event-time'), text(new Date().toLocaleString()));
266 appendClear($('selfck-event-span'), text($('selfck-event-' + code).innerHTML));
270 * Renders a row in the checkouts table for the current circulation
272 function selfckDislplayCheckout(evt) {
273 unHideMe($('selfck-items-out-table-wrapper'));
275 var template = itemsOutTemplate.cloneNode(true);
276 var copy = evt.payload.copy;
277 var record = evt.payload.record;
278 var circ = evt.payload.circ;
281 var pic = $n(template, 'selfck.jacket');
282 pic.setAttribute('src', '../ac/jacket/small/'+cleanISBN(record.isbn()));
284 $n(template, 'selfck.barcode').appendChild(text(copy.barcode()));
285 $n(template, 'selfck.title').appendChild(text(record.title()));
286 $n(template, 'selfck.author').appendChild(text(record.author()));
287 $n(template, 'selfck.due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
288 $n(template, 'selfck.remaining').appendChild(text(circ.renewal_remaining()));
290 hideMe($n(template, 'selfck.cotype_co'));
291 unHideMe($n(template, 'selfck.cotype_rn'));
294 $('selfck-items-out-tbody').appendChild(template);
295 $('selfck-item-barcode-input').value = '';
298 // flesh out the printable version of the page as well
299 var ptemplate = printTemplate.cloneNode(true);
300 $n(ptemplate, 'title').appendChild(text(record.title()));
301 $n(ptemplate, 'barcode').appendChild(text(copy.barcode()));
302 $n(ptemplate, 'due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
303 printWrapper.appendChild(ptemplate);
309 * Checks to see if this item is checked out to the current patron. If so,
310 * this sends the renewal request.
312 function selfckRenew() {
314 // first, make sure the item is checked out to this patron
315 var detailReq = new Request(
316 'open-ils.circ:open-ils.circ.copy_details.retrieve.barcode',
317 G.user.session, itemBarcode);
321 var details = r.getResultObject();
322 if(details.circ.usr() == patron.id()) {
323 // OK, this is our item, renew it
325 var rnReq = new Request(
326 'open-ils.circ:open-ils.circ.renew',
327 G.user.session, {copy_barcode:itemBarcode});
328 rnReq.request.alertEvent = false;
329 rnReq.callback(selfckHandleCoResult);
339 * Sets the print date and prints the page
341 function selfckPrint() {
342 for(var x in successfulItems) { // make sure we've checked out at least one item
343 appendClear($('selfck-print-date'), text(new Date().toLocaleString()));
351 * Test method for generating dummy data in the checkout tables
353 function selfckMkDummyCirc() {
354 unHideMe($('selfck-items-out-table'));
356 var template = itemsOutTemplate.cloneNode(true);
357 $n(template, 'selfck.barcode').appendChild(text('123456789'));
358 $n(template, 'selfck.title').appendChild(text('Test Title'));
359 $n(template, 'selfck.author').appendChild(text('Test Author'));
360 $n(template, 'selfck.due_date').appendChild(text('2008-08-01'));
361 $n(template, 'selfck.remaining').appendChild(text('1'));
362 $('selfck-items-out-tbody').appendChild(template);
364 // flesh out the printable version of the page as well
365 var ptemplate = printTemplate.cloneNode(true);
366 $n(ptemplate, 'title').appendChild(text('Test Title'));
367 $n(ptemplate, 'barcode').appendChild(text('123456789'));
368 $n(ptemplate, 'due_date').appendChild(text('2008-08-01'));
369 printWrapper.appendChild(ptemplate);