LP#1706147: handle multiple matches on patron barcode completion in web client
authorJeff Davis <jdavis@sitka.bclibraries.ca>
Fri, 6 Oct 2017 18:15:05 +0000 (11:15 -0700)
committerGalen Charlton <gmc@equinoxinitiative.org>
Tue, 7 Nov 2017 18:52:01 +0000 (13:52 -0500)
To test:

1. Add a barcode completion rule for BR1, applying to users and set to
   active, where "BR1" is the prefix.

2. Create a user with barcode "BR100001" and home library BR1.

3. Create another user with barcode "00001".

4. Login to the web client with BR1 as your working location. Go to
   "Check Out Item" and enter barcode "00001". EG will retrieve one of
   the two accounts you created; it ought to present a dialog that
   allows you to choose between BR00001 and 00001 (or none of the above).

Signed-off-by: Jeff Davis <jdavis@sitka.bclibraries.ca>
Signed-off-by: Cesar Velez <cesar.velez@equinoxinitiative.org>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/web/js/ui/default/staff/circ/patron/app.js

index f92eac1..eaaf9ba 100644 (file)
@@ -436,8 +436,8 @@ function($scope,  $q , $location , $filter , egCore , egNet , egUser , egAlertDi
 }])
 
 .controller('PatronBarcodeSearchCtrl',
 }])
 
 .controller('PatronBarcodeSearchCtrl',
-       ['$scope','$location','egCore','egConfirmDialog','egUser','patronSvc',
-function($scope , $location , egCore , egConfirmDialog , egUser , patronSvc) {
+       ['$scope','$location','egCore','egConfirmDialog','egUser','patronSvc','$uibModal','$q',
+function($scope , $location , egCore , egConfirmDialog , egUser , patronSvc , $uibModal , $q) {
     $scope.selectMe = true; // focus text input
     patronSvc.clearPrimary(); // clear the default user
 
     $scope.selectMe = true; // focus text input
     patronSvc.clearPrimary(); // clear the default user
 
@@ -472,72 +472,127 @@ function($scope , $location , egCore , egConfirmDialog , egUser , patronSvc) {
 
         var user_id;
 
 
         var user_id;
 
-        // lookup barcode
-        egCore.net.request(
-            'open-ils.actor',
-            'open-ils.actor.get_barcodes',
-            egCore.auth.token(), egCore.auth.user().ws_ou(), 
-            'actor', args.barcode)
+        // given a scanned barcode, this function finds any matching users
+        // and handles multiple matches due to barcode completion
+        function handleBarcodeCompletion(scanned_barcode) {
+            var deferred = $q.defer();
 
 
-        .then(function(resp) { // get_barcodes
+            egCore.net.request(
+                'open-ils.actor',
+                'open-ils.actor.get_barcodes',
+                egCore.auth.token(), egCore.auth.user().ws_ou(), 
+                'actor', scanned_barcode)
 
 
-            if (evt = egCore.evt.parse(resp)) {
-                alert(evt); // FIXME
-                return;
-            }
+            .then(function(resp) { // get_barcodes
 
 
-            if (!resp || !resp[0]) {
-                $scope.bcNotFound = args.barcode;
-                $scope.selectMe = true;
-                egCore.audio.play('warning.patron.not_found');
-                return;
-            }
+                if (evt = egCore.evt.parse(resp)) {
+                    alert(evt); // FIXME
+                    deferred.reject();
+                    return;
+                }
+
+                if (!resp || !resp[0]) {
+                    $scope.bcNotFound = args.barcode;
+                    $scope.selectMe = true;
+                    egCore.audio.play('warning.patron.not_found');
+                    deferred.reject();
+                    return;
+                }
+
+                if (resp.length == 1) {
+                    // exactly one matching barcode: return it
+                    deferred.resolve();
+                    user_id = resp[0].id;
+                } else {
+                    // multiple matching barcodes: let the user pick one 
+                    var barcode_map = {};
+                    var matches = [];
+                    var promises = [];
+                    var selected_barcode;
+                    angular.forEach(resp, function(match) {
+                        promises.push(
+                            egUser.get(match.id, {useFields : ['home_ou']}).then(function(user) {
+                                barcode_map[match.barcode] = user.id();
+                                matches.push( {
+                                    barcode: match.barcode,
+                                    title: user.first_given_name() + ' ' + user.family_name(),
+                                    org_name: user.home_ou().name(),
+                                    org_shortname: user.home_ou().shortname()
+                                });
+                            })
+                        );
+                    });
+                    return $q.all(promises)
+                    .then(function() {
+                        $uibModal.open({
+                            templateUrl: './circ/share/t_barcode_choice_dialog',
+                            controller:
+                                ['$scope', '$uibModalInstance',
+                                function($scope, $uibModalInstance) {
+                                $scope.matches = matches;
+                                $scope.ok = function(barcode) {
+                                    $uibModalInstance.close();
+                                    selected_barcode = barcode;
+                                }
+                                $scope.cancel = function() {$uibModalInstance.dismiss()}
+                            }],
+                        }).result.then(function() {
+                            deferred.resolve();
+                            user_id = barcode_map[selected_barcode];
+                        });
+                    });
+                }
+            });
+            return deferred.promise;
+        }
+
+        // call our function to lookup matching users for the scanned barcode
+        handleBarcodeCompletion(args.barcode).then(function() {
 
             // see if an opt-in request is needed
 
             // see if an opt-in request is needed
-            user_id = resp[0].id;
             return egCore.net.request(
                 'open-ils.actor',
                 'open-ils.actor.user.org_unit_opt_in.check',
             return egCore.net.request(
                 'open-ils.actor',
                 'open-ils.actor.user.org_unit_opt_in.check',
-                egCore.auth.token(), user_id);
+                egCore.auth.token(), user_id
+            ).then(function(optInResp) { // opt_in_check
 
 
-        }).then(function(optInResp) { // opt_in_check
-
-            if (evt = egCore.evt.parse(optInResp)) {
-                alert(evt); // FIXME
-                return;
-            }
+                if (evt = egCore.evt.parse(optInResp)) {
+                    alert(evt); // FIXME
+                    return;
+                }
 
 
-            if (optInResp == 2) {
-                // opt-in disallowed at this location by patron's home library
-                $scope.optInRestricted = true;
-                $scope.selectMe = true;
-                egCore.audio.play('warning.patron.opt_in_restricted');
-                return;
-            }
-           
-            if (optInResp == 1) {
-                // opt-in handled or not needed
-                return loadPatron(user_id);
-            }
+                if (optInResp == 2) {
+                    // opt-in disallowed at this location by patron's home library
+                    $scope.optInRestricted = true;
+                    $scope.selectMe = true;
+                    egCore.audio.play('warning.patron.opt_in_restricted');
+                    return;
+                }
+            
+                if (optInResp == 1) {
+                    // opt-in handled or not needed
+                    return loadPatron(user_id);
+                }
 
 
-            // opt-in needed, show the opt-in dialog
-            egUser.get(user_id, {useFields : []})
+                // opt-in needed, show the opt-in dialog
+                egUser.get(user_id, {useFields : []})
 
 
-            .then(function(user) { // retrieve user
-                var org = egCore.org.get(user.home_ou());
-                egConfirmDialog.open(
-                    egCore.strings.OPT_IN_DIALOG_TITLE,
-                    egCore.strings.OPT_IN_DIALOG,
-                    {   family_name : user.family_name(),
-                        first_given_name : user.first_given_name(),
-                        org_name : org.name(),
-                        org_shortname : org.shortname(),
-                        ok : function() { createOptIn(user.id()) },
-                        cancel : function() {}
-                    }
-                );
+                .then(function(user) { // retrieve user
+                    var org = egCore.org.get(user.home_ou());
+                    egConfirmDialog.open(
+                        egCore.strings.OPT_IN_DIALOG_TITLE,
+                        egCore.strings.OPT_IN_DIALOG,
+                        {   family_name : user.family_name(),
+                            first_given_name : user.first_given_name(),
+                            org_name : org.name(),
+                            org_shortname : org.shortname(),
+                            ok : function() { createOptIn(user.id()) },
+                            cancel : function() {}
+                        }
+                    );
+                })
             })
             })
-        });
+        })
     }
 }])
 
     }
 }])