lp1841270 eg1_title_holds_via_item_status
authorJason Etheridge <jason@EquinoxInitiative.org>
Fri, 19 Jul 2019 22:59:19 +0000 (18:59 -0400)
committerJason Etheridge <jason@EquinoxInitiative.org>
Fri, 23 Aug 2019 19:29:16 +0000 (15:29 -0400)
adds a Title Hold option to certain invocations of Request Items
(Item Status, Copy Buckets, but not Holdings View)

switches count of items to count of titles when Title hold option
is selected

adds a checkbox for honoring the preferred notification settings
and default pickup library of the selected patron

adds a success/failure toast for Request Items

Signed-off-by: Jason Etheridge <jason@EquinoxInitiative.org>
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
Open-ILS/src/templates/staff/cat/bucket/copy/index.tt2
Open-ILS/src/templates/staff/cat/catalog/t_request_items.tt2
Open-ILS/src/templates/staff/cat/item/index.tt2
Open-ILS/web/js/ui/default/staff/cat/bucket/copy/app.js
Open-ILS/web/js/ui/default/staff/cat/item/app.js
Open-ILS/web/js/ui/default/staff/circ/services/item.js

index 1336e4e..e19915e 100644 (file)
@@ -108,6 +108,36 @@ sub test_and_create_hold_batch {
 
             $params->{'depth'} = $res->{'depth'} if $res->{'depth'};
 
+            if ($$oargs{honor_user_settings}) {
+                my $recipient = $e->retrieve_actor_user($$params{patronid})
+                    or return $e->die_event;
+                my $opac_hold_notify = $e->search_actor_user_setting(
+                    {usr => $$params{patronid}, name => 'opac.hold_notify'})->[0];
+                if ($opac_hold_notify) {
+                    if ($opac_hold_notify->value =~ 'email') {
+                        $$params{email_notify} = 1;
+                    }
+                    if ($opac_hold_notify->value =~ 'phone') {
+                        my $opac_default_phone = $e->search_actor_user_setting(
+                            {usr => $$params{patronid}, name => 'opac.default_phone'})->[0];
+                        # FIXME - what's up with the ->value putting quotes around the string?
+                        if ($opac_default_phone && $opac_default_phone->value =~ /^"(.*)"$/) {
+                            $$params{phone_notify} = $1;
+                        }
+                    }
+                    if ($opac_hold_notify->value =~ 'sms') {
+                        my $opac_default_sms_carrier = $e->search_actor_user_setting(
+                            {usr => $$params{patronid}, name => 'opac.default_sms_carrier'})->[0];
+                        $$params{sms_carrier} = $opac_default_sms_carrier->value if $opac_default_sms_carrier;
+                        my $opac_default_sms_notify = $e->search_actor_user_setting(
+                            {usr => $$params{patronid}, name => 'opac.default_sms_notify'})->[0];
+                        if ($opac_default_sms_notify && $opac_default_sms_notify->value =~ /^"(.*)"$/) {
+                            $$params{sms_notify} = $1;
+                        }
+                    }
+                }
+            }
+
             # Remove oargs from params so holds can be created.
             if ($$params{oargs}) {
                 delete $$params{oargs};
index 91d2f20..74a379f 100644 (file)
       "[% l('One or more items could not be transferred. Override?') %]";
     s.OVERRIDE_TRANSFER_COPY_BUCKET_ITEMS_TO_MARKED_VOLUME_BODY =
       "[% l('Reason(s) include: [_1]', '{{evt_desc}}') %]";
+    s.SUCCESS_HOLD_REQUEST =
+      "[% l('Hold successfully requested') %]";
+    s.FAILURE_HOLD_REQUEST =
+      "[% l('Hold not successfully requested') %]";
   }])
 </script>
 [% END %]
index f28a521..15fba04 100644 (file)
       </div>
       <div class="col-md-6"> {{user_name}} </div>
     </div>
+    <div class="row">
+      <div class="col-md-6">
+          <label>
+            <input type="checkbox" ng-model="hold_data.honor_user_settings"/>
+            [% l('Honor user preferences?') %]
+          </label>
+      </div>
+      <div></div>
+    </div>
     <div class="row pad-vert">
       <div class="col-md-6">
         <div class="input-group">
@@ -23,6 +32,7 @@
             <option value="C">[% l('Copy Hold') %]</option>
             <option value="R" selected>[% l('Recall Hold') %]</option>
             <option value="F">[% l('Force Hold') %]</option>
+            <option ng-show="hold_data.record_list" value="T">[% l('Title Hold') %]</option>
           </select>
         </div>
       </div>
   </div>
   <div class="modal-footer">
     <div class="row">
-      <div class="col-md-6">
+      <div ng-show="hold_data.copy_list && hold_data.hold_type != 'T'" class="col-md-6">
         [% l('Number of items: ') %] {{hold_data.copy_list.length}}
       </div>
+      <div ng-show="hold_data.record_list && hold_data.hold_type == 'T'" class="col-md-6">
+        [% l('Number of titles: ') %] {{hold_data.record_list.length}}
+      </div>
       <div class="col-md-6 pull-right">
         <input type="submit" class="btn btn-primary" value="[% l('OK') %]" ng-disabled="!hold_data.user"/>
         <button class="btn btn-warning" ng-click="cancel($event)">[% l('Cancel') %]</button>
index 785f250..441c125 100644 (file)
       "[% l('Item successfully modified') %]";
     s.ITEMS_SUCCESSFULLY_MODIFIED =
       "[% l('Item(s) successfully modified') %]";
+    s.SUCCESS_HOLD_REQUEST =
+      "[% l('Hold successfully requested') %]";
+    s.FAILURE_HOLD_REQUEST =
+      "[% l('Hold not successfully requested') %]";
 
   }])
 </script>
index f23b8a9..e5cc7f4 100644 (file)
@@ -514,10 +514,10 @@ function($scope,  $routeParams,  bucketSvc , egGridDataProvider,   egCore) {
 }])
 
 .controller('ViewCtrl',
-       ['$scope','$q','$routeParams','$timeout','$window','$uibModal','bucketSvc','egCore','egUser',
-        'egConfirmDialog',
-function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc , egCore , egUser ,
-         egConfirmDialog) {
+       ['$scope','$q','$routeParams','$timeout','$window','$uibModal','bucketSvc','egCore','egOrg','egUser',
+        'ngToast','egConfirmDialog',
+function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc , egCore , egOrg , egUser ,
+         ngToast , egConfirmDialog) {
 
     $scope.setTab('view');
     $scope.bucketId = $routeParams.id;
@@ -621,6 +621,13 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
                 return i.id;
             }
         );
+        var record_list = $scope.gridControls.selectedItems().map(
+            function (i) {
+                return i['call_number.record.id'];
+            }
+        ).filter(function(v,i,s){ // dedup
+            return s.indexOf(v) == i;
+        });
 
         if (copy_list.length == 0) return;
 
@@ -637,8 +644,11 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
                 $scope.hold_data = {
                     hold_type : 'C',
                     copy_list : copy_list,
+                    record_list : record_list,
                     pickup_lib: egCore.org.get(egCore.auth.user().ws_ou()),
-                    user      : egCore.auth.user().id()
+                    user      : egCore.auth.user().id(),
+                    honor_user_settings : 
+                        egCore.hatch.getLocalItem('eg.cat.request_items.honor_user_settings')
                 };
 
                 egUser.get( $scope.hold_data.user ).then(function(u) {
@@ -650,12 +660,24 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
 
                 $scope.user_name = '';
                 $scope.barcode = '';
+                function user_preferred_pickup_lib(u) {
+                    var pickup_lib = u.home_ou();
+                    angular.forEach(u.settings(), function (s) {
+                        if (s.name() == "opac.default_pickup_location") {
+                            pickup_lib = s.value();
+                        }
+                    });
+                    return egOrg.get(pickup_lib);
+                }
                 $scope.$watch('barcode', function (n) {
                     if (!$scope.first_user_fetch) {
                         egUser.getByBarcode(n).then(function(u) {
                             $scope.user = u;
                             $scope.user_name = egUser.format_name(u);
                             $scope.hold_data.user = u.id();
+                            if ($scope.hold_data.honor_user_settings) {
+                                $scope.hold_data.pickup_lib = user_preferred_pickup_lib(u);
+                            }
                         }, function() {
                             $scope.user = null;
                             $scope.user_name = '';
@@ -664,6 +686,14 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
                     }
                     $scope.first_user_fetch = false;
                 });
+                $scope.$watch('hold_data.honor_user_settings', function (n) {
+                    if (n && $scope.user) {
+                        $scope.hold_data.pickup_lib = user_preferred_pickup_lib($scope.user);
+                    } else {
+                        $scope.hold_data.pickup_lib = egCore.org.get(egCore.auth.user().ws_ou());
+                    }
+                    egCore.hatch.setLocalItem('eg.cat.request_items.honor_user_settings',n);
+                });
 
                 $scope.ok = function(h) {
                     var args = {
@@ -676,8 +706,25 @@ function($scope,  $q , $routeParams , $timeout , $window , $uibModal , bucketSvc
                     egCore.net.request(
                         'open-ils.circ',
                         'open-ils.circ.holds.test_and_create.batch.override',
-                        egCore.auth.token(), args, h.copy_list
-                    );
+                        egCore.auth.token(), args,
+                        h.hold_type == 'T' ? h.record_list : h.copy_list,
+                        { 'all' : 1, 'honor_user_settings' : h.honor_user_settings }
+                    ).then(function(r) {
+                        console.log('request result',r);
+                        if (isNaN(r.result)) {
+                            if (typeof r.result.desc != 'undefined') {
+                                ngToast.danger(r.result.desc);
+                            } else {
+                                if (typeof r.result.last_event != 'undefined') {
+                                    ngToast.danger(r.result.last_event.desc);
+                                } else {
+                                    ngToast.danger(egCore.strings.FAILURE_HOLD_REQUEST);
+                                }
+                            }
+                        } else {
+                            ngToast.success(egCore.strings.SUCCESS_HOLD_REQUEST);
+                        }
+                    });
 
                     $uibModalInstance.close();
                 }
index 5e418e7..fbf4181 100644 (file)
@@ -145,7 +145,7 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD
     }
 
     $scope.requestItems = function() {
-        itemSvc.requestItems([$scope.args.copyId]);
+        itemSvc.requestItems([$scope.args.copyId],[$scope.args.recordId]);
     }
 
     $scope.update_inventory = function() {
@@ -529,7 +529,8 @@ function($scope , $q , $window , $location , $timeout , egCore , egNet , egGridD
 
     $scope.requestItems = function() {
         var copy_list = gatherSelectedHoldingsIds();
-        itemSvc.requestItems(copy_list);
+        var record_list = gatherSelectedRecordIds();
+        itemSvc.requestItems(copy_list,record_list);
     }
 
     $scope.replaceBarcodes = function() {
index 6382852..51e7115 100644 (file)
@@ -4,8 +4,8 @@
 
 angular.module('egCoreMod')
     .factory('egItem',
-       ['egCore','egCirc','$uibModal','$q','$timeout','$window','egConfirmDialog','egAlertDialog',
-function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog , egAlertDialog ) {
+       ['egCore','egOrg','egCirc','$uibModal','$q','$timeout','$window','ngToast','egConfirmDialog','egAlertDialog',
+function(egCore , egOrg , egCirc , $uibModal , $q , $timeout , $window , ngToast , egConfirmDialog , egAlertDialog ) {
 
     var service = {
         copies : [], // copy barcode search results
@@ -418,8 +418,13 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
         });
     }
 
-    service.requestItems = function(copy_list) {
+    service.requestItems = function(copy_list,record_list) {
         if (copy_list.length == 0) return;
+        if (record_list) {
+            record_list = record_list.filter(function(v,i,s){ // dedup
+                return s.indexOf(v) == i;
+            });
+        }
 
         return $uibModal.open({
             templateUrl: './cat/catalog/t_request_items',
@@ -434,8 +439,11 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
                 $scope.hold_data = {
                     hold_type : 'C',
                     copy_list : copy_list,
+                    record_list : record_list,
                     pickup_lib: egCore.org.get(egCore.auth.user().ws_ou()),
-                    user      : egCore.auth.user().id()
+                    user      : egCore.auth.user().id(),
+                    honor_user_settings : 
+                        egCore.hatch.getLocalItem('eg.cat.request_items.honor_user_settings')
                 };
 
                 egUser.get( $scope.hold_data.user ).then(function(u) {
@@ -447,12 +455,24 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
 
                 $scope.user_name = '';
                 $scope.barcode = '';
+                function user_preferred_pickup_lib(u) {
+                    var pickup_lib = u.home_ou();
+                    angular.forEach(u.settings(), function (s) {
+                        if (s.name() == "opac.default_pickup_location") {
+                            pickup_lib = s.value();
+                        }
+                    });
+                    return egOrg.get(pickup_lib);
+                }
                 $scope.$watch('barcode', function (n) {
                     if (!$scope.first_user_fetch) {
                         egUser.getByBarcode(n).then(function(u) {
                             $scope.user = u;
                             $scope.user_name = egUser.format_name(u);
                             $scope.hold_data.user = u.id();
+                            if ($scope.hold_data.honor_user_settings) {
+                                $scope.hold_data.pickup_lib = user_preferred_pickup_lib(u);
+                            }
                         }, function() {
                             $scope.user = null;
                             $scope.user_name = '';
@@ -461,6 +481,14 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
                     }
                     $scope.first_user_fetch = false;
                 });
+                $scope.$watch('hold_data.honor_user_settings', function (n) {
+                    if (n && $scope.user) {
+                        $scope.hold_data.pickup_lib = user_preferred_pickup_lib($scope.user);
+                    } else {
+                        $scope.hold_data.pickup_lib = egCore.org.get(egCore.auth.user().ws_ou());
+                    }
+                    egCore.hatch.setLocalItem('eg.cat.request_items.honor_user_settings',n);
+                });
 
                 $scope.ok = function(h) {
                     var args = {
@@ -473,8 +501,25 @@ function(egCore , egCirc , $uibModal , $q , $timeout , $window , egConfirmDialog
                     egCore.net.request(
                         'open-ils.circ',
                         'open-ils.circ.holds.test_and_create.batch.override',
-                        egCore.auth.token(), args, h.copy_list
-                    );
+                        egCore.auth.token(), args,
+                        h.hold_type == 'T' ? h.record_list : h.copy_list,
+                        { 'all' : 1, 'honor_user_settings' : h.honor_user_settings }
+                    ).then(function(r) {
+                        console.log('request result',r);
+                        if (isNaN(r.result)) {
+                            if (typeof r.result.desc != 'undefined') {
+                                ngToast.danger(r.result.desc);
+                            } else {
+                                if (typeof r.result.last_event != 'undefined') {
+                                    ngToast.danger(r.result.last_event.desc);
+                                } else {
+                                    ngToast.danger(egCore.strings.FAILURE_HOLD_REQUEST);
+                                }
+                            }
+                        } else {
+                            ngToast.success(egCore.strings.SUCCESS_HOLD_REQUEST);
+                        }
+                    });
 
                     $uibModalInstance.close();
                 }