From 7ef736f3ac6c1cc48e3bfab9070759aaf434b68d Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Mon, 15 Aug 2022 12:19:31 +0100 Subject: [PATCH] Bug 30979: Add checkout modal to the OPAC This patch adds a new self checkout modal to the OPAC when OpacTrustedCheckout is enabled and a user is logged in. The new modal allows an end user to scan an item barcode, check for item existance and availability and then check the item out after any confirmations have been displayed. --- .../bootstrap/en/includes/masthead.inc | 7 + .../bootstrap/en/includes/modals/checkout.inc | 25 +++ .../bootstrap/en/includes/opac-bottom.inc | 10 + .../opac-tmpl/bootstrap/js/modals/checkout.js | 182 ++++++++++++++++++ 4 files changed, 224 insertions(+) create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc create mode 100644 koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc index fbab4ec2c9..7b704b6e0c 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/masthead.inc @@ -80,6 +80,13 @@ [% END # / IF virtualshelves %] + [% IF ( Koha.Preference( 'OpacTrustedCheckout' ) && loggedinusername ) %] + + [% END %] [% IF Koha.Preference( 'opacuserlogin' ) == 1 || Koha.Preference( 'EnableOpacSearchHistory') || Koha.Preference( 'opaclanguagesdisplay' ) %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc new file mode 100644 index 0000000000..67d3c66e2c --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/modals/checkout.inc @@ -0,0 +1,25 @@ + + diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc index 4fab59077d..33cf6b8610 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc +++ b/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc @@ -117,6 +117,10 @@ [% END # /IF OpacLangSelectorMode == 'both' || OpacLangSelectorMode == 'footer' %] [% END # / UNLESS is_popup %] +[% IF ( Koha.Preference( 'OpacTrustedCheckout' ) && loggedinusername ) %] + [% INCLUDE 'modals/checkout.inc' %] +[% END %] + [% Asset.js("lib/jquery/jquery-3.6.0.min.js") | $raw %] [% Asset.js("lib/jquery/jquery-migrate-3.3.2.min.js") | $raw %] @@ -124,6 +128,9 @@ [% Asset.js("lib/bootstrap/js/bootstrap.bundle.min.js") | $raw %] [% Asset.js("lib/fontfaceobserver.min.js") | $raw %] [% Asset.js("lib/enquire.min.js") | $raw %] + [% Asset.js("js/global.js") | $raw %] [% IF ( OPACAmazonCoverImages || SyndeticsCoverImages ) %] [% END %] [% END %] +[% IF ( Koha.Preference( 'OpacTrustedCheckout' ) && loggedinusername ) %] + [% Asset.js("js/modals/checkout.js") | $raw %] +[% END %] [% KohaPlugins.get_plugins_opac_js | $raw %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js b/koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js new file mode 100644 index 0000000000..e5d48b7d4a --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/js/modals/checkout.js @@ -0,0 +1,182 @@ +$(document).ready(function() { + + $("#checkoutModal").on("shown.bs.modal", function(e) { + $("#checkoutResults").replaceWith('
'); + $("#availabilityResult").replaceWith('
'); + $("#external_id").focus(); + }); + + $('#checkoutModal').on('click', '#checkoutSubmit', function(e) { + let external_id = $('#checkout_barcode').val(); + let item_id; + let items = $.ajax({ + url: '/api/v1/public/items?external_id=' + external_id, + dataType: 'json', + type: 'GET', + success: function(data) { + console.log(data); + } + }); + + $('#availabilityResult').replaceWith('
'); + + let availability = items.then( + function(data, textStatus, jqXHR) { + if (data.length == 1) { + item_id = data[0].item_id; + console.log("Found one item with id: "+item_id); + return $.ajax({ + url: '/api/v1/public/checkouts/availability?item_id='+item_id+'&patron_id='+logged_in_user_id, + type: 'GET', + contentType: "json" + }); + } else { + $('#availabilityResult').append('
'+_("Failure: Item '%s' not found").format(external_id)+'
'); + } + }, + function(data, textStatus, jqXHR) { + console.log('Items request failed with: ' + textStatus); + console.log(data); + } + ); + + let checkout = availability.then( + function(data, textStatus, jqXHR) { + let result; + console.log(data); + // blocked + if (Object.keys(data.blockers).length >= 1) { + let report = $('
'+_("Item '%s' cannot be checked out for the following reasons: ").format(external_id)+'
'); + for (const blocker in data.blockers) { + if (data.blockers.hasOwnProperty(blocker)) { + report.append(`${blocker}`); + console.log(`${blocker}: ${data.blockers[blocker]}`); + } + } + $('#availabilityResult').append(report); + console.log("Request succeeded but blockers were reported"); + } + // requires confirmation + else if (Object.keys(data.confirms).length >= 1) { + let report = $('
'+_("Item '%s' needs confirmation for the following: ").format(external_id)+'
'); + for (const key in data.confirms) { + if (data.confirms.hasOwnProperty(key)) { + report.append(`${key}`); + console.log(`${key}: ${data.confirms[key]}`); + } + } + $('#availabilityResult').append(report); + $('#checkoutSubmit').replaceWith(''); + console.log("Request succeeded confirmation is required"); + } + // straight checkout + else { + let params = { + "checkout_id": undefined, + "patron_id": logged_in_user_id, + "item_id": item_id, + "due_date": undefined, + "library_id": undefined, + "issuer_id": undefined, + "checkin_date": undefined, + "last_renewed_date": undefined, + "renewals_count": undefined, + "unseen_renewals": undefined, + "auto_renew": undefined, + "auto_renew_error": undefined, + "timestamp": undefined, + "checkout_date": undefined, + "onsite_checkout": false, + "note": undefined, + "note_date": undefined, + "note_seen": undefined, + }; + result = $.ajax({ + url: '/api/v1/public/checkouts', + type: 'POST', + data: JSON.stringify(params), + contentType: "json" + }); + } + // warnings to display + if (Object.keys(data.warnings).length >= 1) { + let report = $('
'+_("The following warnings were reported:
")+'
'); + for (const key in data.warnings) { + if (data.warnings.hasOwnProperty(key)) { + report.append(`${key}`+""); + console.log(`${key}: ${data.confirms[key]}`); + } + } + $('#availabilityResult').append(report); + console.log("Request succeeded but there were warnings"); + } + + // return a rejected promise if we've reached here + return result ? result : $.Deferred().reject('Checkout halted'); + }, + function(data, textStatus, jqXHR) { + console.log('Items request failed with: ' + textStatus); + console.log(data); + } + ); + + checkout.then( + function(data, textStatus, jqXHR) { + console.log("checkout.then succeeded"); + $("#checkoutResults").replaceWith('
'+_("Item '%s' was checked out").format(external_id)+'
'); + $('#checkout_barcode').val("").focus(); + console.log(data); + // data retrieved from url2 as provided by the first request + }, + function(data, textStatus, jqXHR) { + console.log("checkout.then failed"); + } + ); + + }); + + $('#checkoutModal').on('click', '#checkoutConfirm', function(e) { + let item_id = $('#item_id').val(); + let token = $('#confirmation_token').val(); + let params = { + "checkout_id": undefined, + "patron_id": logged_in_user_id, + "item_id": item_id, + "due_date": undefined, + "library_id": undefined, + "issuer_id": undefined, + "checkin_date": undefined, + "last_renewed_date": undefined, + "renewals_count": undefined, + "unseen_renewals": undefined, + "auto_renew": undefined, + "auto_renew_error": undefined, + "timestamp": undefined, + "checkout_date": undefined, + "onsite_checkout": false, + "note": undefined, + "note_date": undefined, + "note_seen": undefined, + }; + let checkout = $.ajax({ + url: '/api/v1/public/checkouts?confirmation='+token, + type: 'POST', + data: JSON.stringify(params), + contentType: "json" + }); + + checkout.then( + function(data, textStatus, jqXHR) { + console.log("checkout.then succeeded"); + $('#item_id').remove; + $('#confirm_token').remove; + $('#checkout_barcode').val("").focus(); + $('#checkoutConfirm').replaceWith(''); + // data retrieved from url2 as provided by the first request + }, + function(data, textStatus, jqXHR) { + console.log("checkout.then failed"); + } + ); + }); +}); -- 2.20.1