From d251b57daeae16967612e8348a0e04342fc59c28 Mon Sep 17 00:00:00 2001 From: erickson Date: Wed, 30 Jul 2008 17:07:19 +0000 Subject: [PATCH] Basic web-based selfcheck interface. This interface implements a subset of http://open-ils.org/dokuwiki/doku.php?id=scratchpad:simple_self_check git-svn-id: svn://svn.open-ils.org/ILS/trunk@10188 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/examples/apache/eg_vhost.conf | 15 + .../web/opac/extras/selfcheck/selfcheck.css | 86 +++++ .../web/opac/extras/selfcheck/selfcheck.js | 307 ++++++++++++++++++ .../web/opac/extras/selfcheck/selfcheck.xml | 171 ++++++++++ .../opac/extras/selfcheck/selfcheck_print.css | 15 + Open-ILS/web/opac/locale/en-US/opac.dtd | 33 ++ 6 files changed, 627 insertions(+) create mode 100644 Open-ILS/web/opac/extras/selfcheck/selfcheck.css create mode 100644 Open-ILS/web/opac/extras/selfcheck/selfcheck.js create mode 100644 Open-ILS/web/opac/extras/selfcheck/selfcheck.xml create mode 100644 Open-ILS/web/opac/extras/selfcheck/selfcheck_print.css diff --git a/Open-ILS/examples/apache/eg_vhost.conf b/Open-ILS/examples/apache/eg_vhost.conf index cbfd9b960c..38d0ce5a99 100644 --- a/Open-ILS/examples/apache/eg_vhost.conf +++ b/Open-ILS/examples/apache/eg_vhost.conf @@ -239,6 +239,21 @@ RewriteRule ^/opac/extras/ac/jacket/(small|medium|large)/$ \ allow from all +# ---------------------------------------------------------------------------------- +# Selfcheck interface +# ---------------------------------------------------------------------------------- + + SetHandler perl-script + PerlSetVar OILSProxyTitle "Selfcheck Login" + PerlSetVar OILSProxyDescription "Please log in to activate the selfcheck interface" + PerlSetVar OILSProxyPermissions "STAFF_LOGIN" + PerlHandler OpenILS::WWW::Proxy + Options +ExecCGI + PerlSendHeader On + allow from all + + + # ---------------------------------------------------------------------------------- # Reports GUI # ---------------------------------------------------------------------------------- diff --git a/Open-ILS/web/opac/extras/selfcheck/selfcheck.css b/Open-ILS/web/opac/extras/selfcheck/selfcheck.css new file mode 100644 index 0000000000..b7aa88267c --- /dev/null +++ b/Open-ILS/web/opac/extras/selfcheck/selfcheck.css @@ -0,0 +1,86 @@ +.hide_me { + visibility: hidden; + display: none; +} +table { border-collapse:collapse; } +body { font-size: 12pt; } +.container:after {content: ""; display: block; height: 0; clear: both; } + +.biglabel { + font-size: 13pt; + margin: 5px; +} + +.selfck-link-span { + padding: 2px 4px 2px 4px; +} + +#selfck-items-out-table { + width: 100%; +} +.form_div { + width:100%; +} +.form_div span { + padding: 5px; +} + +#selfck-item-barcode-form { + margin-top:20px; +} +#selfck-items-out-table thead td { + font-weight: bold; +} +#selfck-items-out-table thead tr { + border-bottom: 2px solid #808080; +} +#selfck-items-out-table { + margin-top: 20px; +} +#selfck-items-out-tbody td { + padding: 4px 0px 4px 0px; +} +#selfck-items-out-tbody tr { + border-bottom: 1px solid #808080; +} +#selfck-pic-cell { width: 43px;} +.jacket { height: 50px; width: 40px; border: none;} + +#selfck-logout-div { + width: 100%; + margin: 0px 0px 0px 0px; + padding: 3px; + /*border-bottom:2px solid #e0f0e0;*/ + text-align: right; +} + +#selfck-patron-info-div { + text-align: left; + float:left; +} +#selfck-logout-link-div { + text-align: right; + float:right; +} + +#selfck-message-div { + border: 1px solid #e0f0e0; + height: 1.5em; + overflow: auto; + margin-bottom: 20px; +} +#selfck-item-barcode-form-div { + text-align: center; +} + +.print { + display: none; + visibility: hidden; +} +.noprint { + display: block; + visibility: visible; +} + + + diff --git a/Open-ILS/web/opac/extras/selfcheck/selfcheck.js b/Open-ILS/web/opac/extras/selfcheck/selfcheck.js new file mode 100644 index 0000000000..3ac63e0fb8 --- /dev/null +++ b/Open-ILS/web/opac/extras/selfcheck/selfcheck.js @@ -0,0 +1,307 @@ +/* ----------------------------------------------------------------- +* Copyright (C) 2008 Equinox Software, Inc. +* Bill Erickson +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +* 02110-1301, USA +----------------------------------------------------------------- */ + +var STAFF_SES_PARAM = 'ses'; +var patron = null +var itemBarcode = null; +var itemsOutTemplate = null; +var isRenewal = false; +var pendingXact = false; +var patronTimeout = 120000; +var timerId = null; +var printWrapper; +var printTemplate; +var successfulItems = {}; + + +function selfckInit() { + var cgi = new CGI(); + var staff = grabUser(cookieManager.read(STAFF_SES_PARAM) || cgi.param(STAFF_SES_PARAM)); + + /* + XXX we need org information (from the proxy?) + var t = fetchOrgSettingDefault(1, 'circ.selfcheck.patron_login_timeout'); + patronTimeout = (t) ? parseInt(t) * 1000 : patronTimeout; + */ + + if(!staff) { + // should not happen when behind the proxy + return alert('Staff must login'); + } + + unHideMe($('selfck-patron-login-container')); + $('selfck-patron-login-input').focus(); + + $('selfck-patron-login-input').onkeypress = function(evt) { + if(userPressedEnter(evt)) + selfckPatronLogin(); + }; + + $('selfck-item-barcode-input').onkeypress = function(evt) { + if(userPressedEnter(evt)) + selfckCheckout(); + }; + + // for debugging, allow passing the user barcode via param + var urlbc = new CGI().param('patron'); + if(urlbc) + selfckPatronLogin(urlbc); + + selfckStartTimer(); + + printWrapper = $('selfck-print-items-list'); + printTemplate = printWrapper.removeChild($n(printWrapper, 'selfck-print-items-template')); + itemsOutTemplate = $('selfck-items-out-tbody').removeChild($('selfck-items-out-row')); + +// selfckMkDummyCirc(); // testing only +} + +/* + * Start the logout timer + */ +function selfckStartTimer() { + timerId = setTimeout( + function() { + selfckLogoutPatron(); + }, + patronTimeout + ); + +} + +/* + * Reset the logout timer + */ +function selfckResetTimer() { + clearTimeout(timerId); + selfckStartTimer(); +} + +/* + * Clears fields and "logs out" the patron by reloading the page + */ +function selfckLogoutPatron() { + $('selfck-item-barcode-input').value = ''; // prevent browser caching + $('selfck-patron-login-input').value = ''; + if(patron) // page reload resets everything + location.href = location.href; +} + +/* + * Fetches the user by barcode and displays the item barcode input + */ + +function selfckPatronLogin(barcode) { + barcode = barcode || $('selfck-patron-login-input').value; + if(!barcode) return; + + var bcReq = new Request( + 'open-ils.actor:open-ils.actor.user.fleshed.retrieve_by_barcode', + G.user.session, barcode); + + bcReq.request.alertEvent = false; + + bcReq.callback(function(r) { + patron = r.getResultObject(); + if(checkILSEvent(patron)) { + if(patron.textcode == 'ACTOR_USER_NOT_FOUND') { + unHideMe($('selfck-patron-not-found')); + $('selfck-patron-login-input').select(); + return; + } + return alert(patron.textcode); + } + $('selfck-patron-login-input').value = ''; // reset the input + hideMe($('selfck-patron-login-container')); + unHideMe($('selfck-patron-checkout-container')); + $('selfck-patron-name-span').appendChild(text(patron.usrname())); + $('selfck-item-barcode-input').focus(); + }); + + bcReq.send(); +} + +/** + * Sends the checkout request + */ +function selfckCheckout() { + if(pendingXact) return; + selfckResetTimer(); + pendingXact = true; + isRenewal = false; + + removeChildren($('selfck-event-time')); + removeChildren($('selfck-event-span')); + + itemBarcode = $('selfck-item-barcode-input').value; + if(!itemBarcode) return; + + if (itemBarcode in successfulItems) { + selfckShowMsgNode({textcode:'dupe-barcode'}); + $('selfck-item-barcode-input').select(); + pendingXact = false; + return; + } + + var coReq = new Request( + 'open-ils.circ:open-ils.circ.checkout.full', + G.user.session, {patron_id:patron.id(), copy_barcode:itemBarcode}); + + coReq.request.alertEvent = false; + coReq.callback(selfckHandleCoResult); + coReq.send(); +} + +/** + * Handles the resulting event. If the item is already checked out, + * attempts renewal. Any other events will display a message + */ +function selfckHandleCoResult(r) { + var evt = r.getResultObject(); + + if(evt.textcode == 'SUCCESS') { + selfckDislplayCheckout(evt); + selfckShowMsgNode(evt); + successfulItems[itemBarcode] = 1; + + } else if(evt.textcode == 'OPEN_CIRCULATION_EXISTS') { + selfckRenew(); + + } else { + pendingXact = false; + selfckShowMsgNode(evt); + $('selfck-item-barcode-input').select(); + } +} + +/** + * Display event text in the messages block + */ +function selfckShowMsgNode(evt) { + var code = evt.textcode; + var msgspan = $('selfck-event-span'); + + // if we're not explicitly handling the event, just say "copy cannot circ" + if(!$('selfck-event-' + code)) + code = 'COPY_CIRC_NOT_ALLOWED'; + + appendClear($('selfck-event-time'), text(new Date().toLocaleString())); + appendClear($('selfck-event-span'), text($('selfck-event-' + code).innerHTML)); +} + +/** + * Renders a row in the checkouts table for the current circulation + */ +function selfckDislplayCheckout(evt) { + unHideMe($('selfck-items-out-table')); + + var template = itemsOutTemplate.cloneNode(true); + var copy = evt.payload.copy; + var record = evt.payload.record; + var circ = evt.payload.circ; + + if(record.isbn()) { + var pic = $n(template, 'selfck.jacket'); + pic.setAttribute('src', '../ac/jacket/small/'+cleanISBN(record.isbn())); + } + $n(template, 'selfck.barcode').appendChild(text(copy.barcode())); + $n(template, 'selfck.title').appendChild(text(record.title())); + $n(template, 'selfck.author').appendChild(text(record.author())); + $n(template, 'selfck.due_date').appendChild(text(circ.due_date().replace(/T.*/,''))); + $n(template, 'selfck.remaining').appendChild(text(circ.renewal_remaining())); + if(isRenewal) { + hideMe($n(template, 'selfck.cotype_co')); + unHideMe($n(template, 'selfck.cotype_rn')); + } + + $('selfck-items-out-tbody').appendChild(template); + $('selfck-item-barcode-input').value = ''; + + + // flesh out the printable version of the page as well + var ptemplate = printTemplate.cloneNode(true); + $n(ptemplate, 'title').appendChild(text(record.title())); + $n(ptemplate, 'barcode').appendChild(text(copy.barcode())); + $n(ptemplate, 'due_date').appendChild(text(circ.due_date().replace(/T.*/,''))); + printWrapper.appendChild(ptemplate); + + pendingXact = false; +} + +/** + * Checks to see if this item is checked out to the current patron. If so, + * this sends the renewal request. + */ +function selfckRenew() { + + // first, make sure the item is checked out to this patron + var detailReq = new Request( + 'open-ils.circ:open-ils.circ.copy_details.retrieve.barcode', + G.user.session, itemBarcode); + + detailReq.callback( + function(r) { + var details = r.getResultObject(); + if(details.circ.usr() == patron.id()) { + // OK, this is our item, renew it + isRenewal = true; + var rnReq = new Request( + 'open-ils.circ:open-ils.circ.renew', + G.user.session, {copy_barcode:itemBarcode}); + rnReq.request.alertEvent = false; + rnReq.callback(selfckHandleCoResult); + rnReq.send(); + } + } + ); + + detailReq.send(); +} + +/** + * Sets the print date and prints the page + */ +function selfckPrint() { + appendClear($('selfck-print-date'), text(new Date().toLocaleString())); + window.print(); +} + + +/** + * Test method for generating dummy data in the checkout tables + */ +function selfckMkDummyCirc() { + unHideMe($('selfck-items-out-table')); + + var template = itemsOutTemplate.cloneNode(true); + $n(template, 'selfck.barcode').appendChild(text('123456789')); + $n(template, 'selfck.title').appendChild(text('Test Title')); + $n(template, 'selfck.author').appendChild(text('Test Author')); + $n(template, 'selfck.due_date').appendChild(text('2008-08-01')); + $n(template, 'selfck.remaining').appendChild(text('1')); + $('selfck-items-out-tbody').appendChild(template); + + // flesh out the printable version of the page as well + var ptemplate = printTemplate.cloneNode(true); + $n(ptemplate, 'title').appendChild(text('Test Title')); + $n(ptemplate, 'barcode').appendChild(text('123456789')); + $n(ptemplate, 'due_date').appendChild(text('2008-08-01')); + printWrapper.appendChild(ptemplate); +} diff --git a/Open-ILS/web/opac/extras/selfcheck/selfcheck.xml b/Open-ILS/web/opac/extras/selfcheck/selfcheck.xml new file mode 100644 index 0000000000..b2a98dc282 --- /dev/null +++ b/Open-ILS/web/opac/extras/selfcheck/selfcheck.xml @@ -0,0 +1,171 @@ + + + + +]> + + + + + + + + + + + + + + + + + +
+ + +
+ &selfck.patron_barcode_label; + + + &selfck.event.patron_not_found; +
+ + +
+ + +
+
+ + &selfck.welcome; ! +
+ +
+ + +
+ + + + &selfck.event.co_success; + &selfck.event.unknown; + &selfck.event.patron_not_found; + &selfck.event.item_nocirc; + &selfck.event.item_noncat; + &selfck.event.dupe_barcode; + +
+ + +
+
+ +
&selfck.item_barcode_label;
+
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
&selfck.barcode;&selfck.title;&selfck.author;&selfck.due_date;&selfck.remaining;&selfck.cotype;
+ &selfck.cotype_co; + &selfck.cotype_rn; +
+
+
+ + +
+
+
+ You checked out the following items: +
    +
  1. +
    + Barcode: + Due Date: +
  2. +
+
+
+ + + diff --git a/Open-ILS/web/opac/extras/selfcheck/selfcheck_print.css b/Open-ILS/web/opac/extras/selfcheck/selfcheck_print.css new file mode 100644 index 0000000000..18cd1ee99d --- /dev/null +++ b/Open-ILS/web/opac/extras/selfcheck/selfcheck_print.css @@ -0,0 +1,15 @@ +.noprint { + display: none; + visibility: hidden; +} +.print { + display: block; + visibility: visible; + width: 100%; + font-size: 10pt; + color: black; + font-family: Arial; + background-color: white; +} + + diff --git a/Open-ILS/web/opac/locale/en-US/opac.dtd b/Open-ILS/web/opac/locale/en-US/opac.dtd index 7fed843742..72c924112a 100644 --- a/Open-ILS/web/opac/locale/en-US/opac.dtd +++ b/Open-ILS/web/opac/locale/en-US/opac.dtd @@ -634,3 +634,36 @@ Ensure Caps-Lock is off and try again or contact your local library."> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.43.2