3 # Copyright 2020 Koha Development team
5 # This file is part of Koha
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
22 use Test::More tests => 11;
25 use C4::Circulation qw( AddIssue );
26 use C4::Reserves qw( AddReserve ModReserve ModReserveCancelAll );
27 use Koha::AuthorisedValueCategory;
28 use Koha::Biblio::ItemGroups;
30 use Koha::DateUtils qw( dt_from_string );
34 use t::lib::TestBuilder;
36 my $schema = Koha::Database->new->schema;
37 $schema->storage->txn_begin;
39 my $builder = t::lib::TestBuilder->new;
41 subtest 'DB constraints' => sub {
44 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
45 my $item = $builder->build_sample_item;
47 branchcode => $patron->branchcode,
48 borrowernumber => $patron->borrowernumber,
49 biblionumber => $item->biblionumber,
51 title => "title for fee",
52 itemnumber => $item->itemnumber,
55 my $reserve_id = C4::Reserves::AddReserve($hold_info);
56 my $hold = Koha::Holds->find( $reserve_id );
59 eval { $hold->priority(undef)->store }
61 qr{.*DBD::mysql::st execute failed: Column 'priority' cannot be null.*},
62 'DBD should have raised an error about priority that cannot be null';
65 subtest 'cancel' => sub {
67 my $biblioitem = $builder->build_object( { class => 'Koha::Biblioitems' } );
68 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
69 my $itemtype = $builder->build_object( { class => 'Koha::ItemTypes', value => { rentalcharge => 0 } } );
71 biblionumber => $biblioitem->biblionumber,
72 biblioitemnumber => $biblioitem->biblioitemnumber,
73 homebranch => $library->branchcode,
74 holdingbranch => $library->branchcode,
75 itype => $itemtype->itemtype,
77 my $item = $builder->build_object( { class => 'Koha::Items', value => $item_info } );
78 my $manager = $builder->build_object({ class => "Koha::Patrons" });
79 t::lib::Mocks::mock_userenv({ patron => $manager,branchcode => $manager->branchcode });
81 my ( @patrons, @holds );
82 for my $i ( 0 .. 2 ) {
83 my $priority = $i + 1;
84 my $patron = $builder->build_object(
86 class => 'Koha::Patrons',
87 value => { branchcode => $library->branchcode, }
90 my $reserve_id = C4::Reserves::AddReserve(
92 branchcode => $library->branchcode,
93 borrowernumber => $patron->borrowernumber,
94 biblionumber => $item->biblionumber,
95 priority => $priority,
96 title => "title for fee",
97 itemnumber => $item->itemnumber,
100 my $hold = Koha::Holds->find($reserve_id);
101 push @patrons, $patron;
105 # There are 3 holds on this records
107 Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
109 'There should have 3 holds placed on this biblio record' );
110 my $first_hold = $holds[0];
111 my $second_hold = $holds[1];
112 my $third_hold = $holds[2];
113 is( ref($second_hold), 'Koha::Hold',
114 'We should play with Koha::Hold objects' );
115 is( $second_hold->priority, 2,
116 'Second hold should have a priority set to 3' );
118 # Remove the second hold, only 2 should still exist in DB and priorities must have been updated
119 my $is_cancelled = $second_hold->cancel;
120 is( ref($is_cancelled), 'Koha::Hold',
121 'Koha::Hold->cancel should return the Koha::Hold (?)' )
122 ; # This is can reconsidered
123 is( $second_hold->in_storage, 0,
124 'The hold has been cancelled and does not longer exist in DB' );
126 Koha::Holds->search( { biblionumber => $item->biblionumber } )->count;
128 'a hold has been cancelled, there should have only 2 holds placed on this biblio record'
131 # discard_changes to refetch
132 is( $first_hold->discard_changes->priority, 1, 'First hold should still be first' );
133 is( $third_hold->discard_changes->priority, 2, 'Third hold should now be second' );
135 subtest 'charge_cancel_fee parameter' => sub {
137 my $patron_category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { reservefee => 0 } } );
138 my $patron = $builder->build_object({ class => 'Koha::Patrons', value => { categorycode => $patron_category->categorycode } });
139 is( $patron->account->balance, 0, 'A new patron does not have any charges' );
142 branchcode => $library->branchcode,
143 borrowernumber => $patron->borrowernumber,
144 biblionumber => $item->biblionumber,
146 title => "title for fee",
147 itemnumber => $item->itemnumber,
150 # First, test cancelling a reserve when there's no charge configured.
151 t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelayCharge', 0);
152 my $reserve_id = C4::Reserves::AddReserve( $hold_info );
153 Koha::Holds->find( $reserve_id )->cancel( { charge_cancel_fee => 1 } );
154 is( $patron->account->balance, 0, 'ExpireReservesMaxPickUpDelayCharge=0 - The patron should not have been charged' );
156 # Then, test cancelling a reserve when there's no charge desired.
157 t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelayCharge', 42);
158 $reserve_id = C4::Reserves::AddReserve( $hold_info );
159 Koha::Holds->find( $reserve_id )->cancel(); # charge_cancel_fee => 0
160 is( $patron->account->balance, 0, 'ExpireReservesMaxPickUpDelayCharge=42, but charge_cancel_fee => 0, The patron should not have been charged' );
163 # Finally, test cancelling a reserve when there's a charge desired and configured.
164 t::lib::Mocks::mock_preference('ExpireReservesMaxPickUpDelayCharge', 42);
165 $reserve_id = C4::Reserves::AddReserve( $hold_info );
166 Koha::Holds->find( $reserve_id )->cancel( { charge_cancel_fee => 1 } );
167 is( int($patron->account->balance), 42, 'ExpireReservesMaxPickUpDelayCharge=42 and charge_cancel_fee => 1, The patron should have been charged!' );
170 subtest 'waiting hold' => sub {
172 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
173 my $reserve_id = C4::Reserves::AddReserve(
175 branchcode => $library->branchcode,
176 borrowernumber => $patron->borrowernumber,
177 biblionumber => $item->biblionumber,
179 title => "title for fee",
180 itemnumber => $item->itemnumber,
184 Koha::Holds->find( $reserve_id )->cancel;
185 my $hold_old = Koha::Old::Holds->find( $reserve_id );
186 is( $hold_old->found, 'W', 'The found column should have been kept and a hold is cancelled' );
189 subtest 'HoldsLog' => sub {
191 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
193 branchcode => $library->branchcode,
194 borrowernumber => $patron->borrowernumber,
195 biblionumber => $item->biblionumber,
197 title => "title for fee",
198 itemnumber => $item->itemnumber,
201 t::lib::Mocks::mock_preference('HoldsLog', 0);
202 my $reserve_id = C4::Reserves::AddReserve($hold_info);
203 Koha::Holds->find( $reserve_id )->cancel;
204 my $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
205 is( $number_of_logs, 0, 'Without HoldsLog, Koha::Hold->cancel should not have logged' );
207 t::lib::Mocks::mock_preference('HoldsLog', 1);
208 $reserve_id = C4::Reserves::AddReserve($hold_info);
209 Koha::Holds->find( $reserve_id )->cancel;
210 $number_of_logs = $schema->resultset('ActionLog')->search( { module => 'HOLDS', action => 'CANCEL', object => $reserve_id } )->count;
211 is( $number_of_logs, 1, 'With HoldsLog, Koha::Hold->cancel should have logged' );
214 subtest 'rollback' => sub {
216 my $patron_category = $builder->build_object(
218 class => 'Koha::Patron::Categories',
219 value => { reservefee => 0 }
222 my $patron = $builder->build_object(
224 class => 'Koha::Patrons',
225 value => { categorycode => $patron_category->categorycode }
229 branchcode => $library->branchcode,
230 borrowernumber => $patron->borrowernumber,
231 biblionumber => $item->biblionumber,
233 title => "title for fee",
234 itemnumber => $item->itemnumber,
237 t::lib::Mocks::mock_preference( 'ExpireReservesMaxPickUpDelayCharge',42 );
238 my $reserve_id = C4::Reserves::AddReserve($hold_info);
239 my $hold = Koha::Holds->find($reserve_id);
241 # Add a row with the same id to make the cancel fails
242 Koha::Old::Hold->new( $hold->unblessed )->store;
245 eval { $hold->cancel( { charge_cancel_fee => 1 } ) };
247 qr{.*DBD::mysql::st execute failed: Duplicate entry.*},
248 'DBD should have raised an error about dup primary key';
250 $hold = Koha::Holds->find($reserve_id);
251 is( ref($hold), 'Koha::Hold', 'The hold should not have been deleted' );
252 is( $patron->account->balance, 0,
253 'If the hold has not been cancelled, the patron should not have been charged'
259 subtest 'cancel with reason' => sub {
261 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
262 my $item = $builder->build_sample_item({ library => $library->branchcode });
263 my $manager = $builder->build_object( { class => "Koha::Patrons" } );
264 t::lib::Mocks::mock_userenv( { patron => $manager, branchcode => $manager->branchcode } );
266 my $patron = $builder->build_object(
268 class => 'Koha::Patrons',
269 value => { branchcode => $library->branchcode, }
273 my $reserve_id = C4::Reserves::AddReserve(
275 branchcode => $library->branchcode,
276 borrowernumber => $patron->borrowernumber,
277 biblionumber => $item->biblionumber,
279 itemnumber => $item->itemnumber,
283 my $hold = Koha::Holds->find($reserve_id);
285 ok($reserve_id, "Hold created");
286 ok($hold, "Hold found");
288 my $av = Koha::AuthorisedValue->new( { category => 'HOLD_CANCELLATION', authorised_value => 'TEST_REASON' } )->store;
289 Koha::Notice::Templates->search({ code => 'HOLD_CANCELLATION'})->delete();
290 my $notice = Koha::Notice::Template->new({
291 name => 'Hold cancellation',
292 module => 'reserves',
293 code => 'HOLD_CANCELLATION',
294 title => 'Hold cancelled',
295 content => 'Your hold was cancelled.',
296 message_transport_type => 'email',
300 $hold->cancel({cancellation_reason => 'TEST_REASON'});
302 $hold = Koha::Holds->find($reserve_id);
303 is( $hold, undef, 'Hold is not in the reserves table');
304 $hold = Koha::Old::Holds->find($reserve_id);
305 ok( $hold, 'Hold was found in the old reserves table');
307 my $message = Koha::Notice::Messages->find({ borrowernumber => $patron->id, letter_code => 'HOLD_CANCELLATION'});
308 ok( $message, 'Found hold cancellation message');
309 is( $message->subject, 'Hold cancelled', 'Message has correct title' );
310 is( $message->content, 'Your hold was cancelled.', 'Message has correct content');
317 subtest 'cancel all with reason' => sub {
319 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
320 my $item = $builder->build_sample_item({ library => $library->branchcode });
321 my $manager = $builder->build_object( { class => "Koha::Patrons" } );
322 t::lib::Mocks::mock_userenv( { patron => $manager, branchcode => $manager->branchcode } );
324 my $patron = $builder->build_object(
326 class => 'Koha::Patrons',
327 value => { branchcode => $library->branchcode, }
331 my $reserve_id = C4::Reserves::AddReserve(
333 branchcode => $library->branchcode,
334 borrowernumber => $patron->borrowernumber,
335 biblionumber => $item->biblionumber,
337 itemnumber => $item->itemnumber,
341 my $hold = Koha::Holds->find($reserve_id);
343 ok($reserve_id, "Hold created");
344 ok($hold, "Hold found");
346 my $av = Koha::AuthorisedValue->new( { category => 'HOLD_CANCELLATION', authorised_value => 'TEST_REASON' } )->store;
347 Koha::Notice::Templates->search({ code => 'HOLD_CANCELLATION'})->delete();
348 my $notice = Koha::Notice::Template->new({
349 name => 'Hold cancellation',
350 module => 'reserves',
351 code => 'HOLD_CANCELLATION',
352 title => 'Hold cancelled',
353 content => 'Your hold was cancelled.',
354 message_transport_type => 'email',
358 ModReserveCancelAll($item->id, $patron->id, 'TEST_REASON');
360 $hold = Koha::Holds->find($reserve_id);
361 is( $hold, undef, 'Hold is not in the reserves table');
362 $hold = Koha::Old::Holds->find($reserve_id);
363 ok( $hold, 'Hold was found in the old reserves table');
365 my $message = Koha::Notice::Messages->find({ borrowernumber => $patron->id, letter_code => 'HOLD_CANCELLATION'});
366 ok( $message, 'Found hold cancellation message');
367 is( $message->subject, 'Hold cancelled', 'Message has correct title' );
368 is( $message->content, 'Your hold was cancelled.', 'Message has correct content');
374 subtest 'Desks' => sub {
376 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
378 my $desk = Koha::Desk->new({
379 desk_name => 'my_desk_name_for_test',
380 branchcode => $library->branchcode ,
382 ok($desk, "Desk created");
383 my $item = $builder->build_sample_item({ library => $library->branchcode });
384 my $manager = $builder->build_object( { class => "Koha::Patrons" } );
385 t::lib::Mocks::mock_userenv( { patron => $manager, branchcode => $manager->branchcode } );
387 my $patron = $builder->build_object(
389 class => 'Koha::Patrons',
390 value => { branchcode => $library->branchcode, }
394 my $reserve_id = C4::Reserves::AddReserve(
396 branchcode => $library->branchcode,
397 borrowernumber => $patron->borrowernumber,
398 biblionumber => $item->biblionumber,
400 itemnumber => $item->itemnumber,
404 my $hold = Koha::Holds->find($reserve_id);
406 ok($reserve_id, "Hold created");
407 ok($hold, "Hold found");
408 $hold->set_waiting($desk->desk_id);
409 is($hold->found, 'W', 'Hold is waiting with correct status set');
410 is($hold->desk_id, $desk->desk_id, 'Hold is attach to its desk');
414 subtest 'get_items_that_can_fill' => sub {
417 my $biblio = $builder->build_sample_biblio;
418 my $itype_1 = $builder->build_object({ class => 'Koha::ItemTypes' }); # For 1, 2, 3, 4
419 my $itype_2 = $builder->build_object({ class => 'Koha::ItemTypes' });
420 my $item_1 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } );
422 my $item_2 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } );
423 my $item_3 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } )
425 my $item_4 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } )
427 my $item_5 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_2->itemtype } );
428 my $lost = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itemlost => 1 } );
429 my $withdrawn = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, withdrawn => 1 } );
430 my $notforloan = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, notforloan => -1 } );
432 my $patron_1 = $builder->build_object( { class => 'Koha::Patrons' } );
433 my $patron_2 = $builder->build_object( { class => 'Koha::Patrons' } );
434 my $patron_3 = $builder->build_object( { class => 'Koha::Patrons' } );
436 my $library_1 = $builder->build_object( { class => 'Koha::Libraries' } );
438 t::lib::Mocks::mock_userenv( { patron => $patron_1 } );
440 my $reserve_id_1 = C4::Reserves::AddReserve(
442 branchcode => $library_1->branchcode,
443 borrowernumber => $patron_1->borrowernumber,
444 biblionumber => $biblio->biblionumber,
446 itemnumber => $item_1->itemnumber,
450 my $holds = Koha::Holds->search({ reserve_id => $reserve_id_1 });
451 my $items = $holds->get_items_that_can_fill;
452 is_deeply( [ map { $_->itemnumber } $items->as_list ], [ $item_1->itemnumber ], 'Item level hold can only be filled by the specific item');
454 my $reserve_id_2 = C4::Reserves::AddReserve(
456 branchcode => $library_1->branchcode,
457 borrowernumber => $patron_2->borrowernumber,
458 biblionumber => $biblio->biblionumber,
460 branchcode => $item_1->homebranch,
464 my $waiting_reserve_id = C4::Reserves::AddReserve(
466 branchcode => $library_1->branchcode,
467 borrowernumber => $patron_2->borrowernumber,
468 biblionumber => $biblio->biblionumber,
471 itemnumber => $item_1->itemnumber,
475 my $notforloan_reserve_id = C4::Reserves::AddReserve(
477 branchcode => $library_1->branchcode,
478 borrowernumber => $patron_2->borrowernumber,
479 biblionumber => $biblio->biblionumber,
481 itemnumber => $notforloan->itemnumber,
486 AddIssue( $patron_3->unblessed, $item_3->barcode );
488 # item 4 is in transfer
489 my $from = $builder->build_object( { class => 'Koha::Libraries' } );
490 my $to = $builder->build_object( { class => 'Koha::Libraries' } );
491 Koha::Item::Transfer->new(
493 itemnumber => $item_4->itemnumber,
494 datearrived => undef,
495 frombranch => $from->branchcode,
496 tobranch => $to->branchcode
500 $holds = Koha::Holds->search(
502 reserve_id => [ $reserve_id_1, $reserve_id_2, $waiting_reserve_id, $notforloan_reserve_id, ]
506 $items = $holds->get_items_that_can_fill;
507 is_deeply( [ map { $_->itemnumber } $items->as_list ],
508 [ $item_2->itemnumber, $item_5->itemnumber ], 'Only item 2 and 5 are available for filling the hold' );
510 # Marking item_5 is no hold allowed
511 Koha::CirculationRule->new(
513 rule_name => 'holdallowed',
514 rule_value => 'not_allowed',
515 itemtype => $item_5->itype
518 $items = $holds->get_items_that_can_fill;
519 is_deeply( [ map { $_->itemnumber } $items->as_list ],
520 [ $item_2->itemnumber ], 'Only item 2 is available for filling the hold' );
523 my $noloan_itype = $builder->build_object( { class => 'Koha::ItemTypes', value => { notforloan => 1 } } );
524 t::lib::Mocks::mock_preference( 'item-level_itypes', 0 );
525 Koha::Holds->find( $waiting_reserve_id )->delete;
526 $holds = Koha::Holds->search(
528 reserve_id => [ $reserve_id_1, $reserve_id_2 ]
531 $items = $holds->get_items_that_can_fill;
532 is_deeply( [ sort { $a <=> $b } map { $_->itemnumber } $items->as_list ],
533 [ $item_1->itemnumber, $item_2->itemnumber, $item_5->itemnumber ], 'Items 1, 2, and 5 are available for filling the holds' );
535 my $no_holds = Koha::Holds->new->empty();
536 my $no_items = $no_holds->get_items_that_can_fill();
537 is( ref $no_items, "Koha::Items", "Routine returns a Koha::Items object");
538 is( $no_items->count, 0, "Object is empty when called on no holds");
542 subtest 'set_waiting+patron_expiration_date' => sub {
544 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
547 $builder->build_sample_item( { library => $library->branchcode } );
548 my $manager = $builder->build_object( { class => "Koha::Patrons" } );
549 t::lib::Mocks::mock_userenv(
550 { patron => $manager, branchcode => $manager->branchcode } );
552 my $patron = $builder->build_object(
554 class => 'Koha::Patrons',
555 value => { branchcode => $library->branchcode, }
559 subtest 'patron_expiration_date < expiration_date' => sub {
561 t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', 5 );
562 my $patron_expiration_date = dt_from_string->add( days => 3 )->ymd;
563 my $reserve_id = C4::Reserves::AddReserve(
565 branchcode => $library->branchcode,
566 borrowernumber => $patron->borrowernumber,
567 biblionumber => $item->biblionumber,
569 itemnumber => $item->itemnumber,
570 expiration_date => $patron_expiration_date,
574 my $hold = Koha::Holds->find($reserve_id);
577 $hold->expirationdate,
578 $patron_expiration_date,
579 'expiration date set to patron expiration date'
582 $hold->patron_expiration_date, $patron_expiration_date,
583 'patron expiration date correctly set'
588 $hold = $hold->get_from_storage;
589 is( $hold->expirationdate, $patron_expiration_date );
590 is( $hold->patron_expiration_date, $patron_expiration_date );
592 C4::Reserves::RevertWaitingStatus(
593 { itemnumber => $item->itemnumber }
596 $hold = $hold->get_from_storage;
597 is( $hold->expirationdate, $patron_expiration_date );
598 is( $hold->patron_expiration_date, $patron_expiration_date );
601 subtest 'patron_expiration_date > expiration_date' => sub {
603 t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', 5 );
604 my $new_expiration_date = dt_from_string->add( days => 5 )->ymd;
605 my $patron_expiration_date = dt_from_string->add( days => 6 )->ymd;
606 my $reserve_id = C4::Reserves::AddReserve(
608 branchcode => $library->branchcode,
609 borrowernumber => $patron->borrowernumber,
610 biblionumber => $item->biblionumber,
612 itemnumber => $item->itemnumber,
613 expiration_date => $patron_expiration_date,
617 my $hold = Koha::Holds->find($reserve_id);
620 $hold->expirationdate,
621 $patron_expiration_date,
622 'expiration date set to patron expiration date'
625 $hold->patron_expiration_date, $patron_expiration_date,
626 'patron expiration date correctly set'
631 $hold = $hold->get_from_storage;
632 is( $hold->expirationdate, $new_expiration_date );
633 is( $hold->patron_expiration_date, $patron_expiration_date );
635 C4::Reserves::RevertWaitingStatus(
636 { itemnumber => $item->itemnumber }
639 $hold = $hold->get_from_storage;
640 is( $hold->expirationdate, $patron_expiration_date );
641 is( $hold->patron_expiration_date, $patron_expiration_date );
645 subtest 'Test Koha::Hold::item_group' => sub {
647 my $library = $builder->build_object( { class => 'Koha::Libraries' } );
648 my $patron = $builder->build_object({ class => 'Koha::Patrons' });
649 my $item = $builder->build_sample_item;
650 my $item_group = $builder->build_object(
652 class => 'Koha::Biblio::ItemGroups',
655 my $reserve_id = AddReserve(
657 branchcode => $library->branchcode,
658 borrowernumber => $patron->borrowernumber,
659 biblionumber => $item->biblionumber,
660 itemnumber => $item->itemnumber,
661 item_group_id => $item_group->id,
665 my $hold = Koha::Holds->find($reserve_id);
666 is( $hold->item_group_id, $item_group->id,
667 'Koha::Hold::item_group returns the correct item_group' );
671 $schema->storage->txn_rollback;
673 subtest 'filter_by_found() tests' => sub {
677 $schema->storage->txn_begin;
679 my $unfilled = $builder->build_object( { class => 'Koha::Holds', value => { found => undef } } );
680 my $processing = $builder->build_object( { class => 'Koha::Holds', value => { found => 'P' } } );
681 my $in_transit = $builder->build_object( { class => 'Koha::Holds', value => { found => 'T' } } );
682 my $waiting = $builder->build_object( { class => 'Koha::Holds', value => { found => 'W' } } );
684 my $holds = Koha::Holds->search(
685 { reserve_id => [ $unfilled->id, $processing->id, $in_transit->id, $waiting->id ] },
686 { order_by => ['reserve_id'] }
689 is( $holds->count, 4, 'Resultset count is correct' );
691 my $found_holds = $holds->filter_by_found;
693 is( $found_holds->count, 3, 'Resultset count is correct' );
695 ok( $found_holds->next->is_in_processing, 'Status is correct (P)' );
696 ok( $found_holds->next->is_in_transit, 'Status is correct (T)' );
697 ok( $found_holds->next->is_waiting, 'Status is correct (W)' );
700 $schema->storage->txn_rollback;
703 subtest 'filter_by_has_cancellation_requests() and filter_out_has_cancellation_requests() tests' => sub {
707 $schema->storage->txn_begin;
709 my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
711 my $item_1 = $builder->build_sample_item;
712 my $item_2 = $builder->build_sample_item;
713 my $item_3 = $builder->build_sample_item;
715 my $hold_1 = $builder->build_object(
717 class => 'Koha::Holds',
720 itemnumber => $item_1->id,
721 biblionumber => $item_1->biblionumber,
722 borrowernumber => $patron->id
726 my $hold_2 = $builder->build_object(
728 class => 'Koha::Holds',
731 itemnumber => $item_2->id,
732 biblionumber => $item_2->biblionumber,
733 borrowernumber => $patron->id
737 my $hold_3 = $builder->build_object(
739 class => 'Koha::Holds',
742 itemnumber => $item_3->id,
743 biblionumber => $item_3->biblionumber,
744 borrowernumber => $patron->id
749 my $rs = Koha::Holds->search(
750 { reserve_id => [ $hold_1->id, $hold_2->id, $hold_3->id ] } );
754 my $filtered_rs = $rs->filter_by_has_cancellation_requests;
756 is( $filtered_rs->count, 0 );
758 my $filtered_out_rs = $rs->filter_out_has_cancellation_requests;
760 is( $filtered_out_rs->count, 3 );
762 $hold_2->add_cancellation_request;
764 $filtered_rs = $rs->filter_by_has_cancellation_requests;
766 is( $filtered_rs->count, 1 );
767 is( $filtered_rs->next->id, $hold_2->id );
769 $filtered_out_rs = $rs->filter_out_has_cancellation_requests;
771 is( $filtered_out_rs->count, 2 );
772 is( $filtered_out_rs->next->id, $hold_1->id );
774 $schema->storage->txn_rollback;
777 subtest 'processing() tests' => sub {
781 $schema->storage->txn_begin;
783 my $hold_1 = $builder->build_object(
785 class => 'Koha::Holds',
786 value => { found => 'P' }
789 my $hold_2 = $builder->build_object(
791 class => 'Koha::Holds',
792 value => { found => undef }
795 my $hold_3 = $builder->build_object(
797 class => 'Koha::Holds',
798 value => { found => 'T' }
802 my $holds = Koha::Holds->search({ reserve_id => [ $hold_1->id, $hold_2->id, $hold_3->id ] });
803 is( $holds->count, 3, 'Resultset contains 3 holds' );
805 my $processing = $holds->processing;
806 is( $processing->count, 1 );
807 is( $processing->next->id, $hold_1->id, "First hold is the only one in 'processing'" );
809 $schema->storage->txn_rollback;