checkout / copy in transit; avoid dupes
authorBill Erickson <berick@esilibrary.com>
Tue, 17 Jun 2014 15:08:49 +0000 (11:08 -0400)
committerBill Erickson <berick@esilibrary.com>
Tue, 17 Jun 2014 15:08:49 +0000 (11:08 -0400)
Signed-off-by: Bill Erickson <berick@esilibrary.com>
Open-ILS/src/templates/staff/circ/patron/t_checkout.tt2
Open-ILS/src/templates/staff/circ/share/t_copy_in_transit_dialog.tt2 [new file with mode: 0644]
Open-ILS/web/js/ui/default/staff/circ/patron/checkout.js
Open-ILS/web/js/ui/default/staff/circ/services/circ.js

index f1b9a4a..21b6e2b 100644 (file)
@@ -56,7 +56,7 @@
 <hr/>
 
 <eg-grid
-  id-field="id"
+  id-field="index"
   features="-display,-sort,-multisort"
   main-label="[% l('Checkouts') %]"
   items-provider="gridDataProvider"
diff --git a/Open-ILS/src/templates/staff/circ/share/t_copy_in_transit_dialog.tt2 b/Open-ILS/src/templates/staff/circ/share/t_copy_in_transit_dialog.tt2
new file mode 100644 (file)
index 0000000..4d38922
--- /dev/null
@@ -0,0 +1,32 @@
+<div>
+  <div class="modal-header">
+    <button type="button" class="close" 
+      ng-click="cancel()" aria-hidden="true">&times;</button>
+    <h4 class="modal-title">[% l('Copy In Transit') %]</h4>
+  </div>
+  <div class="modal-body">
+    <div class="strong-text">
+      [% l('There is an open transit on copy [_1]', 
+        '{{transit.target_copy().barcode()}}') %]
+    </div>
+    <div class="pad-vert"></div>
+    <div class="row">
+      <div class="col-md-4">[% l('Transit Date:') %]</div>
+      <div class="col-md-8">{{transit.source_send_time() | date:'short'}}</div>
+    </div>
+    <div class="row">
+      <div class="col-md-4">[% l('Transit Source:') %]</div>
+      <div class="col-md-8">{{transit.source().shortname()}}</div>
+    </div>
+    <div class="row">
+      <div class="col-md-4">[% l('Transit Destination:') %]</div>
+      <div class="col-md-8">{{transit.dest().shortname()}}</div>
+    </div>
+  </div>
+  <div class="modal-footer">
+    <input type="submit" class="btn btn-primary" ng-click="ok()"
+        value="[% l('Abort Transit then Checkout') %]"/>
+    <button class="btn btn-warning" 
+        ng-click="cancel()">[% l('Cancel') %]</button>
+  </div>
+</div>
index 62dae7d..5ca9b81 100644 (file)
@@ -23,6 +23,9 @@ function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc ,
         }
     });
 
+    // avoid multiple, in-flight attempts on the same barcode
+    var pending_barcodes = {};
+
     var printOnComplete = true;
     egCore.org.settings([
         'circ.staff_client.do_not_auto_attempt_print'
@@ -57,6 +60,16 @@ function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc ,
 
             args.copy_barcode = ''; // reset UI input
             params.noncat_type = ''; // "barcode"
+
+            if (pending_barcodes[params.copy_barcode]) {
+                console.log(
+                    "Skipping checkout of redundant barcode " 
+                    + params.copy_barcode
+                );
+                return;
+            }
+
+            pending_barcodes[params.copy_barcode] = true;
             send_checkout(params);
 
         } else {
@@ -95,7 +108,10 @@ function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc ,
                 munge_checkout_resp(co_resp);
     
                 // copy the response event into the original grid row item
-                angular.copy(co_resp.evt, row_item);
+                // note: angular.copy clobbers the destination
+                angular.forEach(co_resp.evt, function(v, k) {
+                    row_item[k] = v;
+                });
             },
             function() {
                 // Circ was rejected somewhere along the way.
@@ -103,7 +119,14 @@ function($scope , $q , $modal , $routeParams , egCore , egUser , patronSvc ,
                 $scope.checkouts.splice(row_item.index, 1);
                 $scope.gridDataProvider.refresh();
             }
-        );
+
+        )['finally'](function() {
+
+            // regardless of the outcome of the circ, remove the 
+            // barcode from the pending list.
+            if (params.copy_barcode)
+                delete pending_barcodes[params.copy_barcode];
+        });
     }
 
     // move some stuff around so it will play nice w/ the template
index 73f30e3..1134afd 100644 (file)
@@ -135,6 +135,9 @@ function($modal , $q , egCore , egAlertDialog , egConfirmDialog) {
             case 'OPEN_CIRCULATION_EXISTS':
                 return service.circ_exists_dialog(evt, params, options);
 
+            case 'COPY_IN_TRANSIT':
+                return service.copy_in_transit_dialog(evt, params, options);
+
             /* stuff to consider 
             PERM_FAILURE
             PATRON_BARRED
@@ -300,6 +303,66 @@ function($modal , $q , egCore , egAlertDialog , egConfirmDialog) {
         );
     }
 
+    service.copy_in_transit_dialog = function(evt, params, options) {
+        return $modal.open({
+            templateUrl: './circ/share/t_copy_in_transit_dialog',
+            controller: 
+                       ['$scope','$modalInstance','transit',
+                function($scope , $modalInstance , transit) {
+                $scope.transit = transit;
+                $scope.ok = function() { $modalInstance.close(transit) }
+                $scope.cancel = function() { $modalInstance.dismiss() }
+            }],
+            resolve : {
+                // fetch the conflicting open transit w/ fleshed copy
+                transit : function() {
+                    return egCore.pcrud.search('atc',
+                        {   dest_recv_time : null},
+                        {   flesh : 1, 
+                            flesh_fields : {atc : ['target_copy']},
+                            join : {
+                                acp : {
+                                    filter : {
+                                        barcode : params.copy_barcode,
+                                        deleted : 'f'
+                                    }
+                                }
+                            },
+                            limit : 1,
+                            order_by : {atc : 'source_send_time desc'}, 
+                        }
+                    ).then(function(transit) {
+                        transit.source(egCore.org.get(transit.source()));
+                        transit.dest(egCore.org.get(transit.dest()));
+                        return transit;
+                    });
+                }
+            }
+        }).result.then(
+            function(transit) {
+                // user chose to abort the transit then checkout
+                return service.abort_transit(transit.id())
+                .then(function() {
+                    return service.checkout(params, options);
+                });
+            }
+        );
+    }
+
+    service.abort_transit = function(transit_id) {
+        return egCore.net.request(
+            'open-ils.circ',
+            'open-ils.circ.transit.abort',
+            egCore.auth.token(), {transitid : transit_id}
+        ).then(function(resp) {
+            if (evt = egCore.evt.parse(resp)) {
+                alert(evt);
+                return $q.reject();
+            }
+            return $q.when();
+        });
+    }
+
     service.circ_exists_dialog = function(evt, params, options) {
         return $modal.open({
             templateUrl: './circ/share/t_circ_exists_dialog',