From e1d6c925dabbb87d8a866431dd270de3084118a0 Mon Sep 17 00:00:00 2001
From: David Gustafsson <david.gustafsson@ub.gu.se>
Date: Thu, 29 Sep 2022 17:18:01 +0200
Subject: [PATCH] Bug 31735: Add caching for relatively expensive patron
 attributes

---
 C4/Circulation.pm | 13 ++++++-------
 Koha/Patron.pm    | 31 ++++++++++++++++++++++++-------
 2 files changed, 30 insertions(+), 14 deletions(-)

diff --git a/C4/Circulation.pm b/C4/Circulation.pm
index f558b22ce4..eee69bb4a4 100644
--- a/C4/Circulation.pm
+++ b/C4/Circulation.pm
@@ -832,7 +832,7 @@ sub CanBookBeIssued {
         $issuingimpossible{DEBARRED} = 1;
     }
 
-    if ( $patron->is_expired ) {
+    if ( $patron->is_expired({ cache => 1 }) ) {
         $issuingimpossible{EXPIRED} = 1;
     }
 
@@ -918,7 +918,7 @@ sub CanBookBeIssued {
         else {
             $issuingimpossible{USERBLOCKEDWITHENDDATE} = $debarred_date;
         }
-    } elsif ( my $num_overdues = $patron->has_overdues ) {
+    } elsif ( my $num_overdues = $patron->has_overdues({ cache => 1 }) ) {
         ## patron has outstanding overdue loans
         if ( C4::Context->preference("OverduesBlockCirc") eq 'block'){
             $issuingimpossible{USERBLOCKEDOVERDUE} = $num_overdues;
@@ -1716,7 +1716,6 @@ sub AddIssue {
                 if ( $accumulate_charge > 0 ) {
                     AddIssuingCharge( $issue, $accumulate_charge, 'RENT_DAILY' );
                     $charge += $accumulate_charge;
-                    $item_unblessed->{charge} = $charge;
                 }
             }
 
@@ -2522,7 +2521,7 @@ sub MarkIssueReturned {
         # Remove any OVERDUES related debarment if the borrower has no overdues
         if ( C4::Context->preference('AutoRemoveOverduesRestrictions')
           && $patron->debarred
-          && !$patron->has_overdues
+          && !$patron->has_overdues({ cache => 1 })
           && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
         ) {
             DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
@@ -2879,7 +2878,7 @@ sub CanBookBeRenewed {
         my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
         my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
         my $restricted  = $patron->is_debarred;
-        my $hasoverdues = $patron->has_overdues;
+        my $hasoverdues = $patron->has_overdues({ cache => 1 });
 
         if ( $restricted and $restrictionblockrenewing ) {
             return ( 0, 'restriction');
@@ -3156,7 +3155,7 @@ sub AddRenewal {
         # Remove any OVERDUES related debarment if the borrower has no overdues
         if ( $patron
           && $patron->is_debarred
-          && ! $patron->has_overdues
+          && ! $patron->has_overdues({ cache => 1 })
           && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
         ) {
             DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
@@ -4371,7 +4370,7 @@ sub _CanBookBeAutoRenewed {
         }
     );
 
-    if ( $patron->is_expired && $patron->category->effective_BlockExpiredPatronOpacActions ) {
+    if ( $patron->is_expired({ cache => 1 }) && $patron->category->effective_BlockExpiredPatronOpacActions ) {
         return 'auto_account_expired';
     }
 
diff --git a/Koha/Patron.pm b/Koha/Patron.pm
index 8031257304..ef70760bc2 100644
--- a/Koha/Patron.pm
+++ b/Koha/Patron.pm
@@ -770,11 +770,19 @@ Returns 1 if the patron is expired or 0;
 =cut
 
 sub is_expired {
-    my ($self) = @_;
-    return 0 unless $self->dateexpiry;
-    return 0 if $self->dateexpiry =~ '^9999';
-    return 1 if dt_from_string( $self->dateexpiry ) < dt_from_string->truncate( to => 'day' );
-    return 0;
+    my ($self, $params) = @_;
+    $params //= {};
+    if ($params->{cache} && defined $self->{is_expired_cache}) {
+        return $self->{is_expired_cache};
+    }
+    my $is_expired =
+        $self->dateexpiry &&
+        $self->dateexpiry !~ '^9999' &&
+        dt_from_string( $self->dateexpiry ) < dt_from_string->truncate( to => 'day' );
+    if ($params->{cache}) {
+        $self->{is_expired_cache} = $is_expired;
+    }
+    return $is_expired;
 }
 
 =head3 password_expired
@@ -945,9 +953,18 @@ Returns the number of patron's overdues
 =cut
 
 sub has_overdues {
-    my ($self) = @_;
+    my ($self, $params) = @_;
+    $params //= {};
+
+    if ($params->{cache} && defined $self->{has_overdues_cache}) {
+        return $self->{has_overdues_cache};
+    }
     my $dtf = Koha::Database->new->schema->storage->datetime_parser;
-    return $self->_result->issues->search({ date_due => { '<' => $dtf->format_datetime( dt_from_string() ) } })->count;
+    my $has_overdues = $self->_result->issues->search({ date_due => { '<' => $dtf->format_datetime( dt_from_string() ) } })->count;
+    if ($params->{cache}) {
+        $self->{has_overdues_cache} = $has_overdues;
+    }
+    return $has_overdues;
 }
 
 =head3 track_login
-- 
2.35.1