LP#1081551 Serials batch recv. dupe barcode check
authorBill Erickson <berick@esilibrary.com>
Fri, 11 Apr 2014 19:51:53 +0000 (15:51 -0400)
committerBen Shum <bshum@biblio.org>
Wed, 10 Sep 2014 21:16:32 +0000 (17:16 -0400)
Exit processing and return an event if the barcode on a new serial.unit
collides with an existing serial.unit or asset.copy barcode in the
serial receive API.

In the UI, detect the dupe barcode event and provide an error message to
the user.

Signed-off-by: Bill Erickson <berick@esilibrary.com>
Signed-off-by: Jennifer Pringle <jpringle@sitka.bclibraries.ca>
Signed-off-by: Ben Shum <bshum@biblio.org>
Open-ILS/src/perlmods/lib/OpenILS/Application/Serial.pm
Open-ILS/xul/staff_client/server/locale/en-US/serial.properties
Open-ILS/xul/staff_client/server/serial/batch_receive.js

index 7d1ad2e..35bcc82 100644 (file)
@@ -765,8 +765,32 @@ sub _delete_sunit {
 sub _create_sunit {
     my ($editor, $sunit) = @_;
 
+    # The unique barcode constraint does not span asset.copy and serial.unit.
+    # ensure the barcode on the new unit does not collide with an existing
+    # asset.copy barcode.
+    my $existing = $editor->search_asset_copy(
+        {deleted => 'f', barcode => $sunit->barcode})->[0];
+
+    if (!$existing) {
+        # The DB will prevent duplicate serial.unit barcodes, but for 
+        # consistency (and a more specific error message for the
+        # user), prevent creation attempts on serial unit barcode
+        # collisions as well.
+        $existing = $editor->search_serial_unit(
+            {deleted => 'f', barcode => $sunit->barcode})->[0];
+    }
+
+    if ($existing) {
+        $editor->rollback;
+        return new OpenILS::Event(
+            'SERIAL_UNIT_BARCODE_COLLISION', note => 
+            'Serial unit barcode collides with existing unit/copy barcode',
+            payload => {barcode => $sunit->barcode}
+        );
+    }
+
     $logger->info("sunit-alter: new Unit ".OpenSRF::Utils::JSON->perl2JSON($sunit));
-    return $editor->event unless $editor->create_serial_unit($sunit);
+    return $editor->die_event unless $editor->create_serial_unit($sunit);
     return 0;
 }
 
@@ -1742,7 +1766,8 @@ sub receive_items_one_unit_per {
             $user_unit->editor($user_id);
             $user_unit->creator($user_id);
 
-            return $e->die_event unless $e->create_serial_unit($user_unit);
+            $evt = _create_sunit($e, $user_unit);
+            return $evt if $evt;
 
             # save reference to new unit
             $item->unit($e->data->id);
index 14c16bb..d96c1e8 100644 (file)
@@ -110,6 +110,7 @@ batch_receive.cn_for_lib=Do you want to use this call number at %1$s?\nIt doesn'
 batch_receive.missing_units=You have not provided barcodes and call numbers for all of the selected items.  Choose OK to receive those items anyway, or choose Cancel to supply the missing information.
 batch_receive.missing_cn=You cannot assign a barcode without selecting a call number. Please correct the non-conforming units.
 batch_receive.print_routing_list_users=Print Routing List
+batch_receive.unit_barcode_collision=Serial unit barcode '%1$s' collides with an existing barcode.
 pattern_wizard.enumeration.a=First level
 pattern_wizard.enumeration.b=Second level
 pattern_wizard.enumeration.c=Third level
index f2a15f7..f29063b 100644 (file)
@@ -1067,7 +1067,29 @@ function BatchReceiver() {
                 "oncomplete": function(r) {
                     try {
                         var streams_for_printing = [];
-                        while (item_id = openils.Util.readResponse(r)) {
+
+                        // first check for problems encountered during
+                        // receive and exit early if any are found.
+                        var item_ids = [];
+                        while (item_id = openils.Util.readResponse(r, true)) {
+                            if (typeof item_id == 'object') { // event
+                                if (item_id.textcode == 
+                                    'SERIAL_UNIT_BARCODE_COLLISION') {
+                                    alert(F(
+                                        'unit_barcode_collision', 
+                                        item_id.payload.barcode
+                                    ));
+                                } else {
+                                    // unexpected event, rely on toString()
+                                    alert(item_id); 
+                                }
+                                busy(false);
+                                return;
+                            }
+                            item_ids.push(item_id);
+                        }
+
+                        while (item_id = item_ids.shift()) { 
                             if (self._wants_print_routing[item_id]) {
                                 streams_for_printing.push(
                                     self.item_cache[item_id].stream()