Bug 31351: (QA follow-up) Extend the encode/decode test
[koha-ffzg.git] / t / db_dependent / HoldsQueue.t
index 06047c6..7067931 100755 (executable)
@@ -8,14 +8,15 @@
 
 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;
@@ -26,8 +27,8 @@ use t::lib::Mocks;
 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;
@@ -162,7 +163,7 @@ $dbh->do("DELETE FROM items WHERE holdingbranch = '$borrower_branchcode'");
 # 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
@@ -308,7 +309,7 @@ $dbh->do("DELETE FROM circulation_rules");
 Koha::CirculationRules->set_rule(
     {
         rule_name    => 'holdallowed',
-        rule_value   => 1,
+        rule_value   => 'from_home_library',
         branchcode   => undef,
         itemtype     => undef,
     }
@@ -345,7 +346,7 @@ $dbh->do("DELETE FROM circulation_rules");
 Koha::CirculationRules->set_rule(
     {
         rule_name    => 'holdallowed',
-        rule_value   => 2,
+        rule_value   => 'from_any_library',
         branchcode   => undef,
         itemtype     => undef,
     }
@@ -372,7 +373,7 @@ $dbh->do("DELETE FROM circulation_rules");
 Koha::CirculationRules->set_rule(
     {
         rule_name    => 'holdallowed',
-        rule_value   => 2,
+        rule_value   => 'from_any_library',
         branchcode   => undef,
         itemtype     => undef,
     }
@@ -537,7 +538,7 @@ Koha::CirculationRules->set_rules(
         branchcode   => $library_A,
         itemtype     => $itemtype,
         rules        => {
-            holdallowed  => 2,
+            holdallowed  => 'from_any_library',
             returnbranch => 'homebranch',
         }
     }
@@ -650,7 +651,7 @@ Koha::CirculationRules->set_rules(
         branchcode   => undef,
         itemtype     => undef,
         rules        => {
-            holdallowed             => 2,
+            holdallowed             => 'from_any_library',
             hold_fulfillment_policy => 'homebranch',
         }
     }
@@ -711,7 +712,7 @@ Koha::CirculationRules->set_rules(
         branchcode   => undef,
         itemtype     => undef,
         rules        => {
-            holdallowed             => 2,
+            holdallowed             => 'from_any_library',
             hold_fulfillment_policy => 'holdingbranch',
         }
     }
@@ -769,7 +770,7 @@ Koha::CirculationRules->set_rules(
         branchcode   => undef,
         itemtype     => undef,
         rules        => {
-            holdallowed             => 2,
+            holdallowed             => 'from_any_library',
             hold_fulfillment_policy => 'any',
         }
     }
@@ -860,7 +861,7 @@ Koha::CirculationRules->set_rules(
         branchcode   => undef,
         itemtype     => undef,
         rules        => {
-            holdallowed             => 2,
+            holdallowed             => 'from_any_library',
             hold_fulfillment_policy => 'any',
         }
     }
@@ -977,7 +978,7 @@ subtest "Test Local Holds Priority - Bib level" => sub {
     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"
     );
@@ -1047,7 +1048,7 @@ subtest "Test Local Holds Priority - Item level" => sub {
     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"
     );
@@ -1115,7 +1116,7 @@ subtest "Test Local Holds Priority - Item level hold over Record level hold (Bug
     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"
     );
@@ -1192,7 +1193,7 @@ subtest "Test Local Holds Priority - Get correct item for item level hold" => su
     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"
     );
@@ -1413,7 +1414,8 @@ subtest 'Excludes from local holds priority' => sub {
             branchcode     => $other_patron->branchcode,
             borrowernumber => $other_patron->borrowernumber,
             biblionumber   => $item1->biblionumber,
-            priority       => 1
+            priority       => 1,
+            itemtype       => $item1->effective_itemtype
         }
     );
 
@@ -1422,7 +1424,8 @@ subtest 'Excludes from local holds priority' => sub {
             branchcode     => $local_patron_excluded->branchcode,
             borrowernumber => $local_patron_excluded->borrowernumber,
             biblionumber   => $item1->biblionumber,
-            priority       => 2
+            priority       => 2,
+            itemtype       => $item1->effective_itemtype
         }
     );
 
@@ -1431,7 +1434,8 @@ subtest 'Excludes from local holds priority' => sub {
             branchcode     => $local_patron_not_excluded->branchcode,
             borrowernumber => $local_patron_not_excluded->borrowernumber,
             biblionumber   => $item1->biblionumber,
-            priority       => 3
+            priority       => 3,
+            itemtype       => $item1->effective_itemtype
         }
     );
 
@@ -1440,7 +1444,7 @@ subtest 'Excludes from local holds priority' => sub {
     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(
         {
@@ -1454,9 +1458,9 @@ subtest 'Excludes from local holds priority' => sub {
     $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;
 
@@ -1465,9 +1469,9 @@ subtest 'Excludes from local holds priority' => sub {
     $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;
@@ -1519,7 +1523,297 @@ sub test_queue {
 
 }
 
+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;
+};