+subtest "store() tests" => sub {
+
+ plan tests => 5;
+
+ $schema->storage->txn_begin();
+
+ my $item = $builder->build_sample_item;
+ my $biblio = $item->biblio;
+ my $borrower = $builder->build_object( { class => 'Koha::Patrons' } );
+ my $library = $builder->build_object( { class => 'Koha::Libraries' } );
+
+ # Test setting expiration date
+ t::lib::Mocks::mock_preference( 'DefaultHoldExpirationdate', 1 );
+ t::lib::Mocks::mock_preference( 'DefaultHoldExpirationdatePeriod', 2 );
+ t::lib::Mocks::mock_preference( 'DefaultHoldExpirationdateUnitOfTime',
+ 'years' );
+
+ my $hold = Koha::Hold->new(
+ {
+ biblionumber => $biblio->biblionumber,
+ itemnumber => $item->id,
+ reservedate => '2020-11-30',
+ waitingdate => '2020-11-30',
+ borrowernumber => $borrower->borrowernumber,
+ branchcode => $library->branchcode,
+ suspend => 0,
+ }
+ )->store;
+ $hold->discard_changes;
+
+ my $expected_date =
+ dt_from_string( $hold->reservedate )->add( years => 2 );
+ is( $hold->expirationdate,
+ $expected_date->ymd, 'Default expiration date for new hold is correctly set.' );
+
+ my $passed_date =
+ dt_from_string( $hold->reservedate )->add( months => 2 );
+ $hold = Koha::Hold->new(
+ {
+ biblionumber => $biblio->biblionumber,
+ itemnumber => $item->id,
+ reservedate => '2020-11-30',
+ expirationdate => $passed_date->ymd,
+ waitingdate => '2020-11-30',
+ borrowernumber => $borrower->borrowernumber,
+ branchcode => $library->branchcode,
+ suspend => 0,
+ }
+ )->store;
+ $hold->discard_changes;
+
+ is( $hold->expirationdate,
+ $passed_date->ymd, 'Passed expiration date for new hold is correctly set.' );
+
+ $passed_date->add( months => 1 );
+ $hold->expirationdate($passed_date->ymd)->store();
+ $hold->discard_changes;
+
+ is( $hold->expirationdate,
+ $passed_date->ymd, 'Passed expiration date when updating hold is correctly set.' );
+
+ $hold->reservedate($passed_date->ymd)->store();
+ $hold->discard_changes;
+
+ is( $hold->expirationdate,
+ $passed_date->add( years => 2 )->ymd, 'Default expiration date correctly set on reservedate update.' );
+
+ $hold->set(
+ {
+ reservedate => $passed_date->ymd,
+ expirationdate => $passed_date->add( weeks => 2 )->ymd
+ }
+ )->store();
+ $hold->discard_changes;
+
+ is( $hold->expirationdate,
+ $passed_date->ymd, 'Passed expiration date when updating hold correctly set (Passing both reservedate and expirationdate.' );
+
+ $schema->storage->txn_rollback();
+};
+
+subtest "delete() tests" => sub {
+
+ plan tests => 6;
+
+ $schema->storage->txn_begin();
+
+ # Disable logging
+ t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
+
+ my $hold = $builder->build({ source => 'Reserve' });
+
+ my $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
+ my $deleted = $hold_object->delete;
+ is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return the Koha::Hold object if the hold has been correctly deleted' );
+ is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
+ "Koha::Hold->delete should have deleted the hold" );
+
+ my $number_of_logs = $schema->resultset('ActionLog')->search(
+ { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
+ is( $number_of_logs, 0, 'With HoldsLogs, Koha::Hold->delete shouldn\'t have been logged' );
+
+ # Enable logging
+ t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
+
+ $hold = $builder->build({ source => 'Reserve' });
+
+ $hold_object = Koha::Holds->find( $hold->{ reserve_id } );
+ $deleted = $hold_object->delete;
+ is( ref($deleted), 'Koha::Hold', 'Koha::Hold->delete should return a Koha::Hold object if the hold has been correctly deleted' );
+ is( Koha::Holds->search({ reserve_id => $hold->{ reserve_id } })->count, 0,
+ "Koha::Hold->delete should have deleted the hold" );
+
+ $number_of_logs = $schema->resultset('ActionLog')->search(
+ { module => 'HOLDS', action => 'DELETE', object => $hold->{ reserve_id } } )->count;
+ is( $number_of_logs, 1, 'With HoldsLogs, Koha::Hold->delete should have been logged' );
+
+ $schema->storage->txn_rollback();
+ };
+
+subtest 'suspend() tests' => sub {
+
+ plan tests => 18;
+
+ $schema->storage->txn_begin;
+
+ # Disable logging
+ t::lib::Mocks::mock_preference( 'HoldsLog', 0 );
+
+ my $hold = $builder->build_object(
+ { class => 'Koha::Holds',
+ value => { found => undef, suspend => 0, suspend_until => undef, waitingdate => undef }
+ }
+ );
+
+ ok( !$hold->is_suspended, 'Hold is not suspended' );
+ my $suspended = $hold->suspend_hold;
+ is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
+ is( $suspended->id, $hold->id, 'suspend returns the same object' );
+ ok( $suspended->is_suspended, 'The hold is suspended' );
+ is( $suspended->suspend_until, undef, 'It is an indefinite suspension' );
+
+ # resume the hold
+ $suspended->resume;
+ $hold->discard_changes;
+
+ # create a DT
+ my $date = dt_from_string()->add( days => 1 );
+ $suspended = $hold->suspend_hold( $date );
+ is( ref($suspended) , 'Koha::Hold', 'suspend returns the Koha::Hold object' );
+ is( $suspended->id, $hold->id, 'suspend returns the same object' );
+ ok( $suspended->is_suspended, 'The hold is suspended' );
+ is( $suspended->suspend_until, $date->truncate( to => 'day' ), 'It is an indefinite suspension' );
+
+ # resume the hold
+ $suspended->resume;
+ $hold->discard_changes;
+
+ # set hold found=W
+ $hold->set_waiting;
+ throws_ok
+ { $hold->suspend_hold; }
+ 'Koha::Exceptions::Hold::CannotSuspendFound',
+ 'Exception is thrown when a found hold is tried to suspend';
+
+ is( $@->status, 'W', 'Exception gets the \'status\' parameter set correctly' );
+
+ # set hold found=T
+ $hold->set_transfer;
+ throws_ok
+ { $hold->suspend_hold; }
+ 'Koha::Exceptions::Hold::CannotSuspendFound',
+ 'Exception is thrown when a found hold is tried to suspend';
+
+ is( $@->status, 'T', 'Exception gets the \'status\' parameter set correctly' );
+
+ # set hold found=T
+ $hold->set_processing();
+ throws_ok
+ { $hold->suspend_hold; }
+ 'Koha::Exceptions::Hold::CannotSuspendFound',
+ 'Exception is thrown when a found hold is tried to suspend';
+
+ is( $@->status, 'P', 'Exception gets the \'status\' parameter set correctly' );
+
+ my $holds_module = Test::MockModule->new('Koha::Hold');
+ $holds_module->mock( 'is_found', 1 );
+
+ # bad data case
+ $hold->found('X');
+ throws_ok
+ { $hold->suspend_hold }
+ 'Koha::Exceptions::Hold::CannotSuspendFound',
+ 'Exception is thrown when a found hold is tried to suspend';
+
+ is( $@->error, 'Unhandled data exception on found hold (id='
+ . $hold->id
+ . ', found='
+ . $hold->found
+ . ')' , 'Exception gets the \'status\' parameter set correctly' );
+
+ $holds_module->unmock( 'is_found' );
+
+ # Enable logging
+ t::lib::Mocks::mock_preference( 'HoldsLog', 1 );
+
+ my $logs_count = $schema->resultset('ActionLog')->search(
+ { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
+
+ $hold = $builder->build_object(
+ { class => 'Koha::Holds',
+ value => { suspend => 0, suspend_until => undef, waitingdate => undef, found => undef }
+ }
+ );
+
+ $hold->suspend_hold;
+ my $new_logs_count = $schema->resultset('ActionLog')->search(
+ { module => 'HOLDS', action => 'SUSPEND', object => $hold->id } )->count;
+
+ is( $new_logs_count, $logs_count + 1, 'If logging is enabled, suspending a hold gets logged' );
+
+ $schema->storage->txn_rollback;
+};