From 9447698f9d42b027b5a1b549f7c78a95f050d73b Mon Sep 17 00:00:00 2001
From: Nick Clemens <nick@bywatersolutions.com>
Date: Tue, 26 Sep 2023 15:03:45 +0000
Subject: [PATCH] Bug 34924: Add 'auto_renew_final' and 'auto_unseen_final'
 return to CanBookBeRenewed

There is a desire for auto_renewals to treat the final renewal differently. We would like to notify the patron of the final renewal - but not again when the next renewal fails. This patch adds the new return value and tests.

To test:
prove -v t/db_dependent/Circulation.t
---
 C4/Circulation.pm            | 12 +++++--
 t/db_dependent/Circulation.t | 69 ++++++++++++++++++++++++++++++++++--
 2 files changed, 77 insertions(+), 4 deletions(-)

diff --git a/C4/Circulation.pm b/C4/Circulation.pm
index 4c8b51e3c7..5764f7d223 100644
--- a/C4/Circulation.pm
+++ b/C4/Circulation.pm
@@ -2953,7 +2953,10 @@ sub CanBookBeRenewed {
     return ( 0, 'item_issued_to_other_patron') if $issue->borrowernumber != $patron->borrowernumber;
     return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
 
-       # override_limit will override anything else except on_reserve
+    my $final_renewal        = 0;
+    my $final_unseen_renewal = 0;
+
+    # override_limit will override anything else except on_reserve
     unless ( $override_limit ){
         my $branchcode = _GetCircControlBranch( $item, $patron );
         my $issuing_rule = Koha::CirculationRules->get_effective_rules(
@@ -2977,6 +2980,10 @@ sub CanBookBeRenewed {
             looks_like_number($issuing_rule->{unseen_renewals_allowed}) &&
             $issuing_rule->{unseen_renewals_allowed} <= $issue->unseen_renewals;
 
+        $final_renewal        = $issuing_rule->{renewalsallowed} == ( $issue->renewals_count + 1 ) ? 1 : 0;
+        $final_unseen_renewal = ( C4::Context->preference('UnseenRenewals')
+                && $issuing_rule->{unseen_renewals_allowed} == ( $issue->unseen_renewals + 1 ) ) ? 1 : 0;
+
         my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
         my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
         my $restricted  = $patron->is_debarred;
@@ -3077,7 +3084,8 @@ sub CanBookBeRenewed {
         return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
     }
 
-    return ( 0, "auto_renew" ) if $auto_renew eq "ok" && !$override_limit; # 0 if auto-renewal should not succeed
+    my $auto_renew_code = $final_renewal ? 'auto_renew_final' : $final_unseen_renewal ? 'auto_unseen_final' : 'auto_renew';
+    return ( 0, $auto_renew_code ) if $auto_renew eq "ok" && !$override_limit;    # 0 if auto-renewal should not succeed
 
     return ( 1, undef );
 }
diff --git a/t/db_dependent/Circulation.t b/t/db_dependent/Circulation.t
index babbc0384a..93229c2de9 100755
--- a/t/db_dependent/Circulation.t
+++ b/t/db_dependent/Circulation.t
@@ -430,7 +430,7 @@ subtest "GetIssuingCharges tests" => sub {
 
 my ( $reused_itemnumber_1, $reused_itemnumber_2 );
 subtest "CanBookBeRenewed tests" => sub {
-    plan tests => 104;
+    plan tests => 105;
 
     C4::Context->set_preference('ItemsDeniedRenewal','');
     # Generate test biblio
@@ -1345,8 +1345,72 @@ subtest "CanBookBeRenewed tests" => sub {
         );
 
     };
-    # Too many renewals
 
+    subtest "auto_renew_final" => sub {
+        plan tests => 6;
+        my $item_to_auto_renew = $builder->build_sample_item();
+        Koha::CirculationRules->set_rules(
+            {
+                categorycode => undef,
+                branchcode   => undef,
+                itemtype     => $item_to_auto_renew->itype,
+                rules        => {
+                    norenewalbefore => undef,
+                    renewalsallowed => 1,
+                }
+            }
+        );
+
+        my $ten_days_before = dt_from_string->add( days => -10 );
+        my $ten_days_ahead  = dt_from_string->add( days => 10 );
+        my $issue           = AddIssue(
+            $renewing_borrower_obj, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before,
+            undef, { auto_renew => 1 }
+        );
+        $issue->renewals_count(0)->store;
+
+        ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue );
+        is( $renewokay, 0,                  'No success for auto_renewal' );
+        is( $error,     'auto_renew_final', 'Auto renewal allowed, but it is the last one' );
+
+        # Final unseen renewal
+        Koha::CirculationRules->set_rules(
+            {
+                categorycode => undef,
+                branchcode   => undef,
+                itemtype     => $item_to_auto_renew->itype,
+                rules        => {
+                    unseen_renewals_allowed => 2,
+                    renewalsallowed         => 10,
+                }
+            }
+        );
+        t::lib::Mocks::mock_preference( 'UnseenRenewals', 1 );
+        $issue->unseen_renewals(1)->renewals_count(1)->store;
+
+        ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue );
+        is( $renewokay, 0,                  'No success for auto_renewal' );
+        is( $error,     'auto_unseen_final', 'Final unseen renewal reported, not final overall' );
+
+        # Final unseen renewal
+        Koha::CirculationRules->set_rules(
+            {
+                categorycode => undef,
+                branchcode   => undef,
+                itemtype     => $item_to_auto_renew->itype,
+                rules        => {
+                    unseen_renewals_allowed => 2,
+                    renewalsallowed         => 2,
+                }
+            }
+        );
+        ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue );
+        is( $renewokay, 0,                  'No success for auto_renewal' );
+        is( $error,     'auto_renew_final', 'Final auto renewal reported' );
+
+    };
+
+    # Too many renewals
     # set policy to forbid renewals
     Koha::CirculationRules->set_rules(
         {
@@ -1377,6 +1441,7 @@ subtest "CanBookBeRenewed tests" => sub {
         }
     );
     t::lib::Mocks::mock_preference('UnseenRenewals', 1);
+
     $issue_1->unseen_renewals(2)->store;
 
     ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
-- 
2.30.2