Basic web-based selfcheck interface. This interface implements a subset of
[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 = null
23 var itemBarcode = null;
24 var itemsOutTemplate = null;
25 var isRenewal = false;
26 var pendingXact = false;
27 var patronTimeout = 120000;
28 var timerId = null;
29 var printWrapper;
30 var printTemplate;
31 var successfulItems = {};
32
33
34 function selfckInit() {
35     var cgi = new CGI();
36     var staff = grabUser(cookieManager.read(STAFF_SES_PARAM) || cgi.param(STAFF_SES_PARAM));
37
38     /*
39     XXX we need org information (from the proxy?)
40     var t = fetchOrgSettingDefault(1, 'circ.selfcheck.patron_login_timeout');
41     patronTimeout = (t) ? parseInt(t) * 1000 : patronTimeout;
42     */
43
44     if(!staff) {
45         // should not happen when behind the proxy
46         return alert('Staff must login');
47     }
48
49     unHideMe($('selfck-patron-login-container'));
50     $('selfck-patron-login-input').focus();
51
52     $('selfck-patron-login-input').onkeypress = function(evt) {
53         if(userPressedEnter(evt)) 
54             selfckPatronLogin();
55     };
56
57     $('selfck-item-barcode-input').onkeypress = function(evt) {
58         if(userPressedEnter(evt)) 
59             selfckCheckout();
60     };
61
62     // for debugging, allow passing the user barcode via param
63     var urlbc = new CGI().param('patron');
64     if(urlbc)
65         selfckPatronLogin(urlbc);
66
67     selfckStartTimer();
68
69     printWrapper = $('selfck-print-items-list');
70     printTemplate = printWrapper.removeChild($n(printWrapper, 'selfck-print-items-template'));
71     itemsOutTemplate = $('selfck-items-out-tbody').removeChild($('selfck-items-out-row'));
72
73 //    selfckMkDummyCirc(); // testing only
74 }
75
76 /*
77  * Start the logout timer
78  */
79 function selfckStartTimer() {
80     timerId = setTimeout(
81         function() {
82             selfckLogoutPatron();
83         },
84         patronTimeout
85     );
86
87 }
88
89 /*
90  * Reset the logout timer
91  */
92 function selfckResetTimer() {
93     clearTimeout(timerId);
94     selfckStartTimer();
95 }
96
97 /*
98  * Clears fields and "logs out" the patron by reloading the page
99  */
100 function selfckLogoutPatron() {
101     $('selfck-item-barcode-input').value = ''; // prevent browser caching
102     $('selfck-patron-login-input').value = '';
103     if(patron) // page reload resets everything
104         location.href = location.href;
105 }
106
107 /*
108  * Fetches the user by barcode and displays the item barcode input
109  */
110
111 function selfckPatronLogin(barcode) {
112     barcode = barcode || $('selfck-patron-login-input').value;
113     if(!barcode) return;
114
115     var bcReq = new Request(
116         'open-ils.actor:open-ils.actor.user.fleshed.retrieve_by_barcode',
117         G.user.session, barcode);
118
119         bcReq.request.alertEvent = false;
120
121     bcReq.callback(function(r) {
122         patron = r.getResultObject();
123         if(checkILSEvent(patron)) {
124             if(patron.textcode == 'ACTOR_USER_NOT_FOUND') {
125                 unHideMe($('selfck-patron-not-found'));
126                 $('selfck-patron-login-input').select();
127                 return;
128             }
129             return alert(patron.textcode);
130         }
131         $('selfck-patron-login-input').value = ''; // reset the input
132         hideMe($('selfck-patron-login-container'));
133         unHideMe($('selfck-patron-checkout-container'));
134         $('selfck-patron-name-span').appendChild(text(patron.usrname()));
135         $('selfck-item-barcode-input').focus();
136     });
137
138     bcReq.send();
139 }
140
141 /**
142   * Sends the checkout request
143   */
144 function selfckCheckout() {
145     if(pendingXact) return;
146     selfckResetTimer();
147     pendingXact = true;
148     isRenewal = false;
149
150     removeChildren($('selfck-event-time'));
151     removeChildren($('selfck-event-span'));
152
153     itemBarcode = $('selfck-item-barcode-input').value;
154     if(!itemBarcode) return;
155
156     if (itemBarcode in successfulItems) {
157         selfckShowMsgNode({textcode:'dupe-barcode'});
158         $('selfck-item-barcode-input').select();
159         pendingXact = false;
160         return;
161     }
162
163     var coReq = new Request(
164         'open-ils.circ:open-ils.circ.checkout.full',
165         G.user.session, {patron_id:patron.id(), copy_barcode:itemBarcode});
166
167         coReq.request.alertEvent = false;
168     coReq.callback(selfckHandleCoResult);
169     coReq.send();
170 }
171
172 /**
173   * Handles the resulting event.  If the item is already checked out,
174   * attempts renewal.  Any other events will display a message
175   */
176 function selfckHandleCoResult(r) {
177     var evt = r.getResultObject();
178
179     if(evt.textcode == 'SUCCESS') {
180         selfckDislplayCheckout(evt);
181         selfckShowMsgNode(evt);
182         successfulItems[itemBarcode] = 1;
183
184     } else if(evt.textcode == 'OPEN_CIRCULATION_EXISTS') {
185         selfckRenew();
186
187     } else {
188         pendingXact = false;
189         selfckShowMsgNode(evt);
190         $('selfck-item-barcode-input').select();
191     }
192 }
193
194 /**
195   * Display event text in the messages block
196   */
197 function selfckShowMsgNode(evt) {
198     var code = evt.textcode;
199     var msgspan = $('selfck-event-span');
200
201     // if we're not explicitly handling the event, just say "copy cannot circ"
202     if(!$('selfck-event-' + code)) 
203         code = 'COPY_CIRC_NOT_ALLOWED';
204
205     appendClear($('selfck-event-time'), text(new Date().toLocaleString()));
206     appendClear($('selfck-event-span'), text($('selfck-event-' + code).innerHTML));
207 }
208
209 /**
210   * Renders a row in the checkouts table for the current circulation
211   */
212 function selfckDislplayCheckout(evt) {
213     unHideMe($('selfck-items-out-table'));
214
215     var template = itemsOutTemplate.cloneNode(true);
216     var copy = evt.payload.copy;
217     var record = evt.payload.record;
218     var circ = evt.payload.circ;
219
220     if(record.isbn()) {
221             var pic = $n(template, 'selfck.jacket');
222             pic.setAttribute('src', '../ac/jacket/small/'+cleanISBN(record.isbn()));
223     }
224     $n(template, 'selfck.barcode').appendChild(text(copy.barcode()));
225     $n(template, 'selfck.title').appendChild(text(record.title()));
226     $n(template, 'selfck.author').appendChild(text(record.author()));
227     $n(template, 'selfck.due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
228     $n(template, 'selfck.remaining').appendChild(text(circ.renewal_remaining()));
229     if(isRenewal) {
230         hideMe($n(template, 'selfck.cotype_co'));
231         unHideMe($n(template, 'selfck.cotype_rn'));
232     }
233
234     $('selfck-items-out-tbody').appendChild(template);
235     $('selfck-item-barcode-input').value = '';
236
237
238     // flesh out the printable version of the page as well
239     var ptemplate = printTemplate.cloneNode(true);
240     $n(ptemplate, 'title').appendChild(text(record.title()));
241     $n(ptemplate, 'barcode').appendChild(text(copy.barcode()));
242     $n(ptemplate, 'due_date').appendChild(text(circ.due_date().replace(/T.*/,'')));
243     printWrapper.appendChild(ptemplate);
244
245     pendingXact = false;
246 }
247
248 /**
249   * Checks to see if this item is checked out to the current patron.  If so, 
250   * this sends the renewal request.
251   */
252 function selfckRenew() {
253
254     // first, make sure the item is checked out to this patron
255     var detailReq = new Request(
256         'open-ils.circ:open-ils.circ.copy_details.retrieve.barcode',
257         G.user.session, itemBarcode);
258
259     detailReq.callback(
260         function(r) {
261             var details = r.getResultObject();
262             if(details.circ.usr() == patron.id()) {
263                 // OK, this is our item, renew it
264                 isRenewal = true;
265                 var rnReq = new Request(
266                     'open-ils.circ:open-ils.circ.renew',
267                     G.user.session, {copy_barcode:itemBarcode});
268                 rnReq.request.alertEvent = false;
269                 rnReq.callback(selfckHandleCoResult);
270                 rnReq.send();
271             }
272         }
273     );
274
275     detailReq.send();
276 }
277
278 /**
279   * Sets the print date and prints the page
280   */
281 function selfckPrint() {
282     appendClear($('selfck-print-date'), text(new Date().toLocaleString()));
283     window.print();
284 }
285
286
287 /**
288   * Test method for generating dummy data in the checkout tables
289   */
290 function selfckMkDummyCirc() {
291     unHideMe($('selfck-items-out-table'));
292
293     var template = itemsOutTemplate.cloneNode(true);
294     $n(template, 'selfck.barcode').appendChild(text('123456789'));
295     $n(template, 'selfck.title').appendChild(text('Test Title'));
296     $n(template, 'selfck.author').appendChild(text('Test Author'));
297     $n(template, 'selfck.due_date').appendChild(text('2008-08-01'));
298     $n(template, 'selfck.remaining').appendChild(text('1'));
299     $('selfck-items-out-tbody').appendChild(template);
300
301     // flesh out the printable version of the page as well
302     var ptemplate = printTemplate.cloneNode(true);
303     $n(ptemplate, 'title').appendChild(text('Test Title'));
304     $n(ptemplate, 'barcode').appendChild(text('123456789'));
305     $n(ptemplate, 'due_date').appendChild(text('2008-08-01'));
306     printWrapper.appendChild(ptemplate);
307 }