use Modern::Perl;
-use Test::More tests => 55;
+use Test::More tests => 58;
use Data::Dumper;
-use C4::Calendar;
+use C4::Calendar qw( new insert_single_holiday );
use C4::Context;
use C4::Members;
+use C4::Circulation qw( AddIssue AddReturn );
use Koha::Database;
-use Koha::DateUtils;
+use Koha::DateUtils qw( dt_from_string );
use Koha::Items;
use Koha::Holds;
use Koha::CirculationRules;
BEGIN {
use FindBin;
use lib $FindBin::Bin;
- use_ok('C4::Reserves');
- use_ok('C4::HoldsQueue');
+ use_ok('C4::Reserves', qw( AddReserve ModReserve ModReserveAffect ));
+ use_ok('C4::HoldsQueue', qw( TransportCostMatrix GetHoldsQueueItems CreateQueue UpdateTransportCostMatrix GetPendingHoldRequestsForBib ));
}
my $schema = Koha::Database->schema;
# Frst branch from StaticHoldsQueueWeight
test_queue ('take from lowest cost branch', 0, $borrower_branchcode, $other_branches[0]);
test_queue ('take from lowest cost branch', 1, $borrower_branchcode, $least_cost_branch_code);
-my $queue = C4::HoldsQueue::GetHoldsQueueItems($least_cost_branch_code) || [];
+my $queue = C4::HoldsQueue::GetHoldsQueueItems({ branchlmit => $least_cost_branch_code}) || [];
my $queue_item = $queue->[0];
ok( $queue_item
&& $queue_item->{pickbranch} eq $borrower_branchcode
Koha::CirculationRules->set_rule(
{
rule_name => 'holdallowed',
- rule_value => 1,
+ rule_value => 'from_home_library',
branchcode => undef,
itemtype => undef,
}
Koha::CirculationRules->set_rule(
{
rule_name => 'holdallowed',
- rule_value => 2,
+ rule_value => 'from_any_library',
branchcode => undef,
itemtype => undef,
}
Koha::CirculationRules->set_rule(
{
rule_name => 'holdallowed',
- rule_value => 2,
+ rule_value => 'from_any_library',
branchcode => undef,
itemtype => undef,
}
branchcode => $library_A,
itemtype => $itemtype,
rules => {
- holdallowed => 2,
+ holdallowed => 'from_any_library',
returnbranch => 'homebranch',
}
}
branchcode => undef,
itemtype => undef,
rules => {
- holdallowed => 2,
+ holdallowed => 'from_any_library',
hold_fulfillment_policy => 'homebranch',
}
}
branchcode => undef,
itemtype => undef,
rules => {
- holdallowed => 2,
+ holdallowed => 'from_any_library',
hold_fulfillment_policy => 'holdingbranch',
}
}
branchcode => undef,
itemtype => undef,
rules => {
- holdallowed => 2,
+ holdallowed => 'from_any_library',
hold_fulfillment_policy => 'any',
}
}
branchcode => undef,
itemtype => undef,
rules => {
- holdallowed => 2,
+ holdallowed => 'from_any_library',
hold_fulfillment_policy => 'any',
}
}
is( $queue_rs->count(), 1,
"Hold queue contains one hold" );
is(
- $queue_rs->next->borrowernumber,
+ $queue_rs->next->borrowernumber->borrowernumber,
$local_patron->borrowernumber,
"We should pick the local hold over the next available"
);
is( $queue_rs->count(), 1,
"Hold queue contains one hold" );
is(
- $q->borrowernumber,
+ $q->borrowernumber->borrowernumber,
$local_patron->borrowernumber,
"We should pick the local hold over the next available"
);
is( $queue_rs->count(), 1,
"Hold queue contains one hold" );
is(
- $q->borrowernumber,
+ $q->borrowernumber->borrowernumber,
$local_patron->borrowernumber,
"We should pick the local hold over the next available"
);
is( $queue_rs->count(), 1,
"Hold queue contains one hold" );
is(
- $q->borrowernumber,
+ $q->borrowernumber->borrowernumber,
$local_patron->borrowernumber,
"We should pick the local hold over the next available"
);
branchcode => $other_patron->branchcode,
borrowernumber => $other_patron->borrowernumber,
biblionumber => $item1->biblionumber,
- priority => 1
+ priority => 1,
+ itemtype => $item1->effective_itemtype
}
);
branchcode => $local_patron_excluded->branchcode,
borrowernumber => $local_patron_excluded->borrowernumber,
biblionumber => $item1->biblionumber,
- priority => 2
+ priority => 2,
+ itemtype => $item1->effective_itemtype
}
);
branchcode => $local_patron_not_excluded->branchcode,
borrowernumber => $local_patron_not_excluded->borrowernumber,
biblionumber => $item1->biblionumber,
- priority => 3
+ priority => 3,
+ itemtype => $item1->effective_itemtype
}
);
my $queue_rs = $schema->resultset('TmpHoldsqueue');
my $next = $queue_rs->next;
is($queue_rs->count, 1, 'Only 1 patron queueud' );
- is($next->borrowernumber, $local_patron_not_excluded->borrowernumber, 'Not excluded local patron is queued');
+ is($next->borrowernumber->borrowernumber, $local_patron_not_excluded->borrowernumber, 'Not excluded local patron is queued');
my $item2 = $builder->build_sample_item(
{
$queue_rs = $schema->resultset('TmpHoldsqueue');
is( $queue_rs->count, 2, '2 patrons queued' );
$next = $queue_rs->next;
- is($next->borrowernumber, $local_patron_not_excluded->borrowernumber, 'Not excluded local patron is queued');
+ is($next->borrowernumber->borrowernumber, $local_patron_not_excluded->borrowernumber, 'Not excluded local patron is queued');
$next = $queue_rs->next;
- is($next->borrowernumber, $other_patron->borrowernumber, 'Other patron is queued');
+ is($next->borrowernumber->borrowernumber, $other_patron->borrowernumber, 'Other patron is queued');
$item1->exclude_from_local_holds_priority(1)->store;
$queue_rs = $schema->resultset('TmpHoldsqueue');
is( $queue_rs->count, 2, '2 patrons queued' );
$next = $queue_rs->next;
- is($next->borrowernumber, $other_patron->borrowernumber, 'Other patron is queued');
+ is($next->borrowernumber->borrowernumber, $other_patron->borrowernumber, 'Other patron is queued');
$next = $queue_rs->next;
- is($next->borrowernumber, $local_patron_excluded->borrowernumber, 'Excluded local patron is queued');
+ is($next->borrowernumber->borrowernumber, $local_patron_excluded->borrowernumber, 'Excluded local patron is queued');
};
# Cleanup
$schema->storage->txn_rollback;
}
+subtest "Test _checkHoldPolicy" => sub {
+
+ plan tests => 25;
+
+ $schema->storage->txn_begin;
+
+ my $library1 = $builder->build_object( { class => 'Koha::Libraries' } );
+ my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
+ my $library_nongroup = $builder->build_object( { class => 'Koha::Libraries' } );
+ my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
+ my $patron = $builder->build_object(
+ {
+ class => "Koha::Patrons",
+ value => {
+ branchcode => $library1->branchcode,
+ categorycode => $category->categorycode,
+ }
+ }
+ );
+ my $biblio = $builder->build_sample_biblio();
+ my $item1 = $builder->build_sample_item(
+ {
+ biblionumber => $biblio->biblionumber,
+ library => $library1->branchcode,
+ exclude_from_local_holds_priority => 0,
+ }
+ );
+
+ $reserve_id = AddReserve(
+ {
+ branchcode => $item1->homebranch,
+ borrowernumber => $patron->borrowernumber,
+ biblionumber => $biblio->id,
+ priority => 1
+ }
+ );
+ ok( $reserve_id, "Hold was created");
+ my $requests = C4::HoldsQueue::GetPendingHoldRequestsForBib($biblio->biblionumber);
+ is( @$requests, 1, "Got correct number of holds");
+
+ my $request = $requests->[0];
+ is( $request->{biblionumber}, $biblio->id, "Hold has correct biblio");
+ is( $request->{borrowernumber}, $patron->id, "Hold has correct borrower");
+ is( $request->{borrowerbranch}, $patron->branchcode, "Hold has correct borrowerbranch");
+
+ my $hold = Koha::Holds->find( $reserve_id );
+ ok( $hold, "Found hold" );
+
+ my $item = {
+ holdallowed => 'from_home_library',
+ homebranch => $request->{borrowerbranch}, # library1
+ hold_fulfillment_policy => 'any'
+ };
+
+ # Base case should work
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true" );
+
+ # Test holdallowed = 'not_allowed'
+ $item->{holdallowed} = 'not_allowed';
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if holdallowed = not_allowed" );
+
+ # Test holdallowed = 'from_home_library'
+ $item->{holdallowed} = 'from_home_library';
+ $item->{homebranch} = $library_nongroup->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if holdallowed = from_home_library and branches do not match" );
+
+ $item->{homebranch} = $request->{borrowerbranch};
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if holdallowed = from_home_library and branches do match" );
+
+ # Test holdallowed = 3
+ $item->{holdallowed} = 'from_local_hold_group';
+ $item->{homebranch} = $library_nongroup->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if branchode doesn't match, holdallowed = from_local_hold_group and no group branches exist" );
+ $item->{homebranch} = $request->{borrowerbranch};
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if branchode matches, holdallowed = from_local_hold_group and no group branches exist" );
+
+ # Create library groups hierarchy
+ my $rootgroup = $builder->build_object( { class => 'Koha::Library::Groups', value => {ft_local_hold_group => 1} } );
+ my $group1 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library1->branchcode}} );
+ my $group2 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library2->branchcode}} );
+
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if holdallowed = from_local_hold_group and no group branches exist" );
+
+ $group1->delete;
+
+ # Test hold_fulfillment_policy = holdgroup
+ $item->{hold_fulfillment_policy} = 'holdgroup';
+ $item->{homebranch} = $library_nongroup->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns true if library is not part of hold group, branches don't match and hfp = holdgroup" );
+ $item->{homebranch} = $request->{borrowerbranch};
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is not part of hold group, branches match and hfp = holdgroup" );
+
+ $group1 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library1->branchcode}} );
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
+
+ $item->{homebranch} = $library2->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
+ $item->{homebranch} = $library1->id;
+
+ $group1->delete;
+
+ # Test hold_fulfillment_policy = homebranch
+ $item->{hold_fulfillment_policy} = 'homebranch';
+ $item->{homebranch} = $library_nongroup->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if hfp = homebranch and pickup branch != item homebranch" );
+
+ $item->{homebranch} = $request->{borrowerbranch};
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if hfp = homebranch and pickup branch = item homebranch" );
+
+ # Test hold_fulfillment_policy = holdingbranch
+ $item->{hold_fulfillment_policy} = 'holdingbranch';
+ $item->{holdingbranch} = $library_nongroup->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if hfp = holdingbranch and pickup branch != item holdingbranch" );
+
+ $item->{holdingbranch} = $request->{borrowerbranch};
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if hfp = holdingbranch and pickup branch = item holdingbranch" );
+
+ # Test hold_fulfillment_policy = patrongroup
+ $item->{hold_fulfillment_policy} = 'patrongroup';
+ $item->{borrowerbranch} = $library1->id;
+
+ $item->{homebranch} = $library_nongroup->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if library is not part of hold group, branches don't match, hfp = patrongroup" );
+ $item->{homebranch} = $request->{borrowerbranch};
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns false if library is not part of hold group, branches match, hfp = patrongroup" );
+
+ $group1 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library1->branchcode}} );
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
+
+ $item->{borrowerbranch} = $library2->id;
+ is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
+ $item->{borrowerbranch} = $library1->id;
+
+ $schema->storage->txn_rollback;
+};
+
sub dump_records {
my ($tablename) = @_;
return $dbh->selectall_arrayref("SELECT * from $tablename where borrowernumber = ?", { Slice => {} }, $borrowernumber);
}
+
+subtest 'Remove holds on check-in match' => sub {
+
+ plan tests => 2;
+
+ $schema->storage->txn_begin;
+
+ my $lib = $builder->build_object( { class => 'Koha::Libraries' } );
+
+ my $patron1 = $builder->build_object(
+ {
+ class => 'Koha::Patrons',
+ value => { branchcode => $lib->branchcode }
+ }
+ );
+ my $patron2 = $builder->build_object(
+ {
+ class => 'Koha::Patrons',
+ value => { branchcode => $lib->branchcode }
+ }
+ );
+
+ my $item = $builder->build_sample_item(
+ { homebranch => $lib->branchcode, holdingbranch => $lib->branchcode } );
+
+ t::lib::Mocks::mock_userenv( { branchcode => $lib->branchcode } );
+
+ AddIssue( $patron1->unblessed, $item->barcode, dt_from_string );
+
+ my $hold_id = AddReserve(
+ {
+ branchcode => $item->homebranch,
+ borrowernumber => $patron2->borrowernumber,
+ biblionumber => $item->biblionumber,
+ itemnumber => undef,
+ priority => 1
+ }
+ );
+
+ my $hold = Koha::Holds->find($hold_id);
+
+ AddReturn( $item->barcode, $item->homebranch );
+
+ C4::HoldsQueue::CreateQueue();
+
+ my $sth = $dbh->prepare(q{
+ SELECT COUNT(*)
+ FROM tmp_holdsqueue q
+ INNER JOIN hold_fill_targets t
+ ON q.borrowernumber = t.borrowernumber
+ AND q.biblionumber = t.biblionumber
+ AND q.itemnumber = t.itemnumber
+ AND q.item_level_request = t.item_level_request
+ AND q.holdingbranch = t.source_branchcode
+ WHERE t.reserve_id = ?
+ });
+ $sth->execute($hold->reserve_id);
+ my ($count_1) = $sth->fetchrow_array;
+
+ is( $count_1, 1, "Holds queue has one element" );
+
+ AddReturn( $item->barcode, $item->homebranch, undef, dt_from_string );
+
+ ModReserveAffect( $item->itemnumber, $hold->borrowernumber, 0,
+ $hold->reserve_id );
+
+ $sth->execute($hold->reserve_id);
+ my ($count_2) = $sth->fetchrow_array;
+
+ is( $count_2, 0,
+ "Holds queue has no elements, even when queue was not rebuilt" );
+
+ $schema->storage->txn_rollback;
+};
+
+subtest "GetHoldsQueueItems" => sub {
+ plan tests => 4;
+
+ $schema->storage->txn_begin;
+
+ my $ccode = $builder->build_object(
+ {
+ class => 'Koha::AuthorisedValues',
+ value => {
+ category => 'CCODE'
+ }
+ }
+ );
+ my $location = $builder->build_object(
+ {
+ class => 'Koha::AuthorisedValues',
+ value => {
+ category => 'LOC'
+ }
+ }
+ );
+ my $item_1 = $builder->build_sample_item();
+ my $item_2 = $builder->build_sample_item(
+ {
+ itype => $item_1->itype,
+ ccode => $ccode->authorised_value
+ }
+ );
+ my $item_3 = $builder->build_sample_item(
+ {
+ itype => $item_1->itype,
+ ccode => $item_2->ccode,
+ location => $location->authorised_value
+ }
+ );
+
+ my $itemnumber_1 = $item_1->itemnumber;
+ my $itemnumber_2 = $item_2->itemnumber;
+ my $itemnumber_3 = $item_3->itemnumber;
+
+ my $biblionumber_1 = $item_1->biblionumber;
+ my $biblionumber_2 = $item_2->biblionumber;
+ my $biblionumber_3 = $item_3->biblionumber;
+
+ my $sth = $dbh->prepare(q{ SELECT COUNT(*) FROM tmp_holdsqueue });
+ $sth->execute();
+ my ($count) = $sth->fetchrow_array;
+
+ $dbh->do( "
+ INSERT INTO tmp_holdsqueue (itemnumber,biblionumber,surname,firstname,phone,borrowernumber,title,notes) VALUES
+ ($itemnumber_1,$biblionumber_1,'','','',22,'',''),
+ ($itemnumber_2,$biblionumber_2,'','','',32,'',''),
+ ($itemnumber_3,$biblionumber_3,'','','',42,'','')
+ " );
+
+ my $queue_items = GetHoldsQueueItems();
+ is( scalar @$queue_items, $count + 3, 'Three items added to queue' );
+
+ $queue_items = GetHoldsQueueItems( { itemtypeslimit => $item_1->itype } );
+ is( scalar @$queue_items,
+ 3, 'Three items of same itemtype found when itemtypeslimit passed' );
+
+ $queue_items = GetHoldsQueueItems(
+ { itemtypeslimit => $item_1->itype, ccodeslimit => $item_2->ccode } );
+ is( scalar @$queue_items,
+ 2, 'Two items of same collection found when ccodeslimit passed' );
+
+ @$queue_items = GetHoldsQueueItems(
+ {
+ itemtypeslimit => $item_1->itype,
+ ccodeslimit => $item_2->ccode,
+ locationslimit => $item_3->location
+ }
+ );
+ is( scalar @$queue_items,
+ 1, 'One item of shleving location found when locationslimit passed' );
+
+ $schema->storage->txn_rollback;
+};