use Modern::Perl;
-use Test::More tests => 6;
+use Test::More tests => 8;
use Test::Warn;
-use C4::Circulation;
-use C4::Reserves;
+use C4::Circulation qw( AddIssue );
+use C4::Reserves qw( AddReserve ModReserve ModReserveCancelAll );
use Koha::AuthorisedValueCategory;
use Koha::Database;
+use Koha::DateUtils qw( dt_from_string );
use Koha::Holds;
use t::lib::Mocks;
};
subtest 'get_items_that_can_fill' => sub {
- plan tests => 1;
+ plan tests => 6;
my $biblio = $builder->build_sample_biblio;
- my $item_1 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
- my $item_2 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
- my $item_3 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } )
+ my $itype_1 = $builder->build_object({ class => 'Koha::ItemTypes' }); # For 1, 2, 3, 4
+ my $itype_2 = $builder->build_object({ class => 'Koha::ItemTypes' });
+ my $item_1 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } );
+ # waiting
+ my $item_2 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } );
+ my $item_3 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } )
; # onloan
- my $item_4 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } )
+ my $item_4 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_1->itemtype } )
; # in transfer
- my $item_5 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber } );
+ my $item_5 = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itype => $itype_2->itemtype } );
my $lost = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, itemlost => 1 } );
my $withdrawn = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, withdrawn => 1 } );
- my $notforloan = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, notforloan => 1 } );
+ my $notforloan = $builder->build_sample_item( { biblionumber => $biblio->biblionumber, notforloan => -1 } );
my $patron_1 = $builder->build_object( { class => 'Koha::Patrons' } );
my $patron_2 = $builder->build_object( { class => 'Koha::Patrons' } );
my $patron_3 = $builder->build_object( { class => 'Koha::Patrons' } );
+ my $library_1 = $builder->build_object( { class => 'Koha::Libraries' } );
+
t::lib::Mocks::mock_userenv( { patron => $patron_1 } );
my $reserve_id_1 = C4::Reserves::AddReserve(
{
+ branchcode => $library_1->branchcode,
borrowernumber => $patron_1->borrowernumber,
biblionumber => $biblio->biblionumber,
priority => 1,
}
);
+ my $holds = Koha::Holds->search({ reserve_id => $reserve_id_1 });
+ my $items = $holds->get_items_that_can_fill;
+ is_deeply( [ map { $_->itemnumber } $items->as_list ], [ $item_1->itemnumber ], 'Item level hold can only be filled by the specific item');
+
my $reserve_id_2 = C4::Reserves::AddReserve(
{
+ branchcode => $library_1->branchcode,
borrowernumber => $patron_2->borrowernumber,
biblionumber => $biblio->biblionumber,
priority => 2,
- itemnumber => $item_1->itemnumber,
+ branchcode => $item_1->homebranch,
}
);
my $waiting_reserve_id = C4::Reserves::AddReserve(
{
+ branchcode => $library_1->branchcode,
borrowernumber => $patron_2->borrowernumber,
biblionumber => $biblio->biblionumber,
priority => 0,
}
);
+ my $notforloan_reserve_id = C4::Reserves::AddReserve(
+ {
+ branchcode => $library_1->branchcode,
+ borrowernumber => $patron_2->borrowernumber,
+ biblionumber => $biblio->biblionumber,
+ priority => 0,
+ itemnumber => $notforloan->itemnumber,
+ }
+ );
+
# item 3 is on loan
AddIssue( $patron_3->unblessed, $item_3->barcode );
}
)->store;
- my $holds = Koha::Holds->search(
+ $holds = Koha::Holds->search(
+ {
+ reserve_id => [ $reserve_id_1, $reserve_id_2, $waiting_reserve_id, $notforloan_reserve_id, ]
+ }
+ );
+
+ $items = $holds->get_items_that_can_fill;
+ is_deeply( [ map { $_->itemnumber } $items->as_list ],
+ [ $item_2->itemnumber, $item_5->itemnumber ], 'Only item 2 and 5 are available for filling the hold' );
+
+ # Marking item_5 is no hold allowed
+ Koha::CirculationRule->new(
+ {
+ rule_name => 'holdallowed',
+ rule_value => 'not_allowed',
+ itemtype => $item_5->itype
+ }
+ )->store;
+ $items = $holds->get_items_that_can_fill;
+ is_deeply( [ map { $_->itemnumber } $items->as_list ],
+ [ $item_2->itemnumber ], 'Only item 2 is available for filling the hold' );
+
+
+ my $noloan_itype = $builder->build_object( { class => 'Koha::ItemTypes', value => { notforloan => 1 } } );
+ t::lib::Mocks::mock_preference( 'item-level_itypes', 0 );
+ Koha::Holds->find( $waiting_reserve_id )->delete;
+ $holds = Koha::Holds->search(
{
- reserve_id => [ $reserve_id_1, $reserve_id_2, $waiting_reserve_id, ]
+ reserve_id => [ $reserve_id_1, $reserve_id_2 ]
}
);
+ $items = $holds->get_items_that_can_fill;
+ is_deeply( [ sort map { $_->itemnumber } $items->as_list ],
+ [ $item_1->itemnumber, $item_2->itemnumber, $item_5->itemnumber ], 'Items 1, 2, and 5 are available for filling the holds' );
+
+ my $no_holds = Koha::Holds->new->empty();
+ my $no_items = $no_holds->get_items_that_can_fill();
+ is( ref $no_items, "Koha::Items", "Routine returns a Koha::Items object");
+ is( $no_items->count, 0, "Object is empty when called on no holds");
+
+};
+
+subtest 'set_waiting+patron_expiration_date' => sub {
+ plan tests => 2;
+ my $library = $builder->build_object( { class => 'Koha::Libraries' } );
+
+ my $item =
+ $builder->build_sample_item( { library => $library->branchcode } );
+ my $manager = $builder->build_object( { class => "Koha::Patrons" } );
+ t::lib::Mocks::mock_userenv(
+ { patron => $manager, branchcode => $manager->branchcode } );
+
+ my $patron = $builder->build_object(
+ {
+ class => 'Koha::Patrons',
+ value => { branchcode => $library->branchcode, }
+ }
+ );
+
+ subtest 'patron_expiration_date < expiration_date' => sub {
+ plan tests => 6;
+ t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', 5 );
+ my $patron_expiration_date = dt_from_string->add( days => 3 )->ymd;
+ my $reserve_id = C4::Reserves::AddReserve(
+ {
+ branchcode => $library->branchcode,
+ borrowernumber => $patron->borrowernumber,
+ biblionumber => $item->biblionumber,
+ priority => 1,
+ itemnumber => $item->itemnumber,
+ expiration_date => $patron_expiration_date,
+ }
+ );
+
+ my $hold = Koha::Holds->find($reserve_id);
+
+ is(
+ $hold->expirationdate,
+ $patron_expiration_date,
+ 'expiration date set to patron expiration date'
+ );
+ is(
+ $hold->patron_expiration_date, $patron_expiration_date,
+ 'patron expiration date correctly set'
+ );
+
+ $hold->set_waiting;
+
+ $hold = $hold->get_from_storage;
+ is( $hold->expirationdate, $patron_expiration_date );
+ is( $hold->patron_expiration_date, $patron_expiration_date );
+
+ C4::Reserves::RevertWaitingStatus(
+ { itemnumber => $item->itemnumber }
+ );
+
+ $hold = $hold->get_from_storage;
+ is( $hold->expirationdate, $patron_expiration_date );
+ is( $hold->patron_expiration_date, $patron_expiration_date );
+ };
+
+ subtest 'patron_expiration_date > expiration_date' => sub {
+ plan tests => 6;
+ t::lib::Mocks::mock_preference( 'ReservesMaxPickUpDelay', 5 );
+ my $new_expiration_date = dt_from_string->add( days => 5 )->ymd;
+ my $patron_expiration_date = dt_from_string->add( days => 6 )->ymd;
+ my $reserve_id = C4::Reserves::AddReserve(
+ {
+ branchcode => $library->branchcode,
+ borrowernumber => $patron->borrowernumber,
+ biblionumber => $item->biblionumber,
+ priority => 1,
+ itemnumber => $item->itemnumber,
+ expiration_date => $patron_expiration_date,
+ }
+ );
+
+ my $hold = Koha::Holds->find($reserve_id);
+
+ is(
+ $hold->expirationdate,
+ $patron_expiration_date,
+ 'expiration date set to patron expiration date'
+ );
+ is(
+ $hold->patron_expiration_date, $patron_expiration_date,
+ 'patron expiration date correctly set'
+ );
- my @items = $holds->get_items_that_can_fill;
- is_deeply( [ map { $_->itemnumber } @items ],
- [ $item_2->itemnumber, $item_5->itemnumber ], 'Only item 1 and 5 are available for filling the hold' );
+ $hold->set_waiting;
+
+ $hold = $hold->get_from_storage;
+ is( $hold->expirationdate, $new_expiration_date );
+ is( $hold->patron_expiration_date, $patron_expiration_date );
+
+ C4::Reserves::RevertWaitingStatus(
+ { itemnumber => $item->itemnumber }
+ );
+
+ $hold = $hold->get_from_storage;
+ is( $hold->expirationdate, $patron_expiration_date );
+ is( $hold->patron_expiration_date, $patron_expiration_date );
+ };
};
+
$schema->storage->txn_rollback;
-1;
+subtest 'filter_by_has_cancellation_requests() tests' => sub {
+
+ plan tests => 4;
+
+ $schema->storage->txn_begin;
+
+ my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
+
+ my $item_1 = $builder->build_sample_item;
+ my $item_2 = $builder->build_sample_item;
+ my $item_3 = $builder->build_sample_item;
+
+ my $hold_1 = $builder->build_object(
+ {
+ class => 'Koha::Holds',
+ value => {
+ found => 'W',
+ itemnumber => $item_1->id,
+ biblionumber => $item_1->biblionumber,
+ borrowernumber => $patron->id
+ }
+ }
+ );
+ my $hold_2 = $builder->build_object(
+ {
+ class => 'Koha::Holds',
+ value => {
+ found => 'W',
+ itemnumber => $item_2->id,
+ biblionumber => $item_2->biblionumber,
+ borrowernumber => $patron->id
+ }
+ }
+ );
+ my $hold_3 = $builder->build_object(
+ {
+ class => 'Koha::Holds',
+ value => {
+ found => 'W',
+ itemnumber => $item_3->id,
+ biblionumber => $item_3->biblionumber,
+ borrowernumber => $patron->id
+ }
+ }
+ );
+
+ my $rs = Koha::Holds->search(
+ { reserve_id => [ $hold_1->id, $hold_2->id, $hold_3->id ] } );
+
+ is( $rs->count, 3 );
+
+ my $filtered_rs = $rs->filter_by_has_cancellation_requests;
+
+ is( $filtered_rs->count, 0 );
+
+ $hold_2->add_cancellation_request;
+
+ $filtered_rs = $rs->filter_by_has_cancellation_requests;
+
+ is( $filtered_rs->count, 1 );
+ is( $filtered_rs->next->id, $hold_2->id );
+
+ $schema->storage->txn_rollback;
+};