From 19507cd7e957ccbddfe6c98aaa18792151e2f2d0 Mon Sep 17 00:00:00 2001 From: Nick Clemens Date: Mon, 15 Nov 2021 13:54:00 +0000 Subject: [PATCH] Bug 29483: Check ItemsAnyAvailableAndNotRestricted once per patron ItemsAnyAvailableAndNotRestricted can take a long time and create nested loops. We can check it once per patron, however, this requires us to flip the loops. Since an item can only be used once, we now add a check to see if this item has already been assigned to a borrower. To test: 1 - Find or create a biblio with 100 items 2 - Place ten 'Next available' holds on a biblio 3 - Set preference 'AllowRenewalIfOtherItemsAvailable' to 'Allow' Set circ rules 'On shelf holds allowed' to 'If any unavailable' 4 - Checkout one of the items to a patron, backdated to be overdue 5 - Note a long loading time for the patron's checkouts 6 - Apply patch, restart_all 7 - Patron loads much faster --- C4/Circulation.pm | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 12e2905069..646fe5c0f2 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -27,7 +27,7 @@ use Encode; use Koha::DateUtils qw( dt_from_string output_pref ); use C4::Context; use C4::Stats qw( UpdateStats ); -use C4::Reserves qw( CheckReserves CanItemBeReserved MoveReserve ModReserve ModReserveMinusPriority RevertWaitingStatus IsItemOnHoldAndFound IsAvailableForItemLevelRequest ); +use C4::Reserves qw( CheckReserves CanItemBeReserved MoveReserve ModReserve ModReserveMinusPriority RevertWaitingStatus IsItemOnHoldAndFound IsAvailableForItemLevelRequest ItemsAnyAvailableAndNotRestricted ); use C4::Biblio qw( UpdateTotalIssues ); use C4::Items qw( ModItemTransfer ModDateLastSeen CartToShelf ); use C4::Accounts; @@ -2853,19 +2853,23 @@ sub CanBookBeRenewed { # can be filled with available items. We can get the union of the sets simply # by pushing all the elements onto an array and removing the duplicates. my @reservable; - ITEM: while ( my $item = $items->next ) { - next if IsItemOnHoldAndFound( $item->itemnumber ); - while ( my $patron = $patrons->next ) { - next unless IsAvailableForItemLevelRequest($item, $patron); - next unless CanItemBeReserved($patron->borrowernumber,$item->itemnumber,undef,{ignore_hold_counts=>1})->{status} eq 'OK'; - push @reservable, $item->itemnumber; + my %matched_items; + PATRON: while ( my $patron = $patrons->next ) { + my $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $item->biblionumber, patron => $patron }); + while ( my $other_item = $items->next ) { + next if $matched_items{$other_item->itemnumber} == 1; + next if IsItemOnHoldAndFound( $other_item->itemnumber ); + next unless IsAvailableForItemLevelRequest($other_item, $patron, undef, $items_any_available); + next unless CanItemBeReserved($patron->borrowernumber,$other_item->itemnumber,undef,{ignore_hold_counts=>1})->{status} eq 'OK'; + push @reservable, $other_item->itemnumber; if (@reservable >= @borrowernumbers) { $resfound = 0; - last ITEM; + last PATRON; } + $matched_items{$other_item->itemnumber} = 1; last; } - $patrons->reset; + $items->reset; } } } -- 2.20.1