incorporate reset entries into the retargeter so that manually retargeted copies... user/lew/retargeter_reset_entry_adjustments
authorLlewellyn Marshall <llewellyn.marshall@ncdcr.gov>
Fri, 24 Mar 2023 16:07:31 +0000 (12:07 -0400)
committerLlewellyn Marshall <llewellyn.marshall@ncdcr.gov>
Fri, 24 Mar 2023 16:07:31 +0000 (12:07 -0400)
Open-ILS/src/perlmods/lib/OpenILS/Utils/HoldTargeter.pm
Open-ILS/src/sql/Pg/upgrade/xxxx.hold_reset_reasons.sql

index 31b8852..c3a185c 100644 (file)
@@ -265,6 +265,7 @@ use DateTime;
 use OpenSRF::AppSession;
 use OpenILS::Utils::DateTime qw/:datetime/;
 use OpenSRF::Utils::Logger qw(:logger);
+use OpenILS::Const qw/:const/;
 use OpenILS::Application::AppUtils;
 use OpenILS::Utils::CStoreEditor qw/:funcs/;
 
@@ -367,6 +368,20 @@ sub result {
     };
 }
 
+sub retarget_previous_targets_interval {
+    my ($self) = @_;
+    if (!defined($self->{retarget_previous_targets_interval}) || !$self->{retarget_previous_targets_interval}) { 
+        # See if we have a global flag value for the interval
+        my $rri = $self->editor->search_config_global_flag({
+            name => 'circ.holds.retarget_previous_targets_interval',
+            enabled => 't'
+        })->[0];
+        # If no flag is present, default to 0 so feature is disabled
+        $self->{retarget_previous_targets_interval} = $rri ? $rri->value : 0;
+    }    
+    return $self->{retarget_previous_targets_interval};
+}
+
 # List of potential copies in the form of slim hashes.  This list
 # evolves as copies are filtered as they are deemed non-targetable.
 sub copies {
@@ -735,6 +750,42 @@ sub get_copy_circ_libs {
 sub compile_weighted_proximity_map {
     my $self = shift;
 
+    my %copy_reset_map = {}; 
+    my %copy_timeout_map = {}; 
+    eval{
+        my $pt_interval = $self->retarget_previous_targets_interval();
+        if($pt_interval){
+            my $reset_cutoff_time = DateTime->now(time_zone => 'local')
+                    ->subtract(days => $pt_interval);
+
+            # Collect reset reason info and previous copies.
+            # for this hold within the last time interval
+            my $reset_entries = $self->editor->json_query({
+                select => {ahrrre => ['reset_reason','reset_time','previous_copy']},
+                from => 'ahrrre',
+                where => {
+                    hold => $self->hold_id, 
+                    previous_copy => {'!=' => undef},
+                    reset_time => {'>=' => $reset_cutoff_time->strftime('%F %T%z')},
+                    reset_reason => [OILS_HOLD_TIMED_OUT, OILS_HOLD_MANUAL_RESET]
+                }
+            });
+         
+            # count how many times each copy 
+            # was reset or timed out
+            for(@$reset_entries){
+                my $pc = $_->{previous_copy};
+                my $rr = $_->{reset_reason};
+                if($rr == OILS_HOLD_MANUAL_RESET){
+                    $copy_reset_map{$pc} += 1;
+                }
+                elsif($rr == OILS_HOLD_TIMED_OUT){
+                    $copy_timeout_map{$pc} += 1;
+                }
+            }
+        }
+    };
+    
     # Collect copy proximity info (generated via DB trigger)
     # from our newly create copy maps.
     my $hold_copy_maps = $self->editor->json_query({
@@ -745,7 +796,14 @@ sub compile_weighted_proximity_map {
 
     my %copy_prox_map =
         map {$_->{target_copy} => $_->{proximity}} @$hold_copy_maps;
-
+        
+    # calculate the maximum proximity to make adjustments
+    my $max_prox = 0;
+    foreach(@$hold_copy_maps){
+        my $mp = $_->{proximity} + 1;
+        $max_prox = $mp unless $max_prox >= $mp;
+    }
+    
     # Pre-fetch the org setting value for all circ libs so that
     # later calls can reference the cached value.
     $self->parent->precache_batch_ou_settings($self->get_copy_circ_libs, 
@@ -753,7 +811,18 @@ sub compile_weighted_proximity_map {
 
     my %prox_map;
     for my $copy_hash (@{$self->copies}) {
-        my $prox = $copy_prox_map{$copy_hash->{id}};
+        my $copy_id = $copy_hash->{id};
+        my $prox = $copy_prox_map{$copy_id};
+        my $reset_count = $copy_reset_map{$copy_id};
+        my $timeout_count = $copy_timeout_map{$copy_id};
+
+        # make adjustments to proximity based on reset reason.
+        # manual resets get +max_prox each time
+        # this moves them to the end of the hold copy map.
+        # timeout resets only add one level of proximity 
+        # so that copies can be inspected again later.
+        $prox += (($reset_count || 0) * $max_prox) + (($timeout_count || 0));
+        
         $copy_hash->{proximity} = $prox;
         $prox_map{$prox} ||= [];
 
index 39ab13a..15e2f3b 100644 (file)
@@ -66,3 +66,15 @@ INSERT INTO config.global_flag (name, label, enabled)
         ),
         TRUE
     );
+
+INSERT INTO config.global_flag (name, label, enabled)
+    VALUES (
+        'circ.holds.retarget_previous_targets_interval',
+        oils_i18n_gettext(
+            'circ.holds.retarget_previous_targets_interval',
+            'Hold targeter will create proximity adjustments for previously targeted copies within this time interval (in days).',
+            'cgf',
+            'label'
+        ),
+        TRUE
+    );