Bug 25757: Add unit tests for item relation
[koha.git] / t / db_dependent / HoldsQueue.t
1 #!/usr/bin/perl
2
3 # Test C4::HoldsQueue::CreateQueue() for both transport cost matrix
4 # and StaticHoldsQueueWeight array (no RandomizeHoldsQueueWeight, no point)
5 # Wraps tests in transaction that's rolled back, so no data is destroyed
6 # MySQL WARNING: This makes sense only if your tables are InnoDB, otherwise
7 # transactions are not supported and mess is left behind
8
9 use Modern::Perl;
10
11 use Test::More tests => 56;
12 use Data::Dumper;
13
14 use C4::Calendar;
15 use C4::Context;
16 use C4::Members;
17 use Koha::Database;
18 use Koha::DateUtils;
19 use Koha::Items;
20 use Koha::Holds;
21 use Koha::CirculationRules;
22
23 use t::lib::TestBuilder;
24 use t::lib::Mocks;
25
26 BEGIN {
27     use FindBin;
28     use lib $FindBin::Bin;
29     use_ok('C4::Reserves');
30     use_ok('C4::HoldsQueue');
31 }
32
33 my $schema = Koha::Database->schema;
34 $schema->storage->txn_begin;
35 my $dbh = C4::Context->dbh;
36 $dbh->do("DELETE FROM circulation_rules");
37
38 my $builder = t::lib::TestBuilder->new;
39
40 t::lib::Mocks::mock_preference( 'UseBranchTransferLimits',  '0' );
41 t::lib::Mocks::mock_preference( 'BranchTransferLimitsType', 'itemtype' );
42
43 my $library1 = $builder->build({
44     source => 'Branch',
45 });
46 my $library2 = $builder->build({
47     source => 'Branch',
48 });
49 my $library3 = $builder->build({
50     source => 'Branch',
51 });
52
53 my $TITLE = "Test Holds Queue XXX";
54
55 my $borrower = $builder->build({
56     source => 'Borrower',
57     value => {
58         branchcode => $library1->{branchcode},
59     }
60 });
61
62 my $borrowernumber = $borrower->{borrowernumber};
63 # Set special (for this test) branches
64 my $borrower_branchcode = $borrower->{branchcode};
65 my @branchcodes = ( $library1->{branchcode}, $library2->{branchcode}, $library3->{branchcode} );
66 my @other_branches = ( $library2->{branchcode}, $library3->{branchcode} );
67 my $least_cost_branch_code = pop @other_branches;
68 my $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
69
70 #Set up the stage
71 # Sysprefs and cost matrix
72 t::lib::Mocks::mock_preference('HoldsQueueSkipClosed', 0);
73 t::lib::Mocks::mock_preference('LocalHoldsPriority', 0);
74 $dbh->do("UPDATE systempreferences SET value = ? WHERE variable = 'StaticHoldsQueueWeight'", undef,
75          join( ',', @other_branches, $borrower_branchcode, $least_cost_branch_code));
76 $dbh->do("UPDATE systempreferences SET value = '0' WHERE variable = 'RandomizeHoldsQueueWeight'");
77
78 $dbh->do("DELETE FROM transport_cost");
79 my $transport_cost_insert_sth = $dbh->prepare("insert into transport_cost (frombranch, tobranch, cost) values (?, ?, ?)");
80 # Favour $least_cost_branch_code
81 $transport_cost_insert_sth->execute($borrower_branchcode, $least_cost_branch_code, 0.2);
82 $transport_cost_insert_sth->execute($least_cost_branch_code, $borrower_branchcode, 0.2);
83 my @b = @other_branches;
84 while ( my $b1 = shift @b ) {
85     foreach my $b2 ($borrower_branchcode, $least_cost_branch_code, @b) {
86         $transport_cost_insert_sth->execute($b1, $b2, 0.5);
87         $transport_cost_insert_sth->execute($b2, $b1, 0.5);
88     }
89 }
90
91
92 # Loanable items - all possible combinations of homebranch and holdingbranch
93 $dbh->do("INSERT INTO biblio (frameworkcode, author, title, datecreated)
94           VALUES             ('SER', 'Koha test', '$TITLE', '2011-02-01')");
95 my $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$TITLE'")
96   or BAIL_OUT("Cannot find newly created biblio record");
97 $dbh->do("INSERT INTO biblioitems (biblionumber, itemtype)
98           VALUES                  ($biblionumber, '$itemtype')");
99 my $biblioitemnumber = $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber")
100   or BAIL_OUT("Cannot find newly created biblioitems record");
101
102 my $items_insert_sth = $dbh->prepare("INSERT INTO items (biblionumber, biblioitemnumber, barcode, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype)
103                                       VALUES            ($biblionumber, $biblioitemnumber, ?, ?, ?, 0, 0, 0, 0, NULL, '$itemtype')"); # CURRENT_DATE - 3)");
104 my $first_barcode = int(rand(1000000000000)); # XXX
105 my $barcode = $first_barcode;
106 foreach ( $borrower_branchcode, $least_cost_branch_code, @other_branches ) {
107     $items_insert_sth->execute($barcode++, $borrower_branchcode, $_);
108     $items_insert_sth->execute($barcode++, $_, $_);
109     $items_insert_sth->execute($barcode++, $_, $borrower_branchcode);
110 }
111
112 # Remove existing reserves, makes debugging easier
113 $dbh->do("DELETE FROM reserves");
114 my $bibitems = undef;
115 my $priority = 1;
116 # Make a reserve
117 AddReserve(
118     {
119         branchcode     => $borrower_branchcode,
120         borrowernumber => $borrowernumber,
121         biblionumber   => $biblionumber,
122         priority       => $priority,
123     }
124 );
125 #                           $resdate, $expdate, $notes, $title, $checkitem, $found
126 $dbh->do("UPDATE reserves SET reservedate = DATE_SUB( reservedate, INTERVAL 1 DAY )");
127
128 # Tests
129 my $use_cost_matrix_sth = $dbh->prepare("UPDATE systempreferences SET value = ? WHERE variable = 'UseTransportCostMatrix'");
130 my $test_sth = $dbh->prepare("SELECT * FROM hold_fill_targets
131                               JOIN tmp_holdsqueue USING (borrowernumber, biblionumber, itemnumber)
132                               JOIN items USING (itemnumber)
133                               WHERE borrowernumber = $borrowernumber");
134
135 # We have a book available homed in borrower branch, no point fiddling with AutomaticItemReturn
136 t::lib::Mocks::mock_preference('AutomaticItemReturn', 0);
137 test_queue ('take from homebranch',  0, $borrower_branchcode, $borrower_branchcode);
138 test_queue ('take from homebranch',  1, $borrower_branchcode, $borrower_branchcode);
139
140 $dbh->do("DELETE FROM tmp_holdsqueue");
141 $dbh->do("DELETE FROM hold_fill_targets");
142 $dbh->do("DELETE FROM issues WHERE itemnumber IN (SELECT itemnumber FROM items WHERE homebranch = '$borrower_branchcode' AND holdingbranch = '$borrower_branchcode')");
143 $dbh->do("DELETE FROM items WHERE homebranch = '$borrower_branchcode' AND holdingbranch = '$borrower_branchcode'");
144 # test_queue will flush
145 t::lib::Mocks::mock_preference('AutomaticItemReturn', 1);
146 # Not sure how to make this test more difficult - holding branch does not matter
147
148 $dbh->do("DELETE FROM tmp_holdsqueue");
149 $dbh->do("DELETE FROM hold_fill_targets");
150 $dbh->do("DELETE FROM issues WHERE itemnumber IN (SELECT itemnumber FROM items WHERE homebranch = '$borrower_branchcode')");
151 $dbh->do("DELETE FROM items WHERE homebranch = '$borrower_branchcode'");
152 t::lib::Mocks::mock_preference('AutomaticItemReturn', 0);
153 # We have a book available held in borrower branch
154 test_queue ('take from holdingbranch', 0, $borrower_branchcode, $borrower_branchcode);
155 test_queue ('take from holdingbranch', 1, $borrower_branchcode, $borrower_branchcode);
156
157 $dbh->do("DELETE FROM tmp_holdsqueue");
158 $dbh->do("DELETE FROM hold_fill_targets");
159 $dbh->do("DELETE FROM issues WHERE itemnumber IN (SELECT itemnumber FROM items WHERE holdingbranch = '$borrower_branchcode')");
160 $dbh->do("DELETE FROM items WHERE holdingbranch = '$borrower_branchcode'");
161 # No book available in borrower branch, pick according to the rules
162 # Frst branch from StaticHoldsQueueWeight
163 test_queue ('take from lowest cost branch', 0, $borrower_branchcode, $other_branches[0]);
164 test_queue ('take from lowest cost branch', 1, $borrower_branchcode, $least_cost_branch_code);
165 my $queue = C4::HoldsQueue::GetHoldsQueueItems($least_cost_branch_code) || [];
166 my $queue_item = $queue->[0];
167 ok( $queue_item
168  && $queue_item->{pickbranch} eq $borrower_branchcode
169  && $queue_item->{holdingbranch} eq $least_cost_branch_code, "GetHoldsQueueItems" )
170   or diag( "Expected item for pick $borrower_branchcode, hold $least_cost_branch_code, got ".Dumper($queue_item) );
171 ok( exists($queue_item->{itype}), 'item type included in queued items list (bug 5825)' );
172
173 ok(
174     C4::HoldsQueue::least_cost_branch( 'B', [ 'A', 'B', 'C' ] ) eq 'B',
175     'C4::HoldsQueue::least_cost_branch returns the local branch if it is in the list of branches to pull from'
176 );
177
178 # XXX All this tests are for borrower branch pick-up.
179 # Maybe needs expanding to homebranch or holdingbranch pick-up.
180
181 $schema->txn_rollback;
182 $schema->txn_begin;
183
184 ### Test holds queue builder does not violate holds policy ###
185
186 # Clear out existing rules relating to holdallowed
187 $dbh->do("DELETE FROM circulation_rules");
188
189 t::lib::Mocks::mock_preference('UseTransportCostMatrix', 0);
190
191 $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
192
193 $library1 = $builder->build({
194     source => 'Branch',
195 });
196 $library2 = $builder->build({
197     source => 'Branch',
198 });
199 $library3 = $builder->build({
200     source => 'Branch',
201 });
202 @branchcodes = ( $library1->{branchcode}, $library2->{branchcode}, $library3->{branchcode} );
203
204 my $category = $builder->build({ source => 'Category', value => {exclude_from_local_holds_priority => 0} } );
205
206 my $borrower1 = $builder->build({
207     source => 'Borrower',
208     value => {
209         branchcode => $branchcodes[0],
210         categorycode => $category->{categorycode},
211     },
212 });
213 my $borrower2 = $builder->build({
214     source => 'Borrower',
215     value => {
216         branchcode => $branchcodes[1],
217         categorycode => $category->{categorycode},
218     },
219 });
220 my $borrower3 = $builder->build({
221     source => 'Borrower',
222     value => {
223         branchcode => $branchcodes[2],
224         categorycode => $category->{categorycode},
225     },
226 });
227
228 $dbh->do(qq{
229     INSERT INTO biblio (
230         frameworkcode,
231         author,
232         title,
233         datecreated
234     ) VALUES (
235         'SER',
236         'Koha test',
237         '$TITLE',
238         '2011-02-01'
239     )
240 });
241 $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$TITLE'")
242   or BAIL_OUT("Cannot find newly created biblio record");
243
244 $dbh->do(qq{
245     INSERT INTO biblioitems (
246         biblionumber,
247         itemtype
248     ) VALUES (
249         $biblionumber,
250         '$itemtype'
251     )
252 });
253 $biblioitemnumber = $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber")
254   or BAIL_OUT("Cannot find newly created biblioitems record");
255
256 $items_insert_sth = $dbh->prepare(qq{
257     INSERT INTO items (
258         biblionumber,
259         biblioitemnumber,
260         barcode,
261         homebranch,
262         holdingbranch,
263         notforloan,
264         damaged,
265         itemlost,
266         withdrawn,
267         onloan,
268         itype,
269         exclude_from_local_holds_priority
270     ) VALUES (
271         $biblionumber,
272         $biblioitemnumber,
273         ?,
274         ?,
275         ?,
276         0,
277         0,
278         0,
279         0,
280         NULL,
281         '$itemtype',
282         0
283     )
284 });
285 # Create 3 items from 2 branches ( branches are for borrowers 1 and 2 respectively )
286 $barcode = int( rand(1000000000000) );
287 $items_insert_sth->execute( $barcode + 0, $branchcodes[0], $branchcodes[0] );
288 $items_insert_sth->execute( $barcode + 1, $branchcodes[1], $branchcodes[1] );
289 $items_insert_sth->execute( $barcode + 2, $branchcodes[1], $branchcodes[1] );
290
291 $dbh->do("DELETE FROM reserves");
292 my $sth = $dbh->prepare(q{
293     INSERT INTO reserves (
294         borrowernumber,
295         biblionumber,
296         branchcode,
297         priority,
298         reservedate
299     ) VALUES ( ?,?,?,?, CURRENT_DATE() )
300 });
301 $sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
302 $sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
303 $sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
304
305 my $holds_queue;
306
307 $dbh->do("DELETE FROM circulation_rules");
308 Koha::CirculationRules->set_rule(
309     {
310         rule_name    => 'holdallowed',
311         rule_value   => 1,
312         branchcode   => undef,
313         itemtype     => undef,
314     }
315 );
316 C4::HoldsQueue::CreateQueue();
317 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
318 is( @$holds_queue, 2, "Holds queue filling correct number for default holds policy 'from home library'" );
319 is( $holds_queue->[0]->{cardnumber}, $borrower1->{cardnumber}, "Holds queue filling 1st correct hold for default holds policy 'from home library'");
320 is( $holds_queue->[1]->{cardnumber}, $borrower2->{cardnumber}, "Holds queue filling 2nd correct hold for default holds policy 'from home library'");
321
322 # Test skipping hold picks for closed libraries.
323 # At this point in the test, we have 2 rows in the holds queue
324 # 1 of which is coming from MPL. Let's enable HoldsQueueSkipClosed
325 # and make today a holiday for MPL. When we run it again we should only
326 # have 1 row in the holds queue
327 t::lib::Mocks::mock_preference('HoldsQueueSkipClosed', 1);
328 my $today = dt_from_string();
329 C4::Calendar->new( branchcode => $branchcodes[0] )->insert_single_holiday(
330     day         => $today->day(),
331     month       => $today->month(),
332     year        => $today->year(),
333     title       => "$today",
334     description => "$today",
335 );
336 # If the test below is removed, aother tests using the holiday will fail. For some reason if we call is_holiday now
337 # the holiday will get set in cache correctly, but not if we let C4::HoldsQueue call is_holiday instead.
338 is( Koha::Calendar->new( branchcode => $branchcodes[0] )->is_holiday( $today ), 1, 'Is today a holiday for pickup branch' );
339 C4::HoldsQueue::CreateQueue();
340 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
341 is( scalar( @$holds_queue ), 1, "Holds not filled with items from closed libraries" );
342 t::lib::Mocks::mock_preference('HoldsQueueSkipClosed', 0);
343
344 $dbh->do("DELETE FROM circulation_rules");
345 Koha::CirculationRules->set_rule(
346     {
347         rule_name    => 'holdallowed',
348         rule_value   => 2,
349         branchcode   => undef,
350         itemtype     => undef,
351     }
352 );
353 C4::HoldsQueue::CreateQueue();
354 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
355 is( @$holds_queue, 3, "Holds queue filling correct number for holds for default holds policy 'from any library'" );
356
357 # Test skipping hold picks for closed libraries without transport cost matrix
358 # At this point in the test, we have 3 rows in the holds queue
359 # one of which is coming from MPL. Let's enable HoldsQueueSkipClosed
360 # and use our previously created holiday for MPL
361 # When we run it again we should only have 2 rows in the holds queue
362 t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 1 );
363 C4::HoldsQueue::CreateQueue();
364 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
365 is( scalar( @$holds_queue ), 2, "Holds not filled with items from closed libraries" );
366 t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 0 );
367
368 ## Test LocalHoldsPriority
369 t::lib::Mocks::mock_preference('LocalHoldsPriority', 1);
370
371 $dbh->do("DELETE FROM circulation_rules");
372 Koha::CirculationRules->set_rule(
373     {
374         rule_name    => 'holdallowed',
375         rule_value   => 2,
376         branchcode   => undef,
377         itemtype     => undef,
378     }
379 );
380 $dbh->do("DELETE FROM issues");
381
382 # Test homebranch = patron branch
383 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
384 t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
385 C4::Context->clear_syspref_cache();
386 $dbh->do("DELETE FROM reserves");
387 $sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
388 $sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
389 $sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
390
391 $dbh->do("DELETE FROM items");
392 # barcode, homebranch, holdingbranch, itemtype
393 $items_insert_sth->execute( $barcode + 4, $branchcodes[2], $branchcodes[0] );
394
395 C4::HoldsQueue::CreateQueue();
396 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
397 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue giving priority to patron who's home library matches item's home library");
398
399 ### Test branch transfer limits ###
400 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
401 t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
402 t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
403 C4::Context->clear_syspref_cache();
404 $dbh->do("DELETE FROM reserves");
405 $sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
406 $sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[1], 2 );
407
408 $dbh->do("DELETE FROM items");
409 # barcode, homebranch, holdingbranch, itemtype
410 $items_insert_sth->execute( $barcode, $branchcodes[2], $branchcodes[2] );
411 my $item = Koha::Items->find( { barcode => $barcode } );
412
413 my $limit1 = Koha::Item::Transfer::Limit->new(
414     {
415         toBranch   => $branchcodes[0],
416         fromBranch => $branchcodes[2],
417         itemtype   => $item->effective_itemtype,
418     }
419 )->store();
420
421 C4::HoldsQueue::CreateQueue();
422 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
423 is( $holds_queue->[0]->{cardnumber}, $borrower2->{cardnumber}, "Holds queue skips hold transfer that would violate branch transfer limits");
424
425 my $limit2 = Koha::Item::Transfer::Limit->new(
426     {
427         toBranch   => $branchcodes[1],
428         fromBranch => $branchcodes[2],
429         itemtype   => $item->effective_itemtype,
430     }
431 )->store();
432
433 C4::HoldsQueue::CreateQueue();
434 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
435 is( $holds_queue->[0]->{cardnumber}, undef, "Holds queue doesn't fill hold where all available items would violate branch transfer limits");
436
437 $limit1->delete();
438 $limit2->delete();
439 t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '0' );
440 ### END Test branch transfer limits ###
441
442 # Test holdingbranch = patron branch
443 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'HomeLibrary');
444 t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
445 C4::Context->clear_syspref_cache();
446 $dbh->do("DELETE FROM reserves");
447 $sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
448 $sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
449 $sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[0], 3 );
450
451 $dbh->do("DELETE FROM items");
452 # barcode, homebranch, holdingbranch, itemtype
453 $items_insert_sth->execute( $barcode + 4, $branchcodes[0], $branchcodes[2] );
454
455 C4::HoldsQueue::CreateQueue();
456 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
457 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue giving priority to patron who's home library matches item's holding library");
458
459 # Test holdingbranch = pickup branch
460 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
461 t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'holdingbranch');
462 C4::Context->clear_syspref_cache();
463 $dbh->do("DELETE FROM reserves");
464 $sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
465 $sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
466 $sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
467
468 $dbh->do("DELETE FROM items");
469 # barcode, homebranch, holdingbranch, itemtype
470 $items_insert_sth->execute( $barcode + 4, $branchcodes[0], $branchcodes[2] );
471
472 C4::HoldsQueue::CreateQueue();
473 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
474 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue giving priority to patron who's home library matches item's holding library");
475
476 # Test homebranch = pickup branch
477 t::lib::Mocks::mock_preference('LocalHoldsPriorityPatronControl', 'PickupLibrary');
478 t::lib::Mocks::mock_preference('LocalHoldsPriorityItemControl', 'homebranch');
479 C4::Context->clear_syspref_cache();
480 $dbh->do("DELETE FROM reserves");
481 $sth->execute( $borrower1->{borrowernumber}, $biblionumber, $branchcodes[0], 1 );
482 $sth->execute( $borrower2->{borrowernumber}, $biblionumber, $branchcodes[0], 2 );
483 $sth->execute( $borrower3->{borrowernumber}, $biblionumber, $branchcodes[2], 3 );
484
485 $dbh->do("DELETE FROM items");
486 # barcode, homebranch, holdingbranch, itemtype
487 $items_insert_sth->execute( $barcode + 4, $branchcodes[2], $branchcodes[0] );
488
489 C4::HoldsQueue::CreateQueue();
490 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
491 is( $holds_queue->[0]->{cardnumber}, $borrower3->{cardnumber}, "Holds queue giving priority to patron who's home library matches item's holding library");
492
493 t::lib::Mocks::mock_preference('LocalHoldsPriority', 0);
494 ## End testing of LocalHoldsPriority
495
496
497 # Bug 14297
498 $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
499 $borrowernumber = $borrower3->{borrowernumber};
500 my $library_A = $library1->{branchcode};
501 my $library_B = $library2->{branchcode};
502 my $library_C = $borrower3->{branchcode};
503 $dbh->do("DELETE FROM reserves");
504 $dbh->do("DELETE FROM issues");
505 $dbh->do("DELETE FROM items");
506 $dbh->do("DELETE FROM biblio");
507 $dbh->do("DELETE FROM biblioitems");
508 $dbh->do("DELETE FROM transport_cost");
509 $dbh->do("DELETE FROM tmp_holdsqueue");
510 $dbh->do("DELETE FROM hold_fill_targets");
511
512 $dbh->do("
513     INSERT INTO biblio (frameworkcode, author, title, datecreated) VALUES ('', 'Koha test', '$TITLE', '2011-02-01')
514 ");
515
516 $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$TITLE'")
517   or BAIL_OUT("Cannot find newly created biblio record");
518
519 $dbh->do("INSERT INTO biblioitems (biblionumber, itemtype) VALUES ($biblionumber, '$itemtype')");
520
521 $biblioitemnumber =
522   $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber")
523   or BAIL_OUT("Cannot find newly created biblioitems record");
524
525 $dbh->do("
526     INSERT INTO items (biblionumber, biblioitemnumber, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype, exclude_from_local_holds_priority)
527     VALUES ($biblionumber, $biblioitemnumber, '$library_A', '$library_A', 0, 0, 0, 0, NULL, '$itemtype', 0)
528 ");
529
530 $dbh->do("
531     INSERT INTO items (biblionumber, biblioitemnumber, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype, exclude_from_local_holds_priority)
532     VALUES ($biblionumber, $biblioitemnumber, '$library_B', '$library_B', 0, 0, 0, 0, NULL, '$itemtype', 0)
533 ");
534
535 Koha::CirculationRules->set_rules(
536     {
537         branchcode   => $library_A,
538         itemtype     => $itemtype,
539         rules        => {
540             holdallowed  => 2,
541             returnbranch => 'homebranch',
542         }
543     }
544 );
545
546 $dbh->do( "UPDATE systempreferences SET value = ? WHERE variable = 'StaticHoldsQueueWeight'",
547     undef, join( ',', $library_B, $library_A, $library_C ) );
548 $dbh->do( "UPDATE systempreferences SET value = 0 WHERE variable = 'RandomizeHoldsQueueWeight'" );
549
550 my $reserve_id = AddReserve(
551     {
552         branchcode     => $library_C,
553         borrowernumber => $borrowernumber,
554         biblionumber   => $biblionumber,
555         priority       => 1,
556     }
557 );
558 C4::HoldsQueue::CreateQueue();
559 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
560 is( @$holds_queue, 1, "Bug 14297 - Holds Queue building ignoring holds where pickup & home branch don't match and item is not from le");
561 # End Bug 14297
562
563 # Bug 15062
564 $itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
565 $borrowernumber = $borrower2->{borrowernumber};
566 $library_A = $library1->{branchcode};
567 $library_B = $library2->{branchcode};
568 $dbh->do("DELETE FROM reserves");
569 $dbh->do("DELETE FROM issues");
570 $dbh->do("DELETE FROM items");
571 $dbh->do("DELETE FROM biblio");
572 $dbh->do("DELETE FROM biblioitems");
573 $dbh->do("DELETE FROM transport_cost");
574 $dbh->do("DELETE FROM tmp_holdsqueue");
575 $dbh->do("DELETE FROM hold_fill_targets");
576
577 t::lib::Mocks::mock_preference("UseTransportCostMatrix",1);
578
579 my $tc_rs = $schema->resultset('TransportCost');
580 $tc_rs->create({ frombranch => $library_A, tobranch => $library_B, cost => 0, disable_transfer => 1 });
581 $tc_rs->create({ frombranch => $library_B, tobranch => $library_A, cost => 0, disable_transfer => 1 });
582
583 $dbh->do("
584     INSERT INTO biblio (frameworkcode, author, title, datecreated) VALUES ('', 'Koha test', '$TITLE', '2011-02-01')
585 ");
586
587 $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$TITLE'")
588   or BAIL_OUT("Cannot find newly created biblio record");
589
590 $dbh->do("INSERT INTO biblioitems (biblionumber, itemtype) VALUES ($biblionumber, '$itemtype')");
591
592 $biblioitemnumber =
593   $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber")
594   or BAIL_OUT("Cannot find newly created biblioitems record");
595
596 $dbh->do("
597     INSERT INTO items (biblionumber, biblioitemnumber, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype, exclude_from_local_holds_priority)
598     VALUES ($biblionumber, $biblioitemnumber, '$library_A', '$library_A', 0, 0, 0, 0, NULL, '$itemtype', 0)
599 ");
600
601 $reserve_id = AddReserve(
602     {
603         branchcode     => $library_B,
604         borrowernumber => $borrowernumber,
605         biblionumber   => $biblionumber,
606         priority       => 1,
607     }
608 );
609
610 C4::HoldsQueue::CreateQueue();
611 $holds_queue = $dbh->selectall_arrayref("SELECT * FROM tmp_holdsqueue", { Slice => {} });
612 is( @$holds_queue, 0, "Bug 15062 - Holds queue with Transport Cost Matrix will transfer item even if transfers disabled");
613 # End Bug 15062
614
615 # Test hold_fulfillment_policy
616 t::lib::Mocks::mock_preference( "UseTransportCostMatrix", 0 );
617 $borrowernumber = $borrower3->{borrowernumber};
618 $library_A = $library1->{branchcode};
619 $library_B = $library2->{branchcode};
620 $library_C = $library3->{branchcode};
621 $dbh->do("DELETE FROM reserves");
622 $dbh->do("DELETE FROM issues");
623 $dbh->do("DELETE FROM items");
624 $dbh->do("DELETE FROM biblio");
625 $dbh->do("DELETE FROM biblioitems");
626 $dbh->do("DELETE FROM transport_cost");
627 $dbh->do("DELETE FROM tmp_holdsqueue");
628 $dbh->do("DELETE FROM hold_fill_targets");
629
630 $dbh->do("INSERT INTO biblio (frameworkcode, author, title, datecreated) VALUES ('', 'Koha test', '$TITLE', '2011-02-01')");
631
632 $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$TITLE'")
633   or BAIL_OUT("Cannot find newly created biblio record");
634
635 $dbh->do("INSERT INTO biblioitems (biblionumber, itemtype) VALUES ($biblionumber, '$itemtype')");
636
637 $biblioitemnumber =
638   $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber")
639   or BAIL_OUT("Cannot find newly created biblioitems record");
640
641 $dbh->do("
642     INSERT INTO items (biblionumber, biblioitemnumber, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype, exclude_from_local_holds_priority)
643     VALUES ($biblionumber, $biblioitemnumber, '$library_A', '$library_B', 0, 0, 0, 0, NULL, '$itemtype', 0)
644 ");
645
646 # With hold_fulfillment_policy = homebranch, hold should only be picked up if pickup branch = homebranch
647 $dbh->do("DELETE FROM circulation_rules");
648 Koha::CirculationRules->set_rules(
649     {
650         branchcode   => undef,
651         itemtype     => undef,
652         rules        => {
653             holdallowed             => 2,
654             hold_fulfillment_policy => 'homebranch',
655         }
656     }
657 );
658
659 # Home branch matches pickup branch
660 $reserve_id = AddReserve(
661     {
662         branchcode     => $library_A,
663         borrowernumber => $borrowernumber,
664         biblionumber   => $biblionumber,
665         priority       => 1,
666     }
667 );
668
669 C4::HoldsQueue::CreateQueue();
670 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
671 is( @$holds_queue, 1, "Hold where pickup branch matches home branch targeted" );
672 my $target_rs = $schema->resultset('HoldFillTarget');
673 is( $target_rs->next->reserve_id, $reserve_id, "Reserve id correctly set in hold fill target for title level hold" );
674 Koha::Holds->find( $reserve_id )->cancel;
675
676 # Holding branch matches pickup branch
677 $reserve_id = AddReserve(
678     {
679         branchcode     => $library_B,
680         borrowernumber => $borrowernumber,
681         biblionumber   => $biblionumber,
682         priority       => 1,
683     }
684 );
685
686
687 C4::HoldsQueue::CreateQueue();
688 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
689 is( @$holds_queue, 0, "Hold where pickup ne home, pickup eq home not targeted" );
690 Koha::Holds->find( $reserve_id )->cancel;
691
692 # Neither branch matches pickup branch
693 $reserve_id = AddReserve(
694     {
695         branchcode     => $library_C,
696         borrowernumber => $borrowernumber,
697         biblionumber   => $biblionumber,
698         priority       => 1,
699     }
700 );
701
702 C4::HoldsQueue::CreateQueue();
703 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
704 is( @$holds_queue, 0, "Hold where pickup ne home, pickup ne holding not targeted" );
705 Koha::Holds->find( $reserve_id )->cancel;
706
707 # With hold_fulfillment_policy = holdingbranch, hold should only be picked up if pickup branch = holdingbranch
708 $dbh->do("DELETE FROM circulation_rules");
709 Koha::CirculationRules->set_rules(
710     {
711         branchcode   => undef,
712         itemtype     => undef,
713         rules        => {
714             holdallowed             => 2,
715             hold_fulfillment_policy => 'holdingbranch',
716         }
717     }
718 );
719
720 # Home branch matches pickup branch
721 $reserve_id = AddReserve(
722     {
723         branchcode     => $library_A,
724         borrowernumber => $borrowernumber,
725         biblionumber   => $biblionumber,
726         priority       => 1,
727     }
728 );
729
730 C4::HoldsQueue::CreateQueue();
731 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
732 is( @$holds_queue, 0, "Hold where pickup eq home, pickup ne holding not targeted" );
733 Koha::Holds->find( $reserve_id )->cancel;
734
735 # Holding branch matches pickup branch
736 $reserve_id = AddReserve(
737     {
738         branchcode     => $library_B,
739         borrowernumber => $borrowernumber,
740         biblionumber   => $biblionumber,
741         priority       => 1,
742     }
743 );
744
745 C4::HoldsQueue::CreateQueue();
746 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
747 is( @$holds_queue, 1, "Hold where pickup ne home, pickup eq holding targeted" );
748 Koha::Holds->find( $reserve_id )->cancel;
749
750 # Neither branch matches pickup branch
751 $reserve_id = AddReserve(
752     {
753         branchcode     => $library_C,
754         borrowernumber => $borrowernumber,
755         biblionumber   => $biblionumber,
756         priority       => 1,
757     }
758 );
759
760 C4::HoldsQueue::CreateQueue();
761 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
762 is( @$holds_queue, 0, "Hold where pickup ne home, pickup ne holding not targeted" );
763 Koha::Holds->find( $reserve_id )->cancel;
764
765 # With hold_fulfillment_policy = any, hold should be pikcup up reguardless of matching home or holding branch
766 $dbh->do("DELETE FROM circulation_rules");
767 Koha::CirculationRules->set_rules(
768     {
769         branchcode   => undef,
770         itemtype     => undef,
771         rules        => {
772             holdallowed             => 2,
773             hold_fulfillment_policy => 'any',
774         }
775     }
776 );
777
778 # Home branch matches pickup branch
779 $reserve_id = AddReserve(
780     {
781         branchcode     => $library_A,
782         borrowernumber => $borrowernumber,
783         biblionumber   => $biblionumber,
784         priority       => 1,
785     }
786 );
787
788 C4::HoldsQueue::CreateQueue();
789 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
790 is( @$holds_queue, 1, "Hold where pickup eq home, pickup ne holding targeted" );
791 Koha::Holds->find( $reserve_id )->cancel;
792
793 # Holding branch matches pickup branch
794 $reserve_id = AddReserve(
795     {
796         branchcode     => $library_B,
797         borrowernumber => $borrowernumber,
798         biblionumber   => $biblionumber,
799         priority       => 1,
800     }
801 );
802
803 C4::HoldsQueue::CreateQueue();
804 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
805 is( @$holds_queue, 1, "Hold where pickup ne home, pickup eq holding targeted" );
806 Koha::Holds->find( $reserve_id )->cancel;
807
808 # Neither branch matches pickup branch
809 $reserve_id = AddReserve(
810     {
811         branchcode     => $library_C,
812         borrowernumber => $borrowernumber,
813         biblionumber   => $biblionumber,
814         priority       => 1,
815     }
816 );
817
818 C4::HoldsQueue::CreateQueue();
819 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
820 is( @$holds_queue, 1, "Hold where pickup ne home, pickup ne holding targeted" );
821 Koha::Holds->find( $reserve_id )->cancel;
822
823 # End testing hold_fulfillment_policy
824
825 # Test hold itemtype limit
826 t::lib::Mocks::mock_preference( "UseTransportCostMatrix", 0 );
827 my $wrong_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
828 my $right_itemtype = $builder->build({ source => 'Itemtype', value => { notforloan => 0 } })->{itemtype};
829 $borrowernumber = $borrower3->{borrowernumber};
830 my $branchcode = $library1->{branchcode};
831 $dbh->do("DELETE FROM reserves");
832 $dbh->do("DELETE FROM issues");
833 $dbh->do("DELETE FROM items");
834 $dbh->do("DELETE FROM biblio");
835 $dbh->do("DELETE FROM biblioitems");
836 $dbh->do("DELETE FROM transport_cost");
837 $dbh->do("DELETE FROM tmp_holdsqueue");
838 $dbh->do("DELETE FROM hold_fill_targets");
839
840 $dbh->do("INSERT INTO biblio (frameworkcode, author, title, datecreated) VALUES ('', 'Koha test', '$TITLE', '2011-02-01')");
841
842 $biblionumber = $dbh->selectrow_array("SELECT biblionumber FROM biblio WHERE title = '$TITLE'")
843   or BAIL_OUT("Cannot find newly created biblio record");
844
845 $dbh->do("INSERT INTO biblioitems (biblionumber, itemtype) VALUES ($biblionumber, '$itemtype')");
846
847 $biblioitemnumber =
848   $dbh->selectrow_array("SELECT biblioitemnumber FROM biblioitems WHERE biblionumber = $biblionumber")
849   or BAIL_OUT("Cannot find newly created biblioitems record");
850
851 $dbh->do("
852     INSERT INTO items (biblionumber, biblioitemnumber, homebranch, holdingbranch, notforloan, damaged, itemlost, withdrawn, onloan, itype, exclude_from_local_holds_priority)
853     VALUES ($biblionumber, $biblioitemnumber, '$library_A', '$library_B', 0, 0, 0, 0, NULL, '$right_itemtype', 0)
854 ");
855
856 # With hold_fulfillment_policy = homebranch, hold should only be picked up if pickup branch = homebranch
857 $dbh->do("DELETE FROM circulation_rules");
858 Koha::CirculationRules->set_rules(
859     {
860         branchcode   => undef,
861         itemtype     => undef,
862         rules        => {
863             holdallowed             => 2,
864             hold_fulfillment_policy => 'any',
865         }
866     }
867 );
868
869 # Home branch matches pickup branch
870 $reserve_id = AddReserve(
871     {
872         branchcode     => $library_A,
873         borrowernumber => $borrowernumber,
874         biblionumber   => $biblionumber,
875         priority       => 1,
876         itemtype       => $wrong_itemtype,
877     }
878 );
879
880 C4::HoldsQueue::CreateQueue();
881 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
882 is( @$holds_queue, 0, "Item with incorrect itemtype not targeted" );
883 Koha::Holds->find( $reserve_id )->cancel;
884
885 # Holding branch matches pickup branch
886 $reserve_id = AddReserve(
887     {
888         branchcode     => $library_A,
889         borrowernumber => $borrowernumber,
890         biblionumber   => $biblionumber,
891         priority       => 1,
892         itemtype       => $right_itemtype,
893     }
894 );
895
896 C4::HoldsQueue::CreateQueue();
897 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
898 is( @$holds_queue, 1, "Item with matching itemtype is targeted" );
899 Koha::Holds->find( $reserve_id )->cancel;
900
901 # Neither branch matches pickup branch
902 $reserve_id = AddReserve(
903     {
904         branchcode     => $library_A,
905         borrowernumber => $borrowernumber,
906         biblionumber   => $biblionumber,
907         priority       => 1,
908     }
909 );
910
911 C4::HoldsQueue::CreateQueue();
912 $holds_queue = $dbh->selectall_arrayref( "SELECT * FROM tmp_holdsqueue", { Slice => {} } );
913 is( @$holds_queue, 1, "Item targeted when hold itemtype is not set" );
914 Koha::Holds->find( $reserve_id )->cancel;
915
916 # End testing hold itemtype limit
917
918
919 subtest "Test Local Holds Priority - Bib level" => sub {
920     plan tests => 3;
921
922     Koha::Biblios->delete();
923     t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
924     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
925     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
926     my $branch  = $builder->build_object( { class => 'Koha::Libraries' } );
927     my $branch2 = $builder->build_object( { class => 'Koha::Libraries' } );
928     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
929     my $local_patron = $builder->build_object(
930         {
931             class => "Koha::Patrons",
932             value => {
933                 branchcode => $branch->branchcode,
934                 categorycode => $category->categorycode
935             }
936         }
937     );
938     my $other_patron = $builder->build_object(
939         {
940             class => "Koha::Patrons",
941             value => {
942                 branchcode => $branch2->branchcode,
943                 categorycode => $category->categorycode
944             }
945         }
946     );
947     my $biblio = $builder->build_sample_biblio();
948     my $item   = $builder->build_sample_item(
949         {
950             biblionumber  => $biblio->biblionumber,
951             library    => $branch->branchcode,
952             exclude_from_local_holds_priority => 0,
953         }
954     );
955
956     my $reserve_id = AddReserve(
957         {
958             branchcode     => $branch2->branchcode,
959             borrowernumber => $other_patron->borrowernumber,
960             biblionumber   => $biblio->biblionumber,
961             priority       => 1,
962         }
963     );
964     my $reserve_id2 = AddReserve(
965         {
966             branchcode     => $item->homebranch,
967             borrowernumber => $local_patron->borrowernumber,
968             biblionumber   => $biblio->biblionumber,
969             priority       => 2,
970         }
971     );
972
973     C4::HoldsQueue::CreateQueue();
974
975     my $queue_rs = $schema->resultset('TmpHoldsqueue');
976     my $target_rs = $schema->resultset('HoldFillTarget');
977     is( $queue_rs->count(), 1,
978         "Hold queue contains one hold" );
979     is(
980         $queue_rs->next->borrowernumber,
981         $local_patron->borrowernumber,
982         "We should pick the local hold over the next available"
983     );
984     is( $target_rs->next->reserve_id, $reserve_id2, "Reserve id correctly set in hold fill target" );
985 };
986
987 subtest "Test Local Holds Priority - Item level" => sub {
988     plan tests => 2;
989
990     Koha::Biblios->delete();
991     t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
992     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
993     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
994     my $branch  = $builder->build_object( { class => 'Koha::Libraries' } );
995     my $branch2 = $builder->build_object( { class => 'Koha::Libraries' } );
996     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
997     my $local_patron = $builder->build_object(
998         {
999             class => "Koha::Patrons",
1000             value => {
1001                 branchcode => $branch->branchcode,
1002                 categorycode => $category->categorycode
1003             }
1004         }
1005     );
1006     my $other_patron = $builder->build_object(
1007         {
1008             class => "Koha::Patrons",
1009             value => {
1010                 branchcode => $branch2->branchcode,
1011                 categorycode => $category->categorycode
1012             }
1013         }
1014     );
1015     my $biblio = $builder->build_sample_biblio();
1016     my $item   = $builder->build_sample_item(
1017         {
1018             biblionumber  => $biblio->biblionumber,
1019             library    => $branch->branchcode,
1020             exclude_from_local_holds_priority => 0,
1021         }
1022     );
1023
1024     my $reserve_id = AddReserve(
1025         {
1026             branchcode     => $branch2->branchcode,
1027             borrowernumber => $other_patron->borrowernumber,
1028             biblionumber   => $biblio->biblionumber,
1029             priority       => 1,
1030             itemnumber     => $item->id,
1031         }
1032     );
1033     my $reserve_id2 = AddReserve(
1034         {
1035             branchcode     => $item->homebranch,
1036             borrowernumber => $local_patron->borrowernumber,
1037             biblionumber   => $biblio->biblionumber,
1038             priority       => 2,
1039             itemnumber     => $item->id,
1040         }
1041     );
1042
1043     C4::HoldsQueue::CreateQueue();
1044
1045     my $queue_rs = $schema->resultset('TmpHoldsqueue');
1046     my $q = $queue_rs->next;
1047     is( $queue_rs->count(), 1,
1048         "Hold queue contains one hold" );
1049     is(
1050         $q->borrowernumber,
1051         $local_patron->borrowernumber,
1052         "We should pick the local hold over the next available"
1053     );
1054 };
1055
1056 subtest "Test Local Holds Priority - Item level hold over Record level hold (Bug 23934)" => sub {
1057     plan tests => 2;
1058
1059     Koha::Biblios->delete();
1060     t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
1061     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1062     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
1063     my $branch  = $builder->build_object( { class => 'Koha::Libraries' } );
1064     my $branch2 = $builder->build_object( { class => 'Koha::Libraries' } );
1065     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
1066     my $local_patron = $builder->build_object(
1067         {
1068             class => "Koha::Patrons",
1069             value => {
1070                 branchcode => $branch->branchcode,
1071                 categorycode => $category->categorycode,
1072             }
1073         }
1074     );
1075     my $other_patron = $builder->build_object(
1076         {
1077             class => "Koha::Patrons",
1078             value => {
1079                 branchcode => $branch2->branchcode,
1080                 categorycode => $category->categorycode,
1081             }
1082         }
1083     );
1084     my $biblio = $builder->build_sample_biblio();
1085     my $item   = $builder->build_sample_item(
1086         {
1087             biblionumber  => $biblio->biblionumber,
1088             library    => $branch->branchcode,
1089             exclude_from_local_holds_priority => 0,
1090         }
1091     );
1092
1093     my $reserve_id = AddReserve(
1094         {
1095             branchcode     => $branch2->branchcode,
1096             borrowernumber => $other_patron->borrowernumber,
1097             biblionumber   => $biblio->biblionumber,
1098             priority       => 1,
1099         }
1100     );
1101     my $reserve_id2 = AddReserve(
1102         {
1103             branchcode     => $item->homebranch,
1104             borrowernumber => $local_patron->borrowernumber,
1105             biblionumber   => $biblio->biblionumber,
1106             priority       => 2,
1107             itemnumber     => $item->id,
1108         }
1109     );
1110
1111     C4::HoldsQueue::CreateQueue();
1112
1113     my $queue_rs = $schema->resultset('TmpHoldsqueue');
1114     my $q = $queue_rs->next;
1115     is( $queue_rs->count(), 1,
1116         "Hold queue contains one hold" );
1117     is(
1118         $q->borrowernumber,
1119         $local_patron->borrowernumber,
1120         "We should pick the local hold over the next available"
1121     );
1122 };
1123
1124 subtest "Test Local Holds Priority - Get correct item for item level hold" => sub {
1125     plan tests => 3;
1126
1127     Koha::Biblios->delete();
1128     t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
1129     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1130     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
1131     my $branch  = $builder->build_object( { class => 'Koha::Libraries' } );
1132     my $branch2 = $builder->build_object( { class => 'Koha::Libraries' } );
1133     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
1134     my $local_patron = $builder->build_object(
1135         {
1136             class => "Koha::Patrons",
1137             value => {
1138                 branchcode => $branch->branchcode,
1139                 categorycode => $category->categorycode,
1140             }
1141         }
1142     );
1143     my $other_patron = $builder->build_object(
1144         {
1145             class => "Koha::Patrons",
1146             value => {
1147                 branchcode => $branch2->branchcode,
1148                 categorycode => $category->categorycode,
1149             }
1150         }
1151     );
1152     my $biblio = $builder->build_sample_biblio();
1153
1154     my $item1 = $builder->build_sample_item(
1155         {
1156             biblionumber  => $biblio->biblionumber,
1157             library    => $branch->branchcode,
1158             exclude_from_local_holds_priority => 0,
1159         }
1160     );
1161     my $item2 = $builder->build_sample_item(
1162         {
1163             biblionumber  => $biblio->biblionumber,
1164             library    => $branch->branchcode,
1165             exclude_from_local_holds_priority => 0,
1166         }
1167     );
1168     my $item3 = $builder->build_sample_item(
1169         {
1170             biblionumber  => $biblio->biblionumber,
1171             library    => $branch->branchcode,
1172             exclude_from_local_holds_priority => 0,
1173         }
1174     );
1175
1176     my $reserve_id2 =
1177         AddReserve(
1178             {
1179                 branchcode     => $item2->homebranch,
1180                 borrowernumber => $local_patron->borrowernumber,
1181                 biblionumber   => $biblio->biblionumber,
1182                 priority       => 2,
1183                 itemnumber     => $item2->id,
1184             }
1185         );
1186
1187
1188     C4::HoldsQueue::CreateQueue();
1189
1190     my $queue_rs = $schema->resultset('TmpHoldsqueue');
1191     my $q = $queue_rs->next;
1192     is( $queue_rs->count(), 1,
1193         "Hold queue contains one hold" );
1194     is(
1195         $q->borrowernumber,
1196         $local_patron->borrowernumber,
1197         "We should pick the local hold over the next available"
1198     );
1199     is( $q->itemnumber->id, $item2->id, "Got the correct item for item level local holds priority" );
1200 };
1201
1202 subtest "Test Local Holds Priority - Ensure no duplicate requests in holds queue (Bug 18001)" => sub {
1203     plan tests => 1;
1204
1205     $dbh->do("DELETE FROM tmp_holdsqueue");
1206     $dbh->do("DELETE FROM hold_fill_targets");
1207     $dbh->do("DELETE FROM reserves");
1208     $dbh->do("DELETE FROM circulation_rules");
1209     Koha::Biblios->delete();
1210
1211     t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
1212     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1213     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
1214     my $branch  = $builder->build_object( { class => 'Koha::Libraries' } );
1215     my $branch2 = $builder->build_object( { class => 'Koha::Libraries' } );
1216     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
1217     my $patron  = $builder->build_object(
1218         {
1219             class => "Koha::Patrons",
1220             value => {
1221                 branchcode => $branch->branchcode,
1222                 categorycode => $category->categorycode,
1223             }
1224         }
1225     );
1226     my $biblio = $builder->build_sample_biblio();
1227     my $item1  = $builder->build_sample_item(
1228         {
1229             biblionumber => $biblio->biblionumber,
1230             library      => $branch->branchcode,
1231             exclude_from_local_holds_priority => 0,
1232         }
1233     );
1234     my $item2 = $builder->build_sample_item(
1235         {
1236             biblionumber => $biblio->biblionumber,
1237             library      => $branch->branchcode,
1238             exclude_from_local_holds_priority => 0,
1239         }
1240     );
1241
1242     my $item3 = $builder->build_sample_item(
1243         {
1244             biblionumber => $biblio->biblionumber,
1245             library      => $branch->branchcode,
1246             exclude_from_local_holds_priority => 0,
1247         }
1248     );
1249
1250     $reserve_id = AddReserve(
1251         {
1252             branchcode     => $item1->homebranch,
1253             borrowernumber => $patron->borrowernumber,
1254             biblionumber   => $biblio->id,
1255             priority       => 1
1256         }
1257     );
1258
1259     C4::HoldsQueue::CreateQueue();
1260
1261     my $queue_rs = $schema->resultset('TmpHoldsqueue');
1262
1263     is( $queue_rs->count(), 1,
1264         "Hold queue contains one hold from chosen from three possible items" );
1265 };
1266
1267
1268 subtest "Item level holds info is preserved (Bug 25738)" => sub {
1269
1270     plan tests => 4;
1271
1272     $dbh->do("DELETE FROM tmp_holdsqueue");
1273     $dbh->do("DELETE FROM hold_fill_targets");
1274     $dbh->do("DELETE FROM reserves");
1275     $dbh->do("DELETE FROM circulation_rules");
1276
1277     my $library  = $builder->build_object({ class => 'Koha::Libraries' });
1278     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
1279     my $patron_1 = $builder->build_object(
1280         {
1281             class => "Koha::Patrons",
1282             value => {
1283                 branchcode => $library->branchcode,
1284                 categorycode => $category->categorycode
1285             }
1286         }
1287     );
1288
1289     my $patron_2 = $builder->build_object(
1290         {
1291             class => "Koha::Patrons",
1292             value => {
1293                 branchcode => $library->branchcode,
1294                 categorycode => $category->categorycode
1295             }
1296         }
1297     );
1298
1299     my $biblio = $builder->build_sample_biblio();
1300     my $item_1 = $builder->build_sample_item(
1301         {
1302             biblionumber => $biblio->biblionumber,
1303             library      => $library->branchcode,
1304             exclude_from_local_holds_priority => 0,
1305         }
1306     );
1307     my $item_2 = $builder->build_sample_item(
1308         {
1309             biblionumber => $biblio->biblionumber,
1310             library      => $library->branchcode,
1311             exclude_from_local_holds_priority => 0,
1312         }
1313     );
1314
1315     # Add item-level hold for patron_1
1316     my $reserve_id_1 = AddReserve(
1317         {
1318             branchcode     => $library->branchcode,
1319             borrowernumber => $patron_1->borrowernumber,
1320             biblionumber   => $biblio->id,
1321             itemnumber     => $item_1->itemnumber,
1322             priority       => 1
1323         }
1324     );
1325
1326     my $reserve_id_2 = AddReserve(
1327         {
1328             branchcode     => $library->branchcode,
1329             borrowernumber => $patron_2->borrowernumber,
1330             biblionumber   => $biblio->id,
1331             priority       => 2
1332         }
1333     );
1334
1335     C4::HoldsQueue::CreateQueue();
1336
1337     my $queue_rs = $schema->resultset('TmpHoldsqueue');
1338
1339     is( $queue_rs->count(), 2, "Hold queue contains two holds" );
1340
1341     my $queue_line_1 = $queue_rs->next;
1342     is( $queue_line_1->item_level_request, 1, 'Request is correctly advertised as item-level' );
1343     my $target_rs = $schema->resultset('HoldFillTarget')->search({borrowernumber=>$patron_1->borrowernumber});;
1344     is( $target_rs->next->reserve_id, $reserve_id_1, "Reserve id correctly set in hold fill target for item level hold" );
1345
1346     my $queue_line_2 = $queue_rs->next;
1347     is( $queue_line_2->item_level_request, 0, 'Request is correctly advertised as biblio-level' );
1348
1349 };
1350
1351 subtest 'Trivial test for UpdateTransportCostMatrix' => sub {
1352     plan tests => 1;
1353     my $recs = [
1354         { frombranch => $library1->{branchcode}, tobranch => $library2->{branchcode}, cost => 1, disable_transfer => 0 },
1355         { frombranch => $library2->{branchcode}, tobranch => $library3->{branchcode}, cost => 0, disable_transfer => 1 },
1356     ];
1357     C4::HoldsQueue::UpdateTransportCostMatrix( $recs );
1358     is( $schema->resultset('TransportCost')->count, 2, 'UpdateTransportCostMatrix added two records' );
1359 };
1360
1361 subtest 'Excludes from local holds priority' => sub {
1362     plan tests => 8;
1363
1364     Koha::Holds->delete;
1365
1366     t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
1367     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
1368     t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
1369
1370     my $branch  = $builder->build_object( { class => 'Koha::Libraries' } );
1371     my $branch2 = $builder->build_object( { class => 'Koha::Libraries' } );
1372     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
1373     my $excluded_category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 1} });
1374     my $local_patron_excluded = $builder->build_object(
1375         {
1376             class => "Koha::Patrons",
1377             value => {
1378                 branchcode => $branch->branchcode,
1379                 categorycode => $excluded_category->categorycode
1380             }
1381         }
1382     );
1383
1384     my $local_patron_not_excluded = $builder->build_object(
1385         {
1386             class => "Koha::Patrons",
1387             value => {
1388                 branchcode => $branch->branchcode,
1389                 categorycode => $category->categorycode
1390             }
1391         }
1392     );
1393
1394     my $other_patron = $builder->build_object(
1395         {
1396             class => "Koha::Patrons",
1397             value => {
1398                 branchcode => $branch2->branchcode,
1399                 categorycode => $category->categorycode
1400             }
1401         }
1402     );
1403
1404     my $item1  = $builder->build_sample_item(
1405         {
1406             library      => $branch->branchcode,
1407             exclude_from_local_holds_priority => 0,
1408         }
1409     );
1410
1411     AddReserve(
1412         {
1413             branchcode     => $other_patron->branchcode,
1414             borrowernumber => $other_patron->borrowernumber,
1415             biblionumber   => $item1->biblionumber,
1416             priority       => 1,
1417             itemtype       => $item1->effective_itemtype
1418         }
1419     );
1420
1421     AddReserve(
1422         {
1423             branchcode     => $local_patron_excluded->branchcode,
1424             borrowernumber => $local_patron_excluded->borrowernumber,
1425             biblionumber   => $item1->biblionumber,
1426             priority       => 2,
1427             itemtype       => $item1->effective_itemtype
1428         }
1429     );
1430
1431     AddReserve(
1432         {
1433             branchcode     => $local_patron_not_excluded->branchcode,
1434             borrowernumber => $local_patron_not_excluded->borrowernumber,
1435             biblionumber   => $item1->biblionumber,
1436             priority       => 3,
1437             itemtype       => $item1->effective_itemtype
1438         }
1439     );
1440
1441     C4::HoldsQueue::CreateQueue();
1442
1443     my $queue_rs = $schema->resultset('TmpHoldsqueue');
1444     my $next = $queue_rs->next;
1445     is($queue_rs->count, 1, 'Only 1 patron queueud' );
1446     is($next->borrowernumber, $local_patron_not_excluded->borrowernumber, 'Not excluded local patron is queued');
1447
1448     my $item2  = $builder->build_sample_item(
1449         {
1450             biblionumber => $item1->biblionumber,
1451             library      => $branch->branchcode,
1452             exclude_from_local_holds_priority => 1,
1453         }
1454     );
1455     C4::HoldsQueue::CreateQueue();
1456
1457     $queue_rs = $schema->resultset('TmpHoldsqueue');
1458     is( $queue_rs->count, 2, '2 patrons queued' );
1459     $next = $queue_rs->next;
1460     is($next->borrowernumber, $local_patron_not_excluded->borrowernumber, 'Not excluded local patron is queued');
1461     $next = $queue_rs->next;
1462     is($next->borrowernumber, $other_patron->borrowernumber, 'Other patron is queued');
1463
1464     $item1->exclude_from_local_holds_priority(1)->store;
1465
1466     C4::HoldsQueue::CreateQueue();
1467
1468     $queue_rs = $schema->resultset('TmpHoldsqueue');
1469     is( $queue_rs->count, 2, '2 patrons queued' );
1470     $next = $queue_rs->next;
1471     is($next->borrowernumber, $other_patron->borrowernumber, 'Other patron is queued');
1472     $next = $queue_rs->next;
1473     is($next->borrowernumber, $local_patron_excluded->borrowernumber, 'Excluded local patron is queued');
1474 };
1475 # Cleanup
1476 $schema->storage->txn_rollback;
1477
1478 ### END Test holds queue builder does not violate holds policy ###
1479
1480 sub test_queue {
1481     my ($test_name, $use_cost_matrix, $pick_branch, $hold_branch) = @_;
1482
1483     $test_name = "$test_name (".($use_cost_matrix ? "" : "don't ")."use cost matrix)";
1484
1485     $use_cost_matrix_sth->execute($use_cost_matrix);
1486     C4::Context->clear_syspref_cache();
1487     C4::HoldsQueue::CreateQueue();
1488
1489     my $results = $dbh->selectall_arrayref($test_sth, { Slice => {} }); # should be only one
1490     my $r = $results->[0];
1491
1492     my $ok = is( $r->{pickbranch}, $pick_branch, "$test_name pick up branch");
1493     $ok &&=  is( $r->{holdingbranch}, $hold_branch, "$test_name holding branch")
1494       if $hold_branch;
1495
1496     diag( "Wrong pick-up/hold for first target (pick_branch, hold_branch, reserves, hold_fill_targets, tmp_holdsqueue): "
1497         . Dumper ($pick_branch, $hold_branch, map dump_records($_), qw(reserves hold_fill_targets tmp_holdsqueue)) )
1498       unless $ok;
1499
1500     # Test enforcement of branch transfer limit
1501     if ( $r->{pickbranch} ne $r->{holdingbranch} ) {
1502         t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '1' );
1503         my $limit = Koha::Item::Transfer::Limit->new(
1504             {
1505                 toBranch   => $r->{pickbranch},
1506                 fromBranch => $r->{holdingbranch},
1507                 itemtype   => $r->{itype},
1508             }
1509         )->store();
1510         C4::Context->clear_syspref_cache();
1511         C4::HoldsQueue::CreateQueue();
1512         $results = $dbh->selectall_arrayref( $test_sth, { Slice => {} } )
1513           ;    # should be only one
1514         my $s = $results->[0];
1515         isnt( $r->{holdingbranch}, $s->{holdingbranch}, 'Hold is not trapped for pickup at a branch that cannot be transferred to');
1516
1517         $limit->delete();
1518         t::lib::Mocks::mock_preference( 'UseBranchTransferLimits', '0' );
1519         C4::Context->clear_syspref_cache();
1520         C4::HoldsQueue::CreateQueue();
1521     }
1522
1523 }
1524
1525 subtest "Test _checkHoldPolicy" => sub {
1526     plan tests => 25;
1527
1528     my $library1  = $builder->build_object( { class => 'Koha::Libraries' } );
1529     my $library2  = $builder->build_object( { class => 'Koha::Libraries' } );
1530     my $library_nongroup = $builder->build_object( { class => 'Koha::Libraries' } );
1531     my $category = $builder->build_object( { class => 'Koha::Patron::Categories', value => {exclude_from_local_holds_priority => 0} });
1532     my $patron  = $builder->build_object(
1533         {
1534             class => "Koha::Patrons",
1535             value => {
1536                 branchcode => $library1->branchcode,
1537                 categorycode => $category->categorycode,
1538             }
1539         }
1540     );
1541     my $biblio = $builder->build_sample_biblio();
1542     my $item1  = $builder->build_sample_item(
1543         {
1544             biblionumber => $biblio->biblionumber,
1545             library      => $library1->branchcode,
1546             exclude_from_local_holds_priority => 0,
1547         }
1548     );
1549
1550     $reserve_id = AddReserve(
1551         {
1552             branchcode     => $item1->homebranch,
1553             borrowernumber => $patron->borrowernumber,
1554             biblionumber   => $biblio->id,
1555             priority       => 1
1556         }
1557     );
1558     ok( $reserve_id, "Hold was created");
1559     my $requests = C4::HoldsQueue::GetPendingHoldRequestsForBib($biblio->biblionumber);
1560     is( @$requests, 1, "Got correct number of holds");
1561
1562     my $request = $requests->[0];
1563     is( $request->{biblionumber}, $biblio->id, "Hold has correct biblio");
1564     is( $request->{borrowernumber}, $patron->id, "Hold has correct borrower");
1565     is( $request->{borrowerbranch}, $patron->branchcode, "Hold has correct borrowerbranch");
1566
1567     my $hold = Koha::Holds->find( $reserve_id );
1568     ok( $hold, "Found hold" );
1569
1570     my $item = {
1571         holdallowed              => 1,
1572         homebranch               => $request->{borrowerbranch}, # library1
1573         hold_fulfillment_policy  => 'any'
1574     };
1575
1576     # Base case should work
1577     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true" );
1578
1579     # Test holdallowed = 0
1580     $item->{holdallowed} = 0;
1581     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if holdallowed = 0" );
1582
1583     # Test holdallowed = 1
1584     $item->{holdallowed} = 1;
1585     $item->{homebranch} = $library_nongroup->id;
1586     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if holdallowed = 1 and branches do not match" );
1587
1588     $item->{homebranch} = $request->{borrowerbranch};
1589     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if holdallowed = 1 and branches do match" );
1590
1591     # Test holdallowed = 3
1592     $item->{holdallowed} = 3;
1593     $item->{homebranch} = $library_nongroup->id;
1594     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if branchode doesn't match, holdallowed = 3 and no group branches exist" );
1595     $item->{homebranch} = $request->{borrowerbranch};
1596     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if branchode matches, holdallowed = 3 and no group branches exist" );
1597
1598     # Create library groups hierarchy
1599     my $rootgroup = $builder->build_object( { class => 'Koha::Library::Groups', value => {ft_local_hold_group => 1} } );
1600     my $group1 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library1->branchcode}} );
1601     my $group2 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library2->branchcode}} );
1602
1603     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if holdallowed = 3 and no group branches exist" );
1604
1605     $group1->delete;
1606
1607     # Test hold_fulfillment_policy = holdgroup
1608     $item->{hold_fulfillment_policy} = 'holdgroup';
1609     $item->{homebranch} = $library_nongroup->id;
1610     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" );
1611     $item->{homebranch} = $request->{borrowerbranch};
1612     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is not part of hold group, branches match and hfp = holdgroup" );
1613
1614     $group1 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library1->branchcode}} );
1615     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
1616
1617     $item->{homebranch} = $library2->id;
1618     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
1619     $item->{homebranch} = $library1->id;
1620
1621     $group1->delete;
1622
1623     # Test hold_fulfillment_policy = homebranch
1624     $item->{hold_fulfillment_policy} = 'homebranch';
1625     $item->{homebranch} = $library_nongroup->id;
1626     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if hfp = homebranch and pickup branch != item homebranch" );
1627
1628     $item->{homebranch} = $request->{borrowerbranch};
1629     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if hfp = homebranch and pickup branch = item homebranch" );
1630
1631     # Test hold_fulfillment_policy = holdingbranch
1632     $item->{hold_fulfillment_policy} = 'holdingbranch';
1633     $item->{holdingbranch} = $library_nongroup->id;
1634     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if hfp = holdingbranch and pickup branch != item holdingbranch" );
1635
1636     $item->{holdingbranch} = $request->{borrowerbranch};
1637     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if hfp = holdingbranch and pickup branch = item holdingbranch" );
1638
1639     # Test hold_fulfillment_policy = patrongroup
1640     $item->{hold_fulfillment_policy} = 'patrongroup';
1641     $item->{borrowerbranch} = $library1->id;
1642
1643     $item->{homebranch} = $library_nongroup->id;
1644     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 0, "_checkHoldPolicy returns false if library is not part of hold group, branches don't match, hfp = patrongroup" );
1645     $item->{homebranch} = $request->{borrowerbranch};
1646     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns false if library is not part of hold group, branches match, hfp = patrongroup" );
1647
1648     $group1 = $builder->build_object( { class => 'Koha::Library::Groups', value => {parent_id => $rootgroup->id, branchcode => $library1->branchcode}} );
1649     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
1650
1651     $item->{borrowerbranch} = $library2->id;
1652     is( C4::HoldsQueue::_checkHoldPolicy( $item, $request ), 1, "_checkHoldPolicy returns true if library is part of hold group with hfp = holdgroup" );
1653     $item->{borrowerbranch} = $library1->id;
1654 };
1655
1656 sub dump_records {
1657     my ($tablename) = @_;
1658     return $dbh->selectall_arrayref("SELECT * from $tablename where borrowernumber = ?", { Slice => {} }, $borrowernumber);
1659 }