LP#902255: Protect against hold double-capture
authorMike Rylander <mrylander@gmail.com>
Mon, 8 Jun 2015 15:11:04 +0000 (11:11 -0400)
committerJason Stephenson <jstephenson@mvlc.org>
Mon, 15 Jun 2015 19:14:04 +0000 (15:14 -0400)
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 <mrylander@gmail.com>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Signed-off-by: Jason Stephenson <jstephenson@mvlc.org>
Open-ILS/src/sql/Pg/090.schema.action.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.disallow-double-capture.sql [new file with mode: 0644]
Open-ILS/xul/staff_client/server/circ/util.js
Open-ILS/xul/staff_client/server/locale/en-US/circ.properties

index 0a1c5bf..ca1e7f3 100644 (file)
@@ -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 (file)
index 0000000..e644d35
--- /dev/null
@@ -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;
+
index 96eee5b..2328f4f 100644 (file)
@@ -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 */ }
index 6a2aea1..415eb97 100644 (file)
@@ -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