log username of retargeter
authorLlewellyn Marshall <llewellyn.marshall@ncdcr.gov>
Wed, 18 Aug 2021 17:13:47 +0000 (13:13 -0400)
committerLlewellyn Marshall <llewellyn.marshall@ncdcr.gov>
Fri, 15 Jul 2022 19:39:10 +0000 (15:39 -0400)
add hold notes

better notes for hold update

(cherry picked from commit 5672d9d70fd7122073f7bbf6ba7415339cf42d10)

json format in hold reset hold notes, added cancel cause & cancel note

added API call for create hold reset note, it is used within the hold targeter when not called against a specific hold. added a hold reset note for better hold overwriting old hold.

Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Holds.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/HoldTargeter.pm
Open-ILS/src/perlmods/lib/OpenILS/Const.pm

index 92abe15..e29fba8 100644 (file)
@@ -15426,6 +15426,35 @@ SELECT  usr,
              <field reporter:label="Transaction Closed?" name="xact_closed" sr:suggest_filter="true" reporter:datatype="bool"/>
         </fields>
     </class>
+    
+       <class id="ahrrr" controller="open-ils.cstore" oils_obj:fieldmapper="action::hold_request_reset_reason" oils_persist:tablename="action.hold_request_reset_reason" reporter:label="Hold Request Reset Reason" oils_persist:field_safe="true">
+               <fields oils_persist:primary="id" oils_persist:sequence="action.hold_request_reset_reason_id_seq">
+                       <field name="id" reporter:selector="name" reporter:datatype="id" reporter:label="ID"/>
+                       <field name="name"  reporter:datatype="text" oils_persist:i18n="true" reporter:label="Name"/>
+            <field name="manual" reporter:datatype="bool" reporter:label="Manual"/>
+               </fields>
+       </class>
+
+       <class id="ahrrre" controller="open-ils.cstore" oils_obj:fieldmapper="action::hold_request_reset_reason_entry" oils_persist:tablename="action.hold_request_reset_reason_entry" reporter:label="Hold Request Reset Reason Entry" oils_persist:field_safe="true">
+               <fields oils_persist:primary="id" oils_persist:sequence="action.hold_request_reset_reason_entry_id_seq">
+                       <field name="id" reporter:datatype="id" reporter:label="ID"/>
+            <field name="hold" reporter:label="ID" reporter:datatype="link"/>
+                       <field name="reset_reason" reporter:label="ID" reporter:datatype="link"/>
+            <field name="reset_time" reporter:datatype="timestamp" reporter:label="Reset Date/Time"/>
+                       <field name="note" reporter:datatype="text" oils_persist:i18n="true" reporter:label="Note"/>
+            <field name="requestor" reporter:label="Resetting User" reporter:datatype="link"/>
+            <field name="requestor_workstation" reporter:label="Resetting User Workstation" reporter:datatype="link"/>
+            <field name="previous_copy" reporter:label="Previous Copy" reporter:datatype="link"/>
+               </fields>
+               <links>
+            <link field="hold" reltype="has_a" key="id" map="" class="ahr"/>        
+            <link field="reset_reason" reltype="has_a" key="id" map="" class="ahrrr"/>        
+            <link field="requestor" reltype="might_have" key="id" map="" class="au"/>    
+            <link field="requestor_workstation" reltype="might_have" key="id" map="" class="aws"/>            
+            <link field="previous_copy" reltype="might_have" key="id" map="" class="acp"/>        
+        </links>
+       </class>
+
 
        <!-- ********************************************************************************************************************* -->
 </IDL>
index 0e417c5..29dec09 100644 (file)
@@ -1875,7 +1875,8 @@ sub handle_checkout_holds {
         $hold->clear_shelf_time;
         $hold->clear_shelf_expire_time;
         $hold->clear_current_shelf_lib;
-
+        $U->simplereq('open-ils.circ', 
+            'open-ils.circ.hold_reset_reason_entry.create',$e->authtoken,$hold->id,OILS_HOLD_CHECK_OUT,"Checked out to patron #".$patron->id);
         return $self->bail_on_event($e->event)
             unless $e->update_action_hold_request($hold);
 
@@ -2650,6 +2651,8 @@ sub checkin_retarget {
                 next if ($_->{hold_type} eq 'P');
             }
             # So much for easy stuff, attempt a retarget!
+            $U->simplereq('open-ils.circ', 
+            'open-ils.circ.hold_reset_reason_entry.create',$self->editor->authtoken, $_->{id},OILS_HOLD_BETTER_HOLD);
             my $tresult = $U->simplereq(
                 'open-ils.hold-targeter',
                 'open-ils.hold-targeter.target', 
@@ -3302,7 +3305,9 @@ sub attempt_checkin_hold_capture {
     $hold->clear_expire_time; 
     $hold->clear_cancel_time;
     $hold->clear_prev_check_time unless $hold->prev_check_time;
-
+    
+    $U->simplereq('open-ils.circ', 
+    'open-ils.circ.hold_reset_reason_entry.create',$self->editor->authtoken, $hold->id, OILS_HOLD_CHECK_IN);
     $self->bail_on_events($self->editor->event)
         unless $self->editor->update_action_hold_request($hold);
     $self->hold($hold);
@@ -3446,6 +3451,8 @@ sub retarget_holds {
     my $self = shift;
     $logger->info("circulator: retargeting holds @{$self->retarget} after opportunistic capture");
     my $ses = OpenSRF::AppSession->create('open-ils.hold-targeter');
+    my $cses = OpenSRF::AppSession->create('open-ils.circ');            
+    $cses->request('open-ils.circ.hold_reset_reason_entry.create',$self->editor->authtoken, $self->retarget,OILS_HOLD_BETTER_HOLD);
     $ses->request('open-ils.hold-targeter.target', {hold => $self->retarget});
     # no reason to wait for the return value
     return;
index a11d0ab..0dd2ad4 100644 (file)
@@ -1024,13 +1024,12 @@ sub uncancel_hold {
     $hold->clear_prev_check_time;
     $hold->clear_shelf_expire_time;
     $hold->clear_current_shelf_lib;
-
+    _create_reset_reason_entry($e,$hold,OILS_HOLD_UNCANCELED);
     $e->update_action_hold_request($hold) or return $e->die_event;
     $e->commit;
-
+        
     $U->simplereq('open-ils.hold-targeter',
         'open-ils.hold-targeter.target', {hold => $hold_id});
-
     return 1;
 }
 
@@ -1058,11 +1057,13 @@ sub cancel_hold {
 
     my $e = new_editor(authtoken=>$auth, xact=>1);
     return $e->die_event unless $e->checkauth;
-
+    
+    my $req = $e->requestor->id;
+    
     my $hold = $e->retrieve_action_hold_request($holdid)
         or return $e->die_event;
 
-    if( $e->requestor->id ne $hold->usr ) {
+    if( $req ne $hold->usr ) {
         return $e->die_event unless $e->allowed('CANCEL_HOLDS');
     }
 
@@ -1106,6 +1107,21 @@ sub cancel_hold {
     $hold->cancel_time('now');
     $hold->cancel_cause($cause);
     $hold->cancel_note($note);
+       my $note_body = "";
+       if($cause){
+               my $cancel_reason = "ID $cause";
+               my $cancel_cause = $e->retrieve_action_hold_request_cancel_cause($cause);
+               if($cancel_cause){
+                       $cancel_reason = $cancel_cause->label;
+               }               
+               $note_body .= "Cancel Cause: $cancel_reason";           
+       }
+       else{
+               $note_body .= "Cancel reason unknown";
+       }
+       $note_body .= "," unless $note_body eq "" || $note eq "";
+       $note_body .= " Cancel Note: \"$note\"" unless $note eq "";
+    _create_reset_reason_entry($e,$hold,OILS_HOLD_CANCELED,$note_body);
     $e->update_action_hold_request($hold)
         or return $e->die_event;
 
@@ -1206,6 +1222,8 @@ sub update_hold_impl {
     my($self, $e, $hold, $values) = @_;
     my $hold_status;
     my $need_retarget = 0;
+    my $reset_reason = OILS_HOLD_UPDATED;
+    my $note_body = "";
 
     unless($hold) {
         $hold = $e->retrieve_action_hold_request($values->{id})
@@ -1217,9 +1235,13 @@ sub update_hold_impl {
                 if (defined $values->{$k} && defined $hold->$k() && $values->{$k} ne $hold->$k()) {
                     # Value changed? RETARGET!
                     $need_retarget = 1;
+                    $reset_reason = OILS_HOLD_UPDATED;
+                    $note_body .= "$k value changed."
                 } elsif (defined $hold->$k() != defined $values->{$k}) {
                     # Value being set or cleared? RETARGET!
                     $need_retarget = 1;
+                    $reset_reason = OILS_HOLD_UPDATED;
+                    $note_body .= "$k value cleared."
                 }
             }
             if (defined $values->{$k}) {
@@ -1325,9 +1347,10 @@ sub update_hold_impl {
               $hold->clear_current_copy;
         }
     }
-
+   
     if($U->is_true($hold->frozen)) {
         $logger->info("clearing current_copy and check_time for frozen hold ".$hold->id);
+               _create_reset_reason_entry($e,$hold,OILS_HOLD_FROZEN,$note_body) unless $U->is_true($orig_hold->frozen);
         $hold->clear_current_copy;
         $hold->clear_prev_check_time;
         # Clear expire_time to prevent frozen holds from expiring.
@@ -1349,10 +1372,13 @@ sub update_hold_impl {
     }
 
     $e->update_action_hold_request($hold) or return $e->die_event;
+    _create_reset_reason_entry($e,$hold,$reset_reason,$note_body) if $need_retarget;    
     $e->commit;
-
+    
     if(!$U->is_true($hold->frozen) && $U->is_true($orig_hold->frozen)) {
         $logger->info("Running targeter on activated hold ".$hold->id);
+        $U->simplereq('open-ils.circ', 
+            'open-ils.circ.hold_reset_reason_entry.create',$e->authtoken,$hold->id,OILS_HOLD_UNFROZEN);
         $U->simplereq('open-ils.hold-targeter', 
             'open-ils.hold-targeter.target', {hold => $hold->id});
     }
@@ -1360,11 +1386,13 @@ sub update_hold_impl {
     # a change to mint-condition changes the set of potential copies, so retarget the hold;
     if($U->is_true($hold->mint_condition) and !$U->is_true($orig_hold->mint_condition)) {
         _reset_hold($self, $e->requestor, $hold)
-    } elsif($need_retarget && !defined $hold->capture_time()) { # If needed, retarget the hold due to changes
+    } elsif($need_retarget && !defined $hold->capture_time()) { # If needed, retarget the hold due to changes        
         $U->simplereq('open-ils.hold-targeter', 
             'open-ils.hold-targeter.target', {hold => $hold->id});
     }
-
+    
+   
+    
     return $hold->id;
 }
 
@@ -1450,6 +1478,7 @@ sub update_hold_if_frozen {
     } else {
         if($U->is_true($orig_hold->frozen)) {
             $logger->info("Running targeter on activated hold ".$hold->id);
+            _create_reset_reason_entry($e,$hold,OILS_HOLD_UNFROZEN,"Running targeter on activated hold");
             $U->simplereq('open-ils.hold-targeter', 
                 'open-ils.hold-targeter.target', {hold => $hold->id});
         }
@@ -2209,6 +2238,51 @@ sub reset_hold {
     return 1;
 }
 
+__PACKAGE__->register_method(
+    method   => 'create_reset_reason_entry',
+    api_name => 'open-ils.circ.hold_reset_reason_entry.create'
+);
+
+sub create_reset_reason_entry
+{
+    my($self, $conn, $auth, $hold, $reset_reason, $note) = @_;
+    my $e = new_editor(authtoken => $auth, xact => 1);
+       #checkauth to set the requestor (if available)
+       $e->checkauth;
+    my @holds;
+    if(ref $hold eq 'ARRAY'){
+        @holds = @{$hold};
+    }
+    else{
+        @holds = ($hold);
+    }
+    for my $holdid (@holds){
+        my ($hold, $evt) = $U->fetch_hold($holdid);
+        return $evt if $evt;   
+        _create_reset_reason_entry($e, $hold, $reset_reason, $note);
+    }
+    $e->commit;
+    return 1;
+}
+
+sub _create_reset_reason_entry
+{
+    my($e, $hold, $reset_reason,$note) = @_;
+    my $ts = DateTime->now;
+    my $entry = Fieldmapper::action::hold_request_reset_reason_entry->new; 
+    $logger->info("Creating reset reason entry for hold #" . $hold->id);    
+    my $last_copy = $hold->current_copy;
+    $entry->hold($hold->id);
+    $entry->reset_reason($reset_reason);
+    $entry->reset_time('now');
+    $entry->requestor($e->requestor->id) if defined $e->requestor;
+    $entry->requestor_workstation($e->requestor->wsid)  if defined $e->requestor;
+    $entry->previous_copy($last_copy);
+    $entry->note($note);
+    $e->create_action_hold_request_reset_reason_entry($entry) or return $e->die_event;
+    return 1;
+}
+
 
 __PACKAGE__->register_method(
     method   => 'reset_hold_batch',
@@ -2239,11 +2313,9 @@ sub _reset_hold {
     my ($self, $reqr, $hold) = @_;
 
     my $e = new_editor(xact =>1, requestor => $reqr);
-
-    $logger->info("reseting hold ".$hold->id);
-
     my $hid = $hold->id;
-
+    $logger->info("reseting hold ".$hid." requestor was ".$reqr->usrname." (ID ".$reqr->id.")");
+    my $note_body = "";
     if( $hold->capture_time and $hold->current_copy ) {
 
         my $copy = $e->retrieve_asset_copy($hold->current_copy)
@@ -2251,6 +2323,7 @@ sub _reset_hold {
 
         if( $copy->status == OILS_COPY_STATUS_ON_HOLDS_SHELF ) {
             $logger->info("setting copy to status 'reshelving' on hold retarget");
+            $note_body.=" set copy to status 'reshelving'.";
             $copy->status(OILS_COPY_STATUS_RESHELVING);
             $copy->editor($e->requestor->id);
             $copy->edit_date('now');
@@ -2267,6 +2340,7 @@ sub _reset_hold {
                     $logger->info("Aborting transit [$transid] on hold [$hid] reset...");
                     my $evt = OpenILS::Application::Circ::Transit::__abort_transit($e, $trans, $copy, 1, 1);
                     $logger->info("Transit abort completed with result $evt");
+                    $note_body.=" Transit abort completed with result $evt.";
                     unless ("$evt" eq 1) {
                         $e->rollback;
                         return $evt;
@@ -2276,6 +2350,7 @@ sub _reset_hold {
         }
     }
 
+    _create_reset_reason_entry($e,$hold,OILS_HOLD_MANUAL_RESET,$note_body);
     $hold->clear_capture_time;
     $hold->clear_current_copy;
     $hold->clear_shelf_time;
@@ -2283,8 +2358,9 @@ sub _reset_hold {
     $hold->clear_current_shelf_lib;
 
     $e->update_action_hold_request($hold) or return $e->die_event;
+   
     $e->commit;
-
+    
     $U->simplereq('open-ils.hold-targeter', 
         'open-ils.hold-targeter.target', {hold => $hold->id});
 
@@ -3495,6 +3571,7 @@ sub find_nearest_permitted_hold {
         next if $old_hold->id eq $best_hold->id; # don't re-target the hold we want
         $logger->info("circulator: clearing current_copy and prev_check_time on hold ".
             $old_hold->id." after a better hold [".$best_hold->id."] was found");
+        _create_reset_reason_entry($editor,$old_hold,OILS_HOLD_BETTER_HOLD,"Old hold was reset. Last check time was ".$old_hold->prev_check_time.". a better hold [".$best_hold->id."] was found");
         $old_hold->clear_current_copy;
         $old_hold->clear_prev_check_time;
         $editor->update_action_hold_request($old_hold)
index afca2fc..7b54b39 100644 (file)
@@ -4,6 +4,7 @@ use warnings;
 use OpenILS::Application;
 use base qw/OpenILS::Application/;
 use OpenILS::Utils::HoldTargeter;
+use OpenILS::Const qw/:const/;
 use OpenSRF::Utils::Logger qw(:logger);
 
 __PACKAGE__->register_method(
@@ -80,13 +81,24 @@ sub hold_targeter {
     my $total = scalar(@hold_ids);
 
     $logger->info("targeter processing $total holds");
-
+    my $hold_ses = create OpenSRF::AppSession("open-ils.circ");
+    
     for my $hold_id (@hold_ids) {
         $count++;
 
         my $single = 
             OpenILS::Utils::HoldTargeter::Single->new(parent => $targeter);
 
+        # If targeter is issued without a hold
+        # it will retarget all of the holds that need it
+        # so we shoot off a RRE for all them.                  
+               $hold_ses->request(
+        "open-ils.circ.hold_reset_reason_entry.create",
+               $single->editor()->authtoken,
+        $hold_id,
+        OILS_HOLD_TIMED_OUT) 
+        unless defined $args->{hold};
+
         # Don't let an explosion on a single hold stop processing
         eval { $single->target($hold_id) };
 
@@ -105,9 +117,10 @@ sub hold_targeter {
             $client->respond($res);
 
             $logger->info("targeted $count of $total holds");
-        }
+        }        
     }
-
+    $hold_ses->disconnect;
+    
     return undef;
 }
 
index 0ff4880..093f1a6 100644 (file)
@@ -133,6 +133,19 @@ econst OILS_PENALTY_INVALID_PATRON_ADDRESS => 29;
 
 econst OILS_BILLING_TYPE_NOTIFICATION_FEE => 9;
 
+# ---------------------------------------------------------------------
+# Hold reset reasons
+# ---------------------------------------------------------------------
+econst OILS_HOLD_TIMED_OUT => 1;
+econst OILS_HOLD_MANUAL_RESET => 2;
+econst OILS_HOLD_BETTER_HOLD => 3;
+econst OILS_HOLD_FROZEN => 4;
+econst OILS_HOLD_UNFROZEN => 5;
+econst OILS_HOLD_CANCELED => 6;
+econst OILS_HOLD_UNCANCELED => 7;
+econst OILS_HOLD_UPDATED => 8;
+econst OILS_HOLD_CHECK_OUT => 9;
+econst OILS_HOLD_CHECK_IN => 10;
 
 # ---------------------------------------------------------------------
 # Non Evergreen-specific constants