Bug 12803 - Add ability to skip closed libraries when generating the holds queue
The holds queue is typically generated many times a day in order to select items to fill holds. Often these items are to be sent to a different library. However, if the library whose item is picked to fill a hold is closed, that hold will remain unfilled even if there are other open libraries who own that item. It would be helpful if we could skip closed libraries for the purpose of selecting items to fill holds. Test Plan: 1) Apply this patch 2) Run updatedatabase.pl 3) Create a record with two items on it, one at Branch A, and one at Branch B 4) Place a hold for pickup at Branch C 5) Generate the holds queue 6) Note which branch's item is selected for the hold 7) Enable the new system preference HoldsQueueSkipClosed 8) Add today as a holiday for that branch noted in step 6 9) Regenerate the holds queue 10) View the holds queue, notice the item selected is not from the closed branch! 11) prove t/db_dependent/HoldsQueue.t Signed-off by: Jason Robb <jrobb@sekls.org> Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org> Signed-off-by: Brendan A Gallagher <brendan@bywatersolutions.com>
This commit is contained in:
parent
9bd9476b1d
commit
3c9d50d134
5 changed files with 84 additions and 14 deletions
|
@ -29,6 +29,8 @@ use C4::Branch;
|
||||||
use C4::Circulation;
|
use C4::Circulation;
|
||||||
use C4::Members;
|
use C4::Members;
|
||||||
use C4::Biblio;
|
use C4::Biblio;
|
||||||
|
use C4::Dates qw/format_date/;
|
||||||
|
use Koha::DateUtils;
|
||||||
|
|
||||||
use List::Util qw(shuffle);
|
use List::Util qw(shuffle);
|
||||||
use List::MoreUtils qw(any);
|
use List::MoreUtils qw(any);
|
||||||
|
@ -63,13 +65,25 @@ sub TransportCostMatrix {
|
||||||
my $dbh = C4::Context->dbh;
|
my $dbh = C4::Context->dbh;
|
||||||
my $transport_costs = $dbh->selectall_arrayref("SELECT * FROM transport_cost",{ Slice => {} });
|
my $transport_costs = $dbh->selectall_arrayref("SELECT * FROM transport_cost",{ Slice => {} });
|
||||||
|
|
||||||
|
my $today = dt_from_string();
|
||||||
|
my $calendars;
|
||||||
my %transport_cost_matrix;
|
my %transport_cost_matrix;
|
||||||
foreach (@$transport_costs) {
|
foreach (@$transport_costs) {
|
||||||
my $from = $_->{frombranch};
|
my $from = $_->{frombranch};
|
||||||
my $to = $_->{tobranch};
|
my $to = $_->{tobranch};
|
||||||
my $cost = $_->{cost};
|
my $cost = $_->{cost};
|
||||||
my $disabled = $_->{disable_transfer};
|
my $disabled = $_->{disable_transfer};
|
||||||
$transport_cost_matrix{$to}{$from} = { cost => $cost, disable_transfer => $disabled };
|
$transport_cost_matrix{$to}{$from} = {
|
||||||
|
cost => $cost,
|
||||||
|
disable_transfer => $disabled
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( C4::Context->preference("HoldsQueueSkipClosed") ) {
|
||||||
|
$calendars->{$from} ||= Koha::Calendar->new( branchcode => $from );
|
||||||
|
$transport_cost_matrix{$to}{$from}{disable_transfer} ||=
|
||||||
|
$calendars->{$from}->is_holiday( $today );
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return \%transport_cost_matrix;
|
return \%transport_cost_matrix;
|
||||||
}
|
}
|
||||||
|
@ -601,12 +615,27 @@ sub _trim {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub load_branches_to_pull_from {
|
sub load_branches_to_pull_from {
|
||||||
my $static_branch_list = C4::Context->preference("StaticHoldsQueueWeight")
|
my @branches_to_use;
|
||||||
or return;
|
|
||||||
|
|
||||||
my @branches_to_use = map _trim($_), split /,/, $static_branch_list;
|
my $static_branch_list = C4::Context->preference("StaticHoldsQueueWeight");
|
||||||
|
@branches_to_use = map { _trim($_) } split( /,/, $static_branch_list )
|
||||||
|
if $static_branch_list;
|
||||||
|
|
||||||
@branches_to_use = shuffle(@branches_to_use) if C4::Context->preference("RandomizeHoldsQueueWeight");
|
@branches_to_use =
|
||||||
|
Koha::Database->new()->schema()->resultset('Branch')
|
||||||
|
->get_column('branchcode')->all()
|
||||||
|
unless (@branches_to_use);
|
||||||
|
|
||||||
|
@branches_to_use = shuffle(@branches_to_use)
|
||||||
|
if C4::Context->preference("RandomizeHoldsQueueWeight");
|
||||||
|
|
||||||
|
my $today = dt_from_string();
|
||||||
|
if ( C4::Context->preference('HoldsQueueSkipClosed') ) {
|
||||||
|
@branches_to_use = grep {
|
||||||
|
!Koha::Calendar->new( branchcode => $_ )
|
||||||
|
->is_holiday( $today )
|
||||||
|
} @branches_to_use;
|
||||||
|
}
|
||||||
|
|
||||||
return \@branches_to_use;
|
return \@branches_to_use;
|
||||||
}
|
}
|
||||||
|
|
2
installer/data/mysql/atomicupdate/bug_12803.sql
Normal file
2
installer/data/mysql/atomicupdate/bug_12803.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
INSERT INTO systempreferences (variable,value,explanation,type) VALUES
|
||||||
|
('HoldsQueueSkipClosed', '0', 'If enabled, any libraries that are closed when the holds queue is built will be ignored for the purpose of filling holds.', 'YesNo');
|
|
@ -160,6 +160,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
|
||||||
('HighlightOwnItemsOnOPACWhich','PatronBranch','PatronBranch|OpacURLBranch','Decides which branch\'s items to emphasize. If PatronBranch, emphasize the logged in user\'s library\'s items. If OpacURLBranch, highlight the items of the Apache var BRANCHCODE defined in Koha\'s Apache configuration file.','Choice'),
|
('HighlightOwnItemsOnOPACWhich','PatronBranch','PatronBranch|OpacURLBranch','Decides which branch\'s items to emphasize. If PatronBranch, emphasize the logged in user\'s library\'s items. If OpacURLBranch, highlight the items of the Apache var BRANCHCODE defined in Koha\'s Apache configuration file.','Choice'),
|
||||||
('HoldFeeMode','not_always','always|not_always','Set the hold fee mode','Choice'),
|
('HoldFeeMode','not_always','always|not_always','Set the hold fee mode','Choice'),
|
||||||
('HoldsToPullStartDate','2',NULL,'Set the default start date for the Holds to pull list to this many days ago','Integer'),
|
('HoldsToPullStartDate','2',NULL,'Set the default start date for the Holds to pull list to this many days ago','Integer'),
|
||||||
|
('HoldsQueueSkipClosed', '0', NULL, 'If enabled, any libraries that are closed when the holds queue is built will be ignored for the purpose of filling holds.', 'YesNo'),
|
||||||
('HomeOrHoldingBranch','holdingbranch','holdingbranch|homebranch','Used by Circulation to determine which branch of an item to check with independent branches on, and by search to determine which branch to choose for availability ','Choice'),
|
('HomeOrHoldingBranch','holdingbranch','holdingbranch|homebranch','Used by Circulation to determine which branch of an item to check with independent branches on, and by search to determine which branch to choose for availability ','Choice'),
|
||||||
('HTML5MediaEnabled','not','not|opac|staff|both','Show a tab with a HTML5 media player for files catalogued in field 856','Choice'),
|
('HTML5MediaEnabled','not','not|opac|staff|both','Show a tab with a HTML5 media player for files catalogued in field 856','Choice'),
|
||||||
('HTML5MediaExtensions','webm|ogg|ogv|oga|vtt','','Media file extensions','free'),
|
('HTML5MediaExtensions','webm|ogg|ogv|oga|vtt','','Media file extensions','free'),
|
||||||
|
|
|
@ -501,10 +501,15 @@ Circulation:
|
||||||
- pref: ExpireReservesMaxPickUpDelayCharge
|
- pref: ExpireReservesMaxPickUpDelayCharge
|
||||||
class: currency
|
class: currency
|
||||||
-
|
-
|
||||||
- Satisfy holds from the libraries
|
- Satisfy holds using items from the libraries
|
||||||
- pref: StaticHoldsQueueWeight
|
- pref: StaticHoldsQueueWeight
|
||||||
class: multi
|
class: multi
|
||||||
- (as branchcodes, separated by commas; if empty, uses all libraries)
|
- (as branchcodes, separated by commas; if empty, uses all libraries)
|
||||||
|
- when they are
|
||||||
|
- pref: HoldsQueueSkipClosed
|
||||||
|
choices:
|
||||||
|
yes: open
|
||||||
|
no: open or closed
|
||||||
- pref: RandomizeHoldsQueueWeight
|
- pref: RandomizeHoldsQueueWeight
|
||||||
choices:
|
choices:
|
||||||
yes: in random order.
|
yes: in random order.
|
||||||
|
|
|
@ -8,16 +8,20 @@
|
||||||
|
|
||||||
use Modern::Perl;
|
use Modern::Perl;
|
||||||
|
|
||||||
use C4::Context;
|
use Test::More tests => 24;
|
||||||
|
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
use Test::More tests => 23;
|
|
||||||
|
|
||||||
use C4::Branch;
|
use C4::Branch;
|
||||||
use C4::Members;
|
use C4::Members;
|
||||||
use Koha::Database;
|
use Koha::Database;
|
||||||
|
|
||||||
|
use C4::Calendar;
|
||||||
|
use C4::Context;
|
||||||
|
use C4::Branch;
|
||||||
|
use C4::ItemType;
|
||||||
|
use C4::Members;
|
||||||
|
use Koha::DateUtils;
|
||||||
|
|
||||||
use t::lib::TestBuilder;
|
use t::lib::TestBuilder;
|
||||||
|
|
||||||
use Koha::ItemTypes;
|
use Koha::ItemTypes;
|
||||||
|
@ -66,6 +70,7 @@ $itemtype or BAIL_OUT("No adequate itemtype"); #FIXME Should be $itemtype = $ite
|
||||||
|
|
||||||
#Set up the stage
|
#Set up the stage
|
||||||
# Sysprefs and cost matrix
|
# Sysprefs and cost matrix
|
||||||
|
C4::Context->set_preference('HoldsQueueSkipClosed', 0);
|
||||||
$dbh->do("UPDATE systempreferences SET value = ? WHERE variable = 'StaticHoldsQueueWeight'", undef,
|
$dbh->do("UPDATE systempreferences SET value = ? WHERE variable = 'StaticHoldsQueueWeight'", undef,
|
||||||
join( ',', @other_branches, $borrower_branchcode, $least_cost_branch_code));
|
join( ',', @other_branches, $borrower_branchcode, $least_cost_branch_code));
|
||||||
$dbh->do("UPDATE systempreferences SET value = '0' WHERE variable = 'RandomizeHoldsQueueWeight'");
|
$dbh->do("UPDATE systempreferences SET value = '0' WHERE variable = 'RandomizeHoldsQueueWeight'");
|
||||||
|
@ -300,12 +305,40 @@ is( @$holds_queue, 2, "Holds queue filling correct number for default holds poli
|
||||||
is( $holds_queue->[0]->{cardnumber}, $borrower1->{cardnumber}, "Holds queue filling 1st correct hold for default holds policy 'from home library'");
|
is( $holds_queue->[0]->{cardnumber}, $borrower1->{cardnumber}, "Holds queue filling 1st correct hold for default holds policy 'from home library'");
|
||||||
is( $holds_queue->[1]->{cardnumber}, $borrower2->{cardnumber}, "Holds queue filling 2nd correct hold for default holds policy 'from home library'");
|
is( $holds_queue->[1]->{cardnumber}, $borrower2->{cardnumber}, "Holds queue filling 2nd correct hold for default holds policy 'from home library'");
|
||||||
|
|
||||||
|
# Test skipping hold picks for closed libraries.
|
||||||
|
# At this point in the test, we have 2 rows in the holds queue
|
||||||
|
# 1 of which is coming from MPL. Let's enable HoldsQueueSkipClosed
|
||||||
|
# and make today a holiday for MPL. When we run it again we should only
|
||||||
|
# have 1 row in the holds queue
|
||||||
|
C4::Context->set_preference('HoldsQueueSkipClosed', 1);
|
||||||
|
my $today = dt_from_string();
|
||||||
|
C4::Calendar->new( branchcode => 'MPL' )->insert_single_holiday(
|
||||||
|
day => $today->day(),
|
||||||
|
month => $today->month(),
|
||||||
|
year => $today->year(),
|
||||||
|
title => "$today",
|
||||||
|
description => "$today",
|
||||||
|
);
|
||||||
|
C4::HoldsQueue::CreateQueue();
|
||||||
|
$holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
|
||||||
|
is( scalar( @$holds_queue ), 1, "Holds not filled with items from closed libraries" );
|
||||||
|
C4::Context->set_preference('HoldsQueueSkipClosed', 0);
|
||||||
|
|
||||||
$dbh->do("DELETE FROM default_circ_rules");
|
$dbh->do("DELETE FROM default_circ_rules");
|
||||||
$dbh->do("INSERT INTO default_circ_rules ( holdallowed ) VALUES ( 2 )");
|
$dbh->do("INSERT INTO default_circ_rules ( holdallowed ) VALUES ( 2 )");
|
||||||
C4::HoldsQueue::CreateQueue();
|
C4::HoldsQueue::CreateQueue();
|
||||||
$holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
|
$holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
|
||||||
is( @$holds_queue, 3, "Holds queue filling correct number for holds for default holds policy 'from any library'" );
|
is( @$holds_queue, 3, "Holds queue filling correct number for holds for default holds policy 'from any library'" );
|
||||||
#warn "HOLDS QUEUE: " . Data::Dumper::Dumper( $holds_queue );
|
|
||||||
|
# Test skipping hold picks for closed libraries without transport cost matrix
|
||||||
|
# At this point in the test, we have 3 rows in the holds queue
|
||||||
|
# one of which is coming from MPL. Let's enable HoldsQueueSkipClosed
|
||||||
|
# and use our previously created holiday for MPL.
|
||||||
|
# When we run it again we should only have 2 rows in the holds queue
|
||||||
|
C4::Context->set_preference( 'HoldsQueueSkipClosed', 1 );
|
||||||
|
C4::HoldsQueue::CreateQueue();
|
||||||
|
$holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
|
||||||
|
is( scalar( @$holds_queue ), 2, "Holds not filled with items from closed libraries" );
|
||||||
|
|
||||||
# Bug 14297
|
# Bug 14297
|
||||||
$itemtype = Koha::ItemTypes->search->next->itemtype;
|
$itemtype = Koha::ItemTypes->search->next->itemtype;
|
||||||
|
|
Loading…
Reference in a new issue