LP#1709521 Webstaff show recent patrons
authorBill Erickson <berickxx@gmail.com>
Sat, 12 Aug 2017 15:52:40 +0000 (11:52 -0400)
committerBill Erickson <berickxx@gmail.com>
Sat, 12 Aug 2017 15:57:09 +0000 (11:57 -0400)
Adds a new library setting 'ui.staff.max_recent_patrons' which
specifices the number of recently accessed patrons staff may quickly
refetch from the browser client interface.  If no value is set, it
defaults to 1 for backwards compatibility.

If the value is 0 or less, no recent patrons may be retrieved and the
'Retrieve Last Patron' action is hidden.  If the value is > 1 a new
'Retrieve Recent Patrons' menu item appears.  When clicked, the list
of recent patrons is displayed in the patron search interface, most
recently accessed patrons sorted to the top.

For privacy, the recent patrons list expires from the browser when the
authenticion token expires.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.data.recent-patrons.sql [new file with mode: 0644]
Open-ILS/src/templates/staff/navbar.tt2
Open-ILS/web/js/ui/default/staff/circ/patron/app.js
Open-ILS/web/js/ui/default/staff/services/navbar.js
Open-ILS/web/js/ui/default/staff/services/startup.js

index e95d94c..4ffb86b 100644 (file)
@@ -17125,3 +17125,26 @@ INSERT into config.org_unit_setting_type
         'Define the time zone in which a library physically resides',
         'coust', 'description'),
     'string');
+
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype)
+VALUES (
+    'ui.staff.max_recent_patrons',
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of Retrievable Recent Patrons',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of most recently accessed patrons that can be re-retrieved ' ||
+        'in the staff client.  A value of 0 or less disables the feature',
+        'coust',
+        'description'
+    ),
+    'circ',
+    'integer'
+);
+
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.recent-patrons.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.recent-patrons.sql
new file mode 100644 (file)
index 0000000..3cf897d
--- /dev/null
@@ -0,0 +1,26 @@
+BEGIN;
+
+-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+    (name, label, description, grp, datatype)
+VALUES (
+    'ui.staff.max_recent_patrons',
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of Retrievable Recent Patrons',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'ui.staff.max_recent_patrons',
+        'Number of most recently accessed patrons that can be re-retrieved ' ||
+        'in the staff client.  A value of 0 or less disables the feature',
+        'coust',
+        'description'
+    ),
+    'circ',
+    'integer'
+);
+
+COMMIT;
index ba99321..c42c8cf 100644 (file)
               [% l('Register Patron') %]
             </a>
           </li>
-          <li>
+          <li ng-if="showRecentPatron">
             <a href="./circ/patron/last" target="_self"
               eg-accesskey="[% l('f8') %]" 
               eg-accesskey-desc="[% l('Retrieve Last Patron') %]">
               [% l('Retrieve Last Patron') %]
             </a>
           </li>
+          <li ng-if="showRecentPatrons">
+            <a href="./circ/patron/search?show_recent=1" target="_self"
+              eg-accesskey-desc="[% l('Retrieve Recent Patrons') %]">
+              <span class="glyphicon glyphicon-share-alt"></span>
+              [% l('Retrieve Recent Patrons') %]
+            </a>
+          </li>
           <li>
             <a href="./circ/patron/pending/list" target="_self">
               <span class="glyphicon glyphicon-thumbs-up"></span>
index 1452ce5..23cec43 100644 (file)
@@ -292,6 +292,49 @@ function($q , $timeout , $location , egCore,  egUser , $locale) {
         return $q.when();
     }
 
+    // Set the show-recent flag true only once, then set it to
+    // false the first time it's used.
+    service.showRecentPatrons = function() {
+        if (service.showRecent === undefined 
+            && Boolean($location.path().match(/search/))
+            && Boolean($location.search().show_recent))
+            service.showRecent = true;
+
+        return service.showRecent;
+    }
+
+    service.getRecentPatrons = function() {
+        // avoid getting stuck in a show-recent loop
+        service.showRecent = false;
+
+        if (service.maxRecentPatrons < 1) return $q.when();
+        var patrons = 
+            egCore.hatch.getLoginSessionItem('eg.circ.recent_patrons') || [];
+
+        // add home_ou to the list of fleshed fields for recent patrons
+        var fleshFields = egUser.defaultFleshFields.slice(0);
+        fleshFields.push('home_ou');
+
+        var deferred = $q.defer();
+        function getNext() {
+            if (patrons.length == 0) {
+                deferred.resolve();
+                return;
+            }
+            egUser.get(patrons[0], {useFields : fleshFields}).then(
+                function(usr) { // fetch first user
+                    deferred.notify(usr);
+                    patrons.splice(0, 1); // remove first user from list
+                    getNext();
+                }
+            );
+        }
+
+        getNext();
+        return deferred.promise;
+    }
+
+
     // sets the primary display user, fetching data as necessary.
     service.setPrimary = function(id, user, force) {
         var user_id = id ? id : (user ? user.id() : null);
@@ -301,8 +344,19 @@ function($q , $timeout , $location , egCore,  egUser , $locale) {
         if (!user_id) return $q.reject();
 
         // when loading a new patron, update the last patron setting
-        if (!service.current || service.current.id() != user_id)
-            egCore.hatch.setLoginSessionItem('eg.circ.last_patron', user_id);
+        if (service.maxRecentPatrons > 0 &&
+            (!service.current || service.current.id() != user_id)) {
+            var patrons = 
+                egCore.hatch.getLoginSessionItem('eg.circ.recent_patrons') || [];
+            patrons.splice(0, 0, user_id);  // put this user at front
+            patrons.splice(service.maxRecentPatrons, 1); // remove excess
+
+            // remove any other occurrences of user_id
+            var idx = patrons.indexOf(user_id, 1);
+            if (idx > 0) patrons.splice(idx, 1);
+
+            egCore.hatch.setLoginSessionItem('eg.circ.recent_patrons', patrons);
+        }
 
         // avoid running multiple retrievals for the same patron, which
         // can happen during dbl-click by maintaining a single running
@@ -647,6 +701,12 @@ function($scope,  $q , $location , $filter , egCore , egNet , egUser , egAlertDi
         $scope.aous = egCore.env.aous;
         $scope.auth_user_id = egCore.auth.user().id();
 
+        // max recents setting is loaded and scrubbed during startup.
+        // cache it in a local variable for ease of access.
+        egCore.org.settings('ui.staff.max_recent_patrons').then(function(s) {
+            patronSvc.maxRecentPatrons = s['ui.staff.max_recent_patrons'];
+        });
+
         if (patron_id) {
             $scope.patron_id = patron_id;
             return patronSvc.setPrimary($scope.patron_id)
@@ -932,7 +992,7 @@ function($scope,  $q,  $routeParams,  $timeout,  $window,  $location,  egCore,
 
     var propagate;
     var propagate_inactive;
-    if (patronSvc.lastSearch) {
+    if (patronSvc.lastSearch && !patronSvc.showRecentPatrons()) {
         propagate = patronSvc.lastSearch.search;
         // home_ou needs to be treated specially
         propagate.home_ou = {
@@ -987,6 +1047,11 @@ function($scope,  $q,  $routeParams,  $timeout,  $window,  $location,  egCore,
     provider.get = function(offset, count) {
         var deferred = $q.defer();
 
+        if (patronSvc.showRecentPatrons()) {
+            // avoid getting stuck in show-recent mode
+            return patronSvc.getRecentPatrons();
+        }
+
         var fullSearch;
         if (patronSvc.urlSearch) {
             fullSearch = patronSvc.urlSearch;
@@ -1766,8 +1831,9 @@ function($scope,  $routeParams , $location , egCore , patronSvc) {
        ['$scope','$location','egCore',
 function($scope , $location , egCore) {
 
-    var id = egCore.hatch.getLoginSessionItem('eg.circ.last_patron');
-    if (id) return $location.path('/circ/patron/' + id + '/checkout');
+    var ids = egCore.hatch.getLoginSessionItem('eg.circ.recent_patrons') || [];
+    if (ids.length) 
+        return $location.path('/circ/patron/' + ids[0] + '/checkout');
 
     $scope.no_last = true;
 }])
index 713d9f3..1d90691 100644 (file)
@@ -116,6 +116,13 @@ angular.module('egCoreMod')
                             $scope.op_changed = egCore.auth.OCtoken() ? true : false;
                             $scope.username = egCore.auth.user().usrname();
                             $scope.workstation = egCore.auth.workstation();
+
+                            egCore.org.settings('ui.staff.max_recent_patrons')
+                            .then(function(s) {
+                                var val = s['ui.staff.max_recent_patrons'];
+                                $scope.showRecentPatron = val > 0;
+                                $scope.showRecentPatrons = val > 1;
+                            });
                         }
                     }
                 );
index 038eb2d..603d040 100644 (file)
@@ -25,14 +25,15 @@ function($q,  $rootScope,  $location,  $window,  egIDL,  egAuth,  egEnv , egOrg
 
     var service = { promise : null }
 
-    // Load date/time format settings on all pages.  Add more .push(...)
-    // calls to add more universal data-loading functions. 
+    // Some org settings affect every page.  Load them during startup.  
+    // Other startup data loaders can be added by appending to egEnv.loaders.
     // egEnv.loaders functions must return a promise.
     egEnv.loaders.push(
         function() {
             return egOrg.settings([
                 'webstaff.format.dates',
                 'webstaff.format.date_and_time',
+                'ui.staff.max_recent_patrons', // affects navbar
                 'lib.timezone'
             ]).then(
                 function(set) {
@@ -40,6 +41,10 @@ function($q,  $rootScope,  $location,  $window,  egIDL,  egAuth,  egEnv , egOrg
                         set['webstaff.format.dates'] || 'shortDate';
                     $rootScope.egDateAndTimeFormat = 
                         set['webstaff.format.date_and_time'] || 'short';
+
+                    // default to 1 for backwards compat.
+                    if (set['ui.staff.max_recent_patrons'] === null)
+                        set['ui.staff.max_recent_patrons'] = 1
                 }
             );
         }