]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/opac/extras/selfcheck/selfcheck.js
if a patron barcode regex is configured and a patron barcode is scanned into the...
[Evergreen.git] / Open-ILS / web / opac / extras / selfcheck / selfcheck.js
1 /* -----------------------------------------------------------------
2 * Copyright (C) 2008  Equinox Software, Inc.
3 * Bill Erickson <erickson@esilibrary.com>
4
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.
9
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.
14
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  
18 * 02110-1301, USA
19 ----------------------------------------------------------------- */
20
21 var STAFF_SES_PARAM = 'ses';
22 var PATRON_BARCODE_COOKIE = 'pbcc';
23 var patron = null
24 var itemBarcode = null;
25 var itemsOutTemplate = null;
26 var isRenewal = false;
27 var pendingXact = false;
28 var patronTimeout = 600000; /* 10 minutes */
29 var timerId = null;
30 var printWrapper;
31 var printTemplate;
32 var successfulItems = {};
33 var scanTimeout = 800;
34 var scanTimeoutId;
35 var patronBarcodeRegex;
36
37
38 function selfckInit() {
39     var cgi = new CGI();
40     var staff = grabUser(cookieManager.read(STAFF_SES_PARAM) || cgi.param(STAFF_SES_PARAM));
41
42     /*
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;
46     */
47
48     var reg = fetchOrgSettingDefault(globalOrgTree.id(), 'opac.barcode_regex');
49     if(reg) patronBarcodeRegex = new RegExp(reg);
50
51     if(!staff) {
52         // should not happen when behind the proxy
53         return alert('Staff must login');
54     }
55
56     unHideMe($('selfck-patron-login-container'));
57     $('selfck-patron-login-input').focus();
58
59     $('selfck-patron-login-input').onkeypress = function(evt) {
60         if(userPressedEnter(evt)) 
61             selfckPatronLogin();
62     };
63
64     $('selfck-item-barcode-input').onkeypress = selfckItemBarcodeKeypress;
65
66     // for debugging, allow passing the user barcode via param
67     var urlbc = new CGI().param('patron');
68     if(urlbc)
69         selfckPatronLogin(urlbc);
70
71     selfckStartTimer();
72
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'));
76
77     selfckTryPatronCookie();
78
79 //    selfckMkDummyCirc(); // testing only
80 }
81
82 function selfckTryPatronCookie() {
83     var pb = cookieManager.read(PATRON_BARCODE_COOKIE);
84     if(pb) {
85         cookieManager.write(PATRON_BARCODE_COOKIE, '');
86         $('selfck-patron-login-input').value = pb;
87         selfckPatronLogin();
88     }
89 }
90
91
92 function selfckItemBarcodeKeypress(evt) {
93     if(userPressedEnter(evt)) {
94         clearTimeout(scanTimeoutId);
95         selfckCheckout();
96     } else {
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(
103             function() {
104                 if($('selfck-item-barcode-input').value) {
105                     $('selfck-item-barcode-input').select();
106                 }
107             },
108             scanTimeout
109         );
110     }
111 }
112
113 /*
114  * Start the logout timer
115  */
116 function selfckStartTimer() {
117     timerId = setTimeout(
118         function() {
119             selfckLogoutPatron();
120         },
121         patronTimeout
122     );
123
124 }
125
126 /*
127  * Reset the logout timer
128  */
129 function selfckResetTimer() {
130     clearTimeout(timerId);
131     selfckStartTimer();
132 }
133
134 /*
135  * Clears fields and "logs out" the patron by reloading the page
136  */
137 function selfckLogoutPatron() {
138     $('selfck-item-barcode-input').value = ''; // prevent browser caching
139     $('selfck-patron-login-input').value = '';
140     if(patron) {
141         selfckPrint();
142         setTimeout(
143             function() { location.href = location.href; },
144             800
145         );
146     }
147 }
148
149 /*
150  * Fetches the user by barcode and displays the item barcode input
151  */
152
153 function selfckPatronLogin(barcode) {
154     barcode = barcode || $('selfck-patron-login-input').value;
155     if(!barcode) return;
156
157     var bcReq = new Request(
158         'open-ils.actor:open-ils.actor.user.fleshed.retrieve_by_barcode',
159         G.user.session, barcode);
160
161         bcReq.request.alertEvent = false;
162
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();
169                 return;
170             }
171             return alert(patron.textcode);
172         }
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();
178     });
179
180     bcReq.send();
181 }
182
183 /**
184   * If a user barcode was scanned into the item barcode
185   * input, log out the current user and log in the new user
186   */
187 function selfckCheckPatronBarcode(itemBc) {
188     if(patronBarcodeRegex) {
189         if(itemBc.match(patronBarcodeRegex)) {
190             cookieManager.write(PATRON_BARCODE_COOKIE, itemBc, -1);
191             selfckLogoutPatron();
192             return true;
193         }
194     }
195     return false;
196 }
197
198 /**
199   * Sends the checkout request
200   */
201 function selfckCheckout() {
202     if(pendingXact) return;
203     selfckResetTimer();
204     pendingXact = true;
205     isRenewal = false;
206
207     removeChildren($('selfck-event-time'));
208     removeChildren($('selfck-event-span'));
209
210     itemBarcode = $('selfck-item-barcode-input').value;
211     if(!itemBarcode) return;
212
213     if(selfckCheckPatronBarcode(itemBarcode))
214         return;
215
216     if (itemBarcode in successfulItems) {
217         selfckShowMsgNode({textcode:'dupe-barcode'});
218         $('selfck-item-barcode-input').select();
219         pendingXact = false;
220         return;
221     }
222
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});
226
227         coReq.request.alertEvent = false;
228     coReq.callback(selfckHandleCoResult);
229     coReq.send();
230 }
231
232 /**
233   * Handles the resulting event.  If the item is already checked out,
234   * attempts renewal.  Any other events will display a message
235   */
236 function selfckHandleCoResult(r) {
237     var evt = r.getResultObject();
238
239     if(evt.textcode == 'SUCCESS') {
240         selfckDislplayCheckout(evt);
241         selfckShowMsgNode(evt);
242         successfulItems[itemBarcode] = 1;
243
244     } else if(evt.textcode == 'OPEN_CIRCULATION_EXISTS') {
245         selfckRenew();
246
247     } else {
248         pendingXact = false;
249         selfckShowMsgNode(evt);
250         $('selfck-item-barcode-input').select();
251     }
252 }
253
254 /**
255   * Display event text in the messages block
256   */
257 function selfckShowMsgNode(evt) {
258     var code = evt.textcode;
259     var msgspan = $('selfck-event-span');
260
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';
264
265     appendClear($('selfck-event-time'), text(new Date().toLocaleString()));
266     appendClear($('selfck-event-span'), text($('selfck-event-' + code).innerHTML));
267 }
268
269 /**
270   * Renders a row in the checkouts table for the current circulation
271   */
272 function selfckDislplayCheckout(evt) {
273     unHideMe($('selfck-items-out-table-wrapper'));
274
275     var template = itemsOutTemplate.cloneNode(true);
276     var copy = evt.payload.copy;
277     var record = evt.payload.record;
278     var circ = evt.payload.circ;
279
280     if(record.isbn()) {
281             var pic = $n(template, 'selfck.jacket');
282             pic.setAttribute('src', '../ac/jacket/small/'+cleanISBN(record.isbn()));
283     }
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()));
289     if(isRenewal) {
290         hideMe($n(template, 'selfck.cotype_co'));
291         unHideMe($n(template, 'selfck.cotype_rn'));
292     }
293
294     $('selfck-items-out-tbody').appendChild(template);
295     $('selfck-item-barcode-input').value = '';
296
297
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);
304
305     pendingXact = false;
306 }
307
308 /**
309   * Checks to see if this item is checked out to the current patron.  If so, 
310   * this sends the renewal request.
311   */
312 function selfckRenew() {
313
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);
318
319     detailReq.callback(
320         function(r) {
321             var details = r.getResultObject();
322             if(details.circ.usr() == patron.id()) {
323                 // OK, this is our item, renew it
324                 isRenewal = true;
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);
330                 rnReq.send();
331             }
332         }
333     );
334
335     detailReq.send();
336 }
337
338 /**
339   * Sets the print date and prints the page
340   */
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()));
344         window.print();
345         return;
346     }
347 }
348
349
350 /**
351   * Test method for generating dummy data in the checkout tables
352   */
353 function selfckMkDummyCirc() {
354     unHideMe($('selfck-items-out-table'));
355
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);
363
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);
370 }