+ # override_limit will override anything else except on_reserve
+ unless ( $override_limit ){
+ my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
+ my $issuing_rule = Koha::CirculationRules->get_effective_rules(
+ {
+ categorycode => $patron->categorycode,
+ itemtype => $item->effective_itemtype,
+ branchcode => $branchcode,
+ rules => [
+ 'renewalsallowed',
+ 'no_auto_renewal_after',
+ 'no_auto_renewal_after_hard_limit',
+ 'lengthunit',
+ 'norenewalbefore',
+ 'unseen_renewals_allowed'
+ ]
+ }
+ );
+
+ return ( 0, "too_many" )
+ if not $issuing_rule->{renewalsallowed} or $issuing_rule->{renewalsallowed} <= $issue->renewals;
+
+ return ( 0, "too_unseen" )
+ if C4::Context->preference('UnseenRenewals') &&
+ $issuing_rule->{unseen_renewals_allowed} &&
+ $issuing_rule->{unseen_renewals_allowed} <= $issue->unseen_renewals;
+
+ my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
+ my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
+ $patron = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
+ my $restricted = $patron->is_debarred;
+ my $hasoverdues = $patron->has_overdues;
+
+ if ( $restricted and $restrictionblockrenewing ) {
+ return ( 0, 'restriction');
+ } elsif ( ($hasoverdues and $overduesblockrenewing eq 'block') || ($issue->is_overdue and $overduesblockrenewing eq 'blockitem') ) {
+ return ( 0, 'overdue');
+ }
+
+ if ( $issue->auto_renew && $patron->autorenew_checkouts ) {
+
+ if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) {
+ return ( 0, 'auto_account_expired' );
+ }
+
+ if ( defined $issuing_rule->{no_auto_renewal_after}
+ and $issuing_rule->{no_auto_renewal_after} ne "" ) {
+ # Get issue_date and add no_auto_renewal_after
+ # If this is greater than today, it's too late for renewal.
+ my $maximum_renewal_date = dt_from_string($issue->issuedate, 'sql');
+ $maximum_renewal_date->add(
+ $issuing_rule->{lengthunit} => $issuing_rule->{no_auto_renewal_after}
+ );
+ my $now = dt_from_string;
+ if ( $now >= $maximum_renewal_date ) {
+ return ( 0, "auto_too_late" );
+ }
+ }
+ if ( defined $issuing_rule->{no_auto_renewal_after_hard_limit}
+ and $issuing_rule->{no_auto_renewal_after_hard_limit} ne "" ) {
+ # If no_auto_renewal_after_hard_limit is >= today, it's also too late for renewal
+ if ( dt_from_string >= dt_from_string( $issuing_rule->{no_auto_renewal_after_hard_limit} ) ) {
+ return ( 0, "auto_too_late" );
+ }
+ }
+
+ if ( C4::Context->preference('OPACFineNoRenewalsBlockAutoRenew') ) {
+ my $fine_no_renewals = C4::Context->preference("OPACFineNoRenewals");
+ my $amountoutstanding =
+ C4::Context->preference("OPACFineNoRenewalsIncludeCredit")
+ ? $patron->account->balance
+ : $patron->account->outstanding_debits->total_outstanding;
+ if ( $amountoutstanding and $amountoutstanding > $fine_no_renewals ) {
+ return ( 0, "auto_too_much_oweing" );
+ }
+ }
+ }
+
+ if ( defined $issuing_rule->{norenewalbefore}
+ and $issuing_rule->{norenewalbefore} ne "" )
+ {
+
+ # Calculate soonest renewal by subtracting 'No renewal before' from due date
+ my $soonestrenewal = dt_from_string( $issue->date_due, 'sql' )->subtract(
+ $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
+
+ # Depending on syspref reset the exact time, only check the date
+ if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
+ and $issuing_rule->{lengthunit} eq 'days' )
+ {
+ $soonestrenewal->truncate( to => 'day' );
+ }
+
+ if ( $soonestrenewal > dt_from_string() )
+ {
+ $auto_renew = ($issue->auto_renew && $patron->autorenew_checkouts) ? "auto_too_soon" : "too_soon";
+ }
+ elsif ( $issue->auto_renew && $patron->autorenew_checkouts ) {
+ $auto_renew = "ok";
+ }
+ }
+
+ # Fallback for automatic renewals:
+ # If norenewalbefore is undef, don't renew before due date.
+ if ( $issue->auto_renew && $auto_renew eq "no" && $patron->autorenew_checkouts ) {
+ my $now = dt_from_string;
+ if ( $now >= dt_from_string( $issue->date_due, 'sql' ) ){
+ $auto_renew = "ok";
+ } else {
+ $auto_renew = "auto_too_soon";
+ }
+ }
+ }
+
+ my ( $resfound, $resrec, $possible_reserves ) = C4::Reserves::CheckReserves($itemnumber);
+
+ # If next hold is non priority, then check if any hold with priority (non_priority = 0) exists for the same biblionumber.
+ if ( $resfound && $resrec->{non_priority} ) {
+ $resfound = Koha::Holds->search(
+ { biblionumber => $resrec->{biblionumber}, non_priority => 0 } )
+ ->count > 0;
+ }
+
+