Skip to content

Commit 45852c9

Browse files
joubutomascohen
authored andcommitted
Bug 30860: Cache CanItemBeReserved return value
This patch caches the return value of CanItemBeReserved that could be then returned *on demand* We don't want to introduce side-effects hard to catch from this simple change, so let's return the cache value only from the 2 scripts we are dealing with. This patch requests all item values from CanBookBeReserved on request.pl Before this we either: - Looped every item to find out that book could not be reserved - Looped until we found an item that could be reserved, then looped all items to get statuses In the worst case we avoid double processing a single item, in the best case we avoid double processing all items (if only last on record is holdable) To test: 1 - Find a record in staff client with several items 2 - Set AllowHoldsOnDamagedItems to 'Dont allow' 3 - Add a damaged item to record 4 - Set a hold rule to only allow holds form homebranch and ensure record has items from other branches 5 - Setup things to prevent more items from being held 6 - Attempt hold for patron 7 - Note item statuses 8 - Apply patch 9 - Confirm statuses are as they were before Signed-off-by: Nick Clemens <nick@bywatersolutions.com> Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de> Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
1 parent 79f8e14 commit 45852c9

File tree

3 files changed

+40
-24
lines changed

3 files changed

+40
-24
lines changed

C4/Reserves.pm

+37-21
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ use Koha::Account::Lines;
3636
use Koha::BackgroundJob::BatchUpdateBiblioHoldsQueue;
3737
use Koha::Biblios;
3838
use Koha::Calendar;
39+
use Koha::Cache::Memory::Lite;
3940
use Koha::CirculationRules;
4041
use Koha::Database;
4142
use Koha::DateUtils qw( dt_from_string output_pref );
@@ -419,9 +420,24 @@ sub CanBookBeReserved{
419420
420421
=cut
421422

423+
our $CanItemBeReserved_cache_key;
424+
sub _cache {
425+
my ( $return ) = @_;
426+
my $memory_cache = Koha::Cache::Memory::Lite->get_instance();
427+
$memory_cache->set_in_cache( $CanItemBeReserved_cache_key, $return );
428+
return $return;
429+
}
430+
422431
sub CanItemBeReserved {
423432
my ( $patron, $item, $pickup_branchcode, $params ) = @_;
424433

434+
my $memory_cache = Koha::Cache::Memory::Lite->get_instance();
435+
$CanItemBeReserved_cache_key = sprintf "Hold_CanItemBeReserved:%s:%s:%s", $patron->borrowernumber, $item->itemnumber, $pickup_branchcode || "";
436+
if ( $params->{get_from_cache} ) {
437+
my $cached = $memory_cache->get_from_cache($CanItemBeReserved_cache_key);
438+
return $cached if $cached;
439+
}
440+
425441
my $dbh = C4::Context->dbh;
426442
my $ruleitemtype; # itemtype of the matching issuing rule
427443
my $allowedreserves = 0; # Total number of holds allowed across all records, default to none
@@ -432,7 +448,7 @@ sub CanItemBeReserved {
432448
and !C4::Context->preference('canreservefromotherbranches') )
433449
{
434450
if ( $item->homebranch ne $patron->branchcode ) {
435-
return { status => 'cannotReserveFromOtherBranches' };
451+
return _cache { status => 'cannotReserveFromOtherBranches' };
436452
}
437453
}
438454

@@ -441,7 +457,7 @@ sub CanItemBeReserved {
441457
my $borrower = $patron->unblessed;
442458

443459
# If an item is damaged and we don't allow holds on damaged items, we can stop right here
444-
return { status =>'damaged' }
460+
return _cache { status =>'damaged' }
445461
if ( $item->damaged
446462
&& !C4::Context->preference('AllowHoldsOnDamagedItems') );
447463

@@ -450,21 +466,21 @@ sub CanItemBeReserved {
450466
# Check for the age restriction
451467
my ( $ageRestriction, $daysToAgeRestriction ) =
452468
C4::Circulation::GetAgeRestriction( $biblio->biblioitem->agerestriction, $borrower );
453-
return { status => 'ageRestricted' } if $daysToAgeRestriction && $daysToAgeRestriction > 0;
469+
return _cache { status => 'ageRestricted' } if $daysToAgeRestriction && $daysToAgeRestriction > 0;
454470
}
455471

456472
# Check that the patron doesn't have an item level hold on this item already
457-
return { status =>'itemAlreadyOnHold' }
473+
return _cache { status =>'itemAlreadyOnHold' }
458474
if ( !$params->{ignore_hold_counts} && Koha::Holds->search( { borrowernumber => $patron->borrowernumber, itemnumber => $item->itemnumber } )->count() );
459475

460476
# Check that patron have not checked out this biblio (if AllowHoldsOnPatronsPossessions set)
461477
if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
462478
&& C4::Circulation::CheckIfIssuedToPatron( $patron->borrowernumber, $item->biblionumber ) ) {
463-
return { status =>'alreadypossession' };
479+
return _cache { status =>'alreadypossession' };
464480
}
465481

466482
# check if a recall exists on this item from this borrower
467-
return { status => 'recall' }
483+
return _cache { status => 'recall' }
468484
if $patron->recalls->filter_by_current->search({ item_id => $item->itemnumber })->count;
469485

470486
my $controlbranch = C4::Context->preference('ReservesControlBranch');
@@ -508,15 +524,15 @@ sub CanItemBeReserved {
508524

509525
if ( defined $holds_per_record && $holds_per_record ne '' ){
510526
if ( $holds_per_record == 0 ) {
511-
return { status => "noReservesAllowed" };
527+
return _cache { status => "noReservesAllowed" };
512528
}
513529
if ( !$params->{ignore_hold_counts} ) {
514530
my $search_params = {
515531
borrowernumber => $patron->borrowernumber,
516532
biblionumber => $item->biblionumber,
517533
};
518534
my $holds = Koha::Holds->search($search_params);
519-
return { status => "tooManyHoldsForThisRecord", limit => $holds_per_record } if $holds->count() >= $holds_per_record;
535+
return _cache { status => "tooManyHoldsForThisRecord", limit => $holds_per_record } if $holds->count() >= $holds_per_record;
520536
}
521537
}
522538

@@ -526,13 +542,13 @@ sub CanItemBeReserved {
526542
borrowernumber => $patron->borrowernumber,
527543
reservedate => dt_from_string->date
528544
});
529-
return { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day;
545+
return _cache { status => 'tooManyReservesToday', limit => $holds_per_day } if $today_holds->count() >= $holds_per_day;
530546
}
531547

532548
# we check if it's ok or not
533549
if ( defined $allowedreserves && $allowedreserves ne '' ){
534550
if( $allowedreserves == 0 ){
535-
return { status => 'noReservesAllowed' };
551+
return _cache { status => 'noReservesAllowed' };
536552
}
537553
if ( !$params->{ignore_hold_counts} ) {
538554
# we retrieve count
@@ -577,7 +593,7 @@ sub CanItemBeReserved {
577593
$reservecount = $rowcount->{count};
578594
}
579595

580-
return { status => 'tooManyReserves', limit => $allowedreserves } if $reservecount >= $allowedreserves;
596+
return _cache { status => 'tooManyReserves', limit => $allowedreserves } if $reservecount >= $allowedreserves;
581597
}
582598
}
583599

@@ -596,26 +612,26 @@ sub CanItemBeReserved {
596612
}
597613
)->count();
598614

599-
return { status => 'tooManyReserves', limit => $rule->rule_value} if $total_holds_count >= $rule->rule_value;
615+
return _cache { status => 'tooManyReserves', limit => $rule->rule_value} if $total_holds_count >= $rule->rule_value;
600616
}
601617

602618
my $branchitemrule =
603619
C4::Circulation::GetBranchItemRule( $reserves_control_branch, $item->effective_itemtype );
604620

605621
if ( $branchitemrule->{holdallowed} eq 'not_allowed' ) {
606-
return { status => 'notReservable' };
622+
return _cache { status => 'notReservable' };
607623
}
608624

609625
if ( $branchitemrule->{holdallowed} eq 'from_home_library'
610626
&& $borrower->{branchcode} ne $item->homebranch )
611627
{
612-
return { status => 'cannotReserveFromOtherBranches' };
628+
return _cache { status => 'cannotReserveFromOtherBranches' };
613629
}
614630

615631
my $item_library = Koha::Libraries->find( {branchcode => $item->homebranch} );
616632
if ( $branchitemrule->{holdallowed} eq 'from_local_hold_group') {
617633
if($patron->branchcode ne $item->homebranch && !$item_library->validate_hold_sibling( {branchcode => $patron->branchcode} )) {
618-
return { status => 'branchNotInHoldGroup' };
634+
return _cache { status => 'branchNotInHoldGroup' };
619635
}
620636
}
621637

@@ -625,23 +641,23 @@ sub CanItemBeReserved {
625641
});
626642

627643
unless ($destination) {
628-
return { status => 'libraryNotFound' };
644+
return _cache { status => 'libraryNotFound' };
629645
}
630646
unless ($destination->pickup_location) {
631-
return { status => 'libraryNotPickupLocation' };
647+
return _cache { status => 'libraryNotPickupLocation' };
632648
}
633649
unless ($item->can_be_transferred({ to => $destination })) {
634-
return { status => 'cannotBeTransferred' };
650+
return _cache { status => 'cannotBeTransferred' };
635651
}
636652
if ($branchitemrule->{hold_fulfillment_policy} eq 'holdgroup' && !$item_library->validate_hold_sibling( {branchcode => $pickup_branchcode} )) {
637-
return { status => 'pickupNotInHoldGroup' };
653+
return _cache { status => 'pickupNotInHoldGroup' };
638654
}
639655
if ($branchitemrule->{hold_fulfillment_policy} eq 'patrongroup' && !Koha::Libraries->find({branchcode => $borrower->{branchcode}})->validate_hold_sibling({branchcode => $pickup_branchcode})) {
640-
return { status => 'pickupNotInHoldGroup' };
656+
return _cache { status => 'pickupNotInHoldGroup' };
641657
}
642658
}
643659

644-
return { status => 'OK' };
660+
return _cache { status => 'OK' };
645661
}
646662

647663
=head2 CanReserveBeCanceledFromOpac

opac/opac-reserve.pl

+2-2
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@
264264
my $biblio = Koha::Biblios->find($biblioNum);
265265
my $rank = $biblio->holds->search( { found => [ { "!=" => "W" }, undef ] } )->count + 1;
266266
if ( $item ) {
267-
my $status = CanItemBeReserved( $patron, $item, $branch )->{status};
267+
my $status = CanItemBeReserved( $patron, $item, $branch, { get_from_cache => 1 } )->{status};
268268
if( $status eq 'OK' ){
269269
$canreserve = 1;
270270
} else {
@@ -484,7 +484,7 @@
484484
# items_any_available defined outside of the current loop,
485485
# so we avoiding loop inside IsAvailableForItemLevelRequest:
486486
my $policy_holdallowed =
487-
CanItemBeReserved( $patron, $item )->{status} eq 'OK' &&
487+
CanItemBeReserved( $patron, $item, undef, { get_from_cache => 1 } )->{status} eq 'OK' &&
488488
IsAvailableForItemLevelRequest($item, $patron, undef, $items_any_available);
489489

490490
if ($policy_holdallowed) {

reserve/request.pl

+1-1
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ =head1 request.pl
486486

487487
$item->{'holdallowed'} = $branchitemrule->{'holdallowed'};
488488

489-
my $can_item_be_reserved = CanItemBeReserved( $patron, $item_object )->{status};
489+
my $can_item_be_reserved = CanItemBeReserved( $patron, $item_object, undef, { get_from_cache => 1 } )->{status};
490490
$item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' );
491491
$item->{not_holdable} ||= 'notforloan' if ( $item->{notforloanitype} || $item->{notforloan} > 0 );
492492

0 commit comments

Comments
 (0)