]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/opac/extras/selfcheck/selfcheck.js
when a no_session event is returned, remove the cookie and reload the page. started...
[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 var orgUnit;
37
38
39 function selfckInit() {
40     var cgi = new CGI();
41     var staff = grabUser(cookieManager.read(STAFF_SES_PARAM) || cgi.param(STAFF_SES_PARAM));
42
43     selfckSetupPrinter();
44
45     orgUnit = findOrgUnitSN(cgi.param('l')) || globalOrgTree;
46
47     var t = fetchOrgSettingDefault(orgUnit.id(), 'circ.selfcheck.patron_login_timeout');
48     patronTimeout = (t) ? parseInt(t) * 1000 : patronTimeout;
49
50     var reg = fetchOrgSettingDefault(orgUnit.id(), 'opac.barcode_regex');
51     if(reg) patronBarcodeRegex = new RegExp(reg);
52
53     if(!staff) {
54         // should not happen when behind the proxy
55         return alert('Staff must login');
56     }
57
58     unHideMe($('selfck-patron-login-container'));
59     $('selfck-patron-login-input').focus();
60
61     $('selfck-patron-login-input').onkeypress = function(evt) {
62         if(userPressedEnter(evt)) 
63             selfckPatronLogin();
64     };
65
66     $('selfck-item-barcode-input').onkeypress = selfckItemBarcodeKeypress;
67
68     // for debugging, allow passing the user barcode via param
69     var urlbc = new CGI().param('patron');
70     if(urlbc)
71         selfckPatronLogin(urlbc);
72
73     selfckStartTimer();
74
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'));
78
79     selfckTryPatronCookie();
80
81 //    selfckMkDummyCirc(); // testing only
82     
83 }
84
85 function selfckSetupPrinter() {
86     try { // Mozilla only
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);
92         if (pref)
93             pref.setBoolPref('print.always_print_silent', true);
94     } catch(E) {
95         
96     }
97 }
98
99 function selfckTryPatronCookie() {
100     var pb = cookieManager.read(PATRON_BARCODE_COOKIE);
101     if(pb) {
102         cookieManager.write(PATRON_BARCODE_COOKIE, '');
103         $('selfck-patron-login-input').value = pb;
104         selfckPatronLogin();
105     }
106 }
107
108
109 function selfckItemBarcodeKeypress(evt) {
110     if(userPressedEnter(evt)) {
111         clearTimeout(scanTimeoutId);
112         selfckCheckout();
113     } else {
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(
120             function() {
121                 if($('selfck-item-barcode-input').value) {
122                     $('selfck-item-barcode-input').select();
123                 }
124             },
125             scanTimeout
126         );
127     }
128 }
129
130 /*
131  * Start the logout timer
132  */
133 function selfckStartTimer() {
134     timerId = setTimeout(
135         function() {
136             selfckLogoutPatron();
137         },
138         patronTimeout
139     );
140
141 }
142
143 /*
144  * Reset the logout timer
145  */
146 function selfckResetTimer() {
147     clearTimeout(timerId);
148     selfckStartTimer();
149 }
150
151 /*
152  * Clears fields and "logs out" the patron by reloading the page
153  */
154 function selfckLogoutPatron() {
155     $('selfck-item-barcode-input').value = ''; // prevent browser caching
156     $('selfck-patron-login-input').value = '';
157     if(patron) {
158         selfckPrint();
159         setTimeout(
160             function() { location.href = location.href; },
161             800
162         );
163     }
164 }
165
166 /*
167  * Fetches the user by barcode and displays the item barcode input
168  */
169
170 function selfckPatronLogin(barcode) {
171     barcode = barcode || $('selfck-patron-login-input').value;
172     if(!barcode) return;
173
174     var bcReq = new Request(
175         'open-ils.actor:open-ils.actor.user.fleshed.retrieve_by_barcode',
176         G.user.session, barcode);
177
178         bcReq.request.alertEvent = false;
179
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();
186                 return;
187             }
188
189             if(patron.textcode == 'NO_SESSION') 
190                 return selfckLogoutStaff();
191
192             return alert(patron.textcode);
193         }
194         $('selfck-patron-login-input').value = ''; // reset the input
195         hideMe($('selfck-patron-login-container'));
196         unHideMe($('selfck-patron-checkout-container'));
197         $('selfck-patron-name-span').appendChild(text(patron.usrname()));
198         $('selfck-item-barcode-input').focus();
199     });
200
201     bcReq.send();
202 }
203
204 function selfckLogoutStaff() {
205     cookieManager.remove(STAFF_SES_PARAM);
206     location.reload(true);
207 }
208
209 /**
210   * If a user barcode was scanned into the item barcode
211   * input, log out the current user and log in the new user
212   */
213 function selfckCheckPatronBarcode(itemBc) {
214     if(patronBarcodeRegex) {
215         if(itemBc.match(patronBarcodeRegex)) {
216             cookieManager.write(PATRON_BARCODE_COOKIE, itemBc, -1);
217             selfckLogoutPatron();
218             return true;
219         }
220     }
221     return false;
222 }
223
224 /**
225   * Sends the checkout request
226   */
227 function selfckCheckout() {
228     if(pendingXact) return;
229     selfckResetTimer();
230     pendingXact = true;
231     isRenewal = false;
232
233     removeChildren($('selfck-event-time'));
234     removeChildren($('selfck-event-span'));
235
236     itemBarcode = $('selfck-item-barcode-input').value;
237     if(!itemBarcode) return;
238
239     if(selfckCheckPatronBarcode(itemBarcode))
240         return;
241
242     if (itemBarcode in successfulItems) {
243         selfckShowMsgNode({textcode:'dupe-barcode'});
244         $('selfck-item-barcode-input').select();
245         pendingXact = false;
246         return;
247     }
248
249     var coReq = new Request(
250         'open-ils.circ:open-ils.circ.checkout.full',
251         G.user.session, {patron_id:patron.id(), copy_barcode:itemBarcode});
252
253         coReq.request.alertEvent = false;
254     coReq.callback(selfckHandleCoResult);
255     coReq.send();
256 }
257
258 /**
259   * Handles the resulting event.  If the item is already checked out,
260   * attempts renewal.  Any other events will display a message
261   */
262 function selfckHandleCoResult(r) {
263     var evt;
264
265     try {
266         evt = r.getResultObject();
267     } catch(E) {
268         pendingXact = false;
269         selfckShowMsgNode({textcode:'UNKNOWN'});
270         appendClear($('selfck-errors'), text(E.toString()));
271         return;
272     }
273
274     if(evt.textcode == 'SUCCESS') {
275         selfckDislplayCheckout(evt);
276         selfckShowMsgNode(evt);
277         successfulItems[itemBarcode] = 1;
278
279     } else if(evt.textcode == 'OPEN_CIRCULATION_EXISTS') {
280         selfckRenew();
281
282     } else if(evt.textcode == 'NO_SESSION') {
283         
284         return selfckLogoutStaff();
285
286     } else {
287         pendingXact = false;
288         selfckShowMsgNode(evt);
289         $('selfck-item-barcode-input').select();
290     }
291 }
292
293 /**
294   * Display event text in the messages block
295   */
296 function selfckShowMsgNode(evt) {
297     var code = evt.textcode;
298     var msgspan = $('selfck-event-span');
299
300     // if we're not explicitly handling the event, just say "copy cannot circ"
301     if(!$('selfck-event-' + code)) 
302         code = 'COPY_CIRC_NOT_ALLOWED';
303
304     appendClear($('selfck-event-time'), text(new Date().toLocaleString()));
305     appendClear($('selfck-event-span'), text($('selfck-event-' + code).innerHTML));
306 }
307
308 /**
309   * Renders a row in the checkouts table for the current circulation
310   */
311 function selfckDislplayCheckout(evt) {
312     unHideMe($('selfck-items-out-table-wrapper'));
313
314     var template = itemsOutTemplate.cloneNode(true);
315     var copy = evt.payload.copy;
316     var record = evt.payload.record;
317     var circ = evt.payload.circ;
318
319     if(record.isbn()) {
320             var pic = $n(template, 'selfck.jacket');
321             pic.setAttribute('src', '../ac/jacket/small/'+cleanISBN(record.isbn()));
322     }
323     $n(template, 'selfck.barcode').appendChild(text(copy.barcode()));
324     $n(template, 'selfck.title').appendChild(text(record.title()));
325     $n(template, 'selfck.author').appendChild(text(record.author()));
326     $n(template, 'selfck.due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
327     $n(template, 'selfck.remaining').appendChild(text(circ.renewal_remaining()));
328     if(isRenewal) {
329         hideMe($n(template, 'selfck.cotype_co'));
330         unHideMe($n(template, 'selfck.cotype_rn'));
331     }
332
333     $('selfck-items-out-tbody').appendChild(template);
334     $('selfck-item-barcode-input').value = '';
335
336
337     // flesh out the printable version of the page as well
338     var ptemplate = printTemplate.cloneNode(true);
339     $n(ptemplate, 'title').appendChild(text(record.title()));
340     $n(ptemplate, 'barcode').appendChild(text(copy.barcode()));
341     $n(ptemplate, 'due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
342     printWrapper.appendChild(ptemplate);
343
344     pendingXact = false;
345 }
346
347 /**
348   * Checks to see if this item is checked out to the current patron.  If so, 
349   * this sends the renewal request.
350   */
351 function selfckRenew() {
352
353     // first, make sure the item is checked out to this patron
354     var detailReq = new Request(
355         'open-ils.circ:open-ils.circ.copy_details.retrieve.barcode',
356         G.user.session, itemBarcode);
357
358     detailReq.callback(
359         function(r) {
360             var details = r.getResultObject();
361             if(details.circ.usr() == patron.id()) {
362                 // OK, this is our item, renew it
363                 isRenewal = true;
364                 var rnReq = new Request(
365                     'open-ils.circ:open-ils.circ.renew',
366                     G.user.session, {copy_barcode:itemBarcode});
367                 rnReq.request.alertEvent = false;
368                 rnReq.callback(selfckHandleCoResult);
369                 rnReq.send();
370             }
371         }
372     );
373
374     detailReq.send();
375 }
376
377 /**
378   * Sets the print date and prints the page
379   */
380 function selfckPrint() {
381     for(var x in successfulItems) { // make sure we've checked out at least one item
382         appendClear($('selfck-print-lib-name'), text(orgUnit.name()));
383         appendClear($('selfck-print-date'), text(new Date().toLocaleString()));
384         window.print();
385         return;
386     }
387 }
388
389
390 /**
391   * Test method for generating dummy data in the checkout tables
392   */
393 function selfckMkDummyCirc() {
394     unHideMe($('selfck-items-out-table'));
395
396     var template = itemsOutTemplate.cloneNode(true);
397     $n(template, 'selfck.barcode').appendChild(text('123456789'));
398     $n(template, 'selfck.title').appendChild(text('Test Title'));
399     $n(template, 'selfck.author').appendChild(text('Test Author'));
400     $n(template, 'selfck.due_date').appendChild(text('2008-08-01'));
401     $n(template, 'selfck.remaining').appendChild(text('1'));
402     $('selfck-items-out-tbody').appendChild(template);
403
404     // flesh out the printable version of the page as well
405     var ptemplate = printTemplate.cloneNode(true);
406     $n(ptemplate, 'title').appendChild(text('Test Title'));
407     $n(ptemplate, 'barcode').appendChild(text('123456789'));
408     $n(ptemplate, 'due_date').appendChild(text('2008-08-01'));
409     printWrapper.appendChild(ptemplate);
410 }