LP##1661688 - Want easy way to clear a hold when picked up by other patron. user/dpearl/hold_checkout
authorDan Pearl <dpearl@cwmars.org>
Wed, 1 Mar 2017 19:43:58 +0000 (14:43 -0500)
committerDan Pearl <dpearl@cwmars.org>
Wed, 1 Mar 2017 19:49:28 +0000 (14:49 -0500)
This common action was handled previously as
    1) item it scanned
    2) force override was selected
    3) librarian cancels original hold

This feature provides the option to cancel the hold in step #2.

Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.hold_checkout.sql [new file with mode: 0644]
Open-ILS/src/templates/staff/circ/share/t_event_override_dialog.tt2
Open-ILS/web/js/ui/default/staff/circ/services/circ.js
docs/RELEASE_NOTES_NEXT/Circulation/alternate_patron_hold_pickup.adoc [new file with mode: 0644]

index 0dcc782..4c50778 100644 (file)
@@ -855,7 +855,12 @@ sub check_captured_holds {
                 cancel_time         => undef, 
                 fulfillment_time    => undef 
             },
-            { limit => 1 }
+            { limit => 1,
+              flesh => 2,
+              flesh_fields => { ahr => ['usr'],
+                                au => ['family_name', 'first_given_name']
+             }
+            }
         ]
     )->[0];
 
@@ -864,25 +869,19 @@ sub check_captured_holds {
         return undef;
     }
 
-    /* Get fleshed version of hold so we can grab name of requestor */
-    $hold = $self->editor->retrieve_action_hold_request(
-        [
-            $hold->id,
-            {
-                flesh => 1,
-                flesh_fields => { ahr => [ 'usr' ] }
-            }
-        ]
-    
     $logger->info("circulator: this copy is needed by a different patron to fulfill a hold");
 
-    my $user = $hold->usr;
+    my $payload;
+    my $holdau = $hold->usr;
 
+    if ($holdau) {
+       $payload->{patron_name} = $holdau->first_given_name . ' ' . $holdau->family_name;
+    } else {
+       $payload->{patron_name} = "???";
+    }
+    $payload->{hold_id}     = $hold->id;
     $self->push_events(OpenILS::Event->new('ITEM_ON_HOLDS_SHELF',
-           { payload => { hold => $hold->id,
-                          patron_name = $user->first_given_name. ' '.
-                                        $user->family_name
-           ));
+           payload => $payload));
 }
 
 
index ce5e03f..e0b6754 100644 (file)
@@ -16503,6 +16503,29 @@ INSERT INTO config.org_unit_setting_type
 INSERT INTO config.org_unit_setting_type
 ( name, grp, label, description, datatype )
 VALUES
+       ('circ.clear_hold_on_checkout',
+        'circ',
+       oils_i18n_gettext('circ.clear_hold_on_checkout',
+               'Clear hold when other patron checks out item',
+               'coust', 'label'),
+        oils_i18n_gettext('circ.clear_hold_on_checkout',
+                 'When patron A checks out item on hold for patron B, ' ||
+                'automatically clear the hold for patron B. This is ' ||
+                 'desirable when checking out item for family members',
+               'coust', 'description'),
+       'bool');
+
+INSERT INTO actor.org_unit_setting (
+    org_unit, name, value
+) VALUES (
+    (SELECT id FROM actor.org_unit WHERE parent_ou IS NULL),
+    'circ.clear_hold_on_checkout',
+    'true'
+);
+
+INSERT INTO config.org_unit_setting_type
+( name, grp, label, description, datatype )
+VALUES
 ('circ.patron_search.diacritic_insensitive',
  'circ',
  oils_i18n_gettext('circ.patron_search.diacritic_insensitive',
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.hold_checkout.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.hold_checkout.sql
new file mode 100644 (file)
index 0000000..a425ef3
--- /dev/null
@@ -0,0 +1,29 @@
+BEGIN;
+
+SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+INSERT INTO config.org_unit_setting_type
+( name, grp, label, description, datatype )
+VALUES
+       ('circ.hold.clear_hold_on_checkout',
+        'circ',
+       oils_i18n_gettext('circ.hold.clear_hold_on_checkout',
+               'Clear hold when other patron checks out item',
+               'coust', 'label'),
+        oils_i18n_gettext('circ.hold.clear_hold_on_checkout',
+                 'When patron A checks out item on hold for patron B, ' ||
+                'automatically clear the hold for patron B. This is ' ||
+                 'desirable when checking out item for family members',
+               'coust', 'description'),
+       'bool');
+
+INSERT INTO actor.org_unit_setting (
+    org_unit, name, value
+) VALUES (
+    (SELECT id FROM actor.org_unit WHERE parent_ou IS NULL),
+    'circ.hold.clear_hold_on_checkout',
+    'true'
+);
+
+COMMIT;
+
index 7308145..0adeb11 100644 (file)
         <div class="panel-body">
           <div ng-if="copy_barcode" class="strong-text-2">{{copy_barcode}}</div>
           {{evt.desc}}
+          <div ng-if="evt.textcode == 'ITEM_ON_HOLDS_SHELF'">
+             [% l('for ') %] {{patronName}}.
+            <div>
+               <label><input type="checkbox" ng-model="formdata.clearHold"/> 
+               [% l('Cancel this hold upon checkout?') %]</label>
+           </div>
+
+         </div>
         </div>
       </div>
     </div>
index c32cf6f..d5513b6 100644 (file)
@@ -653,12 +653,53 @@ function($uibModal , $q , egCore , egAlertDialog , egConfirmDialog,
                 ['$scope', '$uibModalInstance', 
                 function($scope, $uibModalInstance) {
                 $scope.events = evt;
+
+                // Find the event, if any, that is for ITEM_ON_HOLDS_SHELF
+                //  and grab the patron name of the owner. 
+                $scope.holdEvent = evt.filter(
+                    function(e) {
+                        return e.textcode === 'ITEM_ON_HOLDS_SHELF'
+                     }
+                );
+
+                if ($scope.holdEvent) {
+                  // Ensure we have a scalar here 
+                   if (angular.isArray($scope.holdEvent)) {
+                       $scope.holdEvent = $scope.holdEvent[0];
+                   }
+
+                   $scope.patronName = $scope.holdEvent.payload.patron_name;
+                   $scope.holdID = $scope.holdEvent.payload.hold_id;
+                }
+
                 $scope.auto_override =
                     evt.filter(function(e){
                         return service.checkout_auto_override_after_first.indexOf(evt.textcode) > -1;
                     }).length > 0;
                 $scope.copy_barcode = params.copy_barcode; // may be null
-                $scope.ok = function() { $uibModalInstance.close() }
+
+                // Implementation note: Why not use a primitive here? It
+                // doesn't work.  See: 
+                // http://stackoverflow.com/questions/18642371/checkbox-not-binding-to-scope-in-angularjs
+                $scope.formdata = {clearHold : service.clearHold};
+
+                $scope.ok = function() { 
+                        $uibModalInstance.close();
+
+                        // Handle the cancellation of the assciated hold here
+                        if ($scope.formdata.clearHold && $scope.holdID) {
+                            $scope.args = {
+                            cancel_reason : 5,
+                                note: 'Item checked out by other patron'
+                           };
+                            egCore.net.request(
+                                'open-ils.circ', 'open-ils.circ.hold.cancel',
+                                egCore.auth.token(), $scope.holdID,
+                                $scope.args.cancel_reason,
+                                $scope.args.note);
+                        }
+               }
+
                 $scope.cancel = function ($event) { 
                     $uibModalInstance.dismiss();
                     $event.preventDefault();
diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/alternate_patron_hold_pickup.adoc b/docs/RELEASE_NOTES_NEXT/Circulation/alternate_patron_hold_pickup.adoc
new file mode 100644 (file)
index 0000000..d3ef60e
--- /dev/null
@@ -0,0 +1,20 @@
+Alternate Patron Hold Pickup
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+This feature adds a bit of convenience to a common task: checking out
+an item on hold to another patron (typically a family member or helper).
+
+When you checkout the item, you will get a pop-up window with warnings associated
+with this item.  The "ITEM_ON_HOLDS_SHELF" message is now expanded to
+
+ * Let you know the name of the person who had placed the hold.
+ * Give you the option (in the form of a checkbox) of cancelling the
+   hold placed by the above-named patron.  (Checked = Cancel the hold;
+   Uncheked = Leave the hold in place)
+
+The initial value of the checkbox is derived from the circ.clear_hold_on_checkout
+organizational setting.  This is found under Administration -- Server Administration -- Org Unit Setting Types
+
+If the operator has CANCEL_HOLD privilege, then if the checkbox is checked and the checkout is allowed to proceed,
+the hold will be cancelled with a note that the item was checked out to another patrron.
+
+This feature is available in the browser-based staff client.