From 32e415a205c40f013d8839a02bb50033a0606072 Mon Sep 17 00:00:00 2001 From: Mike Rylander Date: Mon, 8 Jun 2015 11:11:04 -0400 Subject: [PATCH] LP#902255: Protect against hold double-capture When the staff client is in Fast Scan (async) mode, it is possible to double-scan at checkin and cause two holds to be captured by the same item. By creating a specially crafted unique index we ensure that the database rejects this situation. This protection would cause unhandled errors in the staff client, so we also register a new string to be displayed when this particular situation occurs, alerting staff to the possible double-scan of a barcode at checkin IFF they are using async mode. Signed-off-by: Mike Rylander Signed-off-by: Kathy Lussier Signed-off-by: Jason Stephenson --- Open-ILS/src/sql/Pg/090.schema.action.sql | 1 + .../upgrade/XXXX.schema.disallow-double-capture.sql | 13 +++++++++++++ Open-ILS/xul/staff_client/server/circ/util.js | 8 ++++++-- .../server/locale/en-US/circ.properties | 1 + 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.disallow-double-capture.sql diff --git a/Open-ILS/src/sql/Pg/090.schema.action.sql b/Open-ILS/src/sql/Pg/090.schema.action.sql index 0a1c5bf895..ca1e7f3894 100644 --- a/Open-ILS/src/sql/Pg/090.schema.action.sql +++ b/Open-ILS/src/sql/Pg/090.schema.action.sql @@ -429,6 +429,7 @@ CREATE INDEX hold_request_fulfillment_staff_idx ON action.hold_request ( fulfill CREATE INDEX hold_request_requestor_idx ON action.hold_request ( requestor ); CREATE INDEX hold_request_open_idx ON action.hold_request (id) WHERE cancel_time IS NULL AND fulfillment_time IS NULL; CREATE INDEX hold_request_current_copy_before_cap_idx ON action.hold_request (current_copy) WHERE capture_time IS NULL AND cancel_time IS NULL; +CREATE UNIQUE INDEX hold_request_capture_protect_idx ON action.hold_request (current_copy) WHERE current_copy IS NOT NULL AND capture_time IS NOT NULL AND cancel_time IS NULL AND fulfillment_time IS NULL; CREATE TABLE action.hold_request_note ( diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.disallow-double-capture.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.disallow-double-capture.sql new file mode 100644 index 0000000000..e644d3517d --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.disallow-double-capture.sql @@ -0,0 +1,13 @@ +BEGIN; + +SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +CREATE UNIQUE INDEX CONCURRENTLY + hold_request_capture_protect_idx ON action.hold_request (current_copy) + WHERE current_copy IS NOT NULL -- sometimes null in old/bad data + AND capture_time IS NOT NULL + AND cancel_time IS NULL + AND fulfillment_time IS NULL; + +COMMIT; + diff --git a/Open-ILS/xul/staff_client/server/circ/util.js b/Open-ILS/xul/staff_client/server/circ/util.js index 96eee5b084..2328f4f75b 100644 --- a/Open-ILS/xul/staff_client/server/circ/util.js +++ b/Open-ILS/xul/staff_client/server/circ/util.js @@ -2666,7 +2666,7 @@ circ.util.checkin_via_barcode = function(session,params,backdate,auto_print,asyn JSAN.use('util.error'); var error = new util.error(); try { var check = req.getResultObject(); - var r = circ.util.checkin_via_barcode2(session,params,backdate,auto_print,check); + var r = circ.util.checkin_via_barcode2(session,params,backdate,auto_print,check,async); try { error.work_log( document.getElementById('circStrings').getFormattedString( @@ -2772,7 +2772,7 @@ circ.util.checkin_via_barcode = function(session,params,backdate,auto_print,asyn } }; -circ.util.checkin_via_barcode2 = function(session,params,backdate,auto_print,check) { +circ.util.checkin_via_barcode2 = function(session,params,backdate,auto_print,check,async) { try { JSAN.use('util.error'); var error = new util.error(); JSAN.use('util.network'); var network = new util.network(); @@ -3606,6 +3606,10 @@ circ.util.checkin_via_barcode2 = function(session,params,backdate,auto_print,che check.what_happened = 'error'; sound.special('checkin.error'); error.standard_network_error_alert(document.getElementById('circStrings').getString('staff.circ.checkin.suggest_offline')); + } else /* UPDATE failed, and async */ if (check.ilsevent == 2001 && async) { + check.what_happened = 'error'; + sound.special('checkin.error'); + error.standard_network_error_alert(document.getElementById('circStrings').getString('staff.circ.checkin.possible_dupe_scan')); } else { if (check.ilsevent == null) { return null; /* handled */ } diff --git a/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties b/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties index 6a2aea1fc1..415eb979d8 100644 --- a/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties +++ b/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties @@ -450,6 +450,7 @@ staff.circ.checkin.error=Check In Failed (in circ.util.checkin) (%1$s): # "Circulation" - check &staff.main.menu.circ.label; in lang.dtd # "Offline Interface" - check &staff.main.menu.circ.offline.label; in lang.dtd staff.circ.checkin.suggest_offline=Check In Failed. If you wish to use the offline interface, in the top menubar select Circulation -> Offline Interface +staff.circ.checkin.possible_dupe_scan=Check In May Have Failed. Possible double-scan of the barcode. Use Item Status to confirm Check In and possible Hold capture. staff.circ.checkin.renew_failed.error=Renew Failed for %1$s staff.circ.checkin.renew_failed.override=Override Renew Failure? staff.circ.renew.barcode=Barcode: %1$s -- 2.43.2