Koha/t/db_dependent/Circulation/CalcDateDue.t
David Gustafsson f726558510
Bug 32496: Reduce unnecessary unblessings of objects in Circulation.pm
Refactor the most performance critical subroutines in Circulation.pm
to take objects instead of unblessed ones to reduce unnecessary
unblessings and generally clean up the code.

To test:

1) Ensure the following tests all pass:
  t/db_dependent/Circulation.t
  t/db_dependent/Circulation/CalcDateDue.t
  t/db_dependent/Circulation/CheckIfIssuedToPatron.t
  t/db_dependent/Circulation/GetPendingOnSiteCheckouts.t
  t/db_dependent/Circulation/GetTopIssues.t
  t/db_dependent/Circulation/IsItemIssued.t
  t/db_dependent/Circulation/MarkIssueReturned.t
  t/db_dependent/Circulation/ReturnClaims.t
  t/db_dependent/Circulation/Returns.t
  t/db_dependent/Circulation/SwitchOnSiteCheckouts.t
  t/db_dependent/Circulation/TooMany.t
  t/db_dependent/Circulation/dateexpiry.t
  t/db_dependent/Circulation/issue.t
  t/db_dependent/Circulation/maxsuspensiondays.t
  t/db_dependent/Circulation/transferbook.t
  t/db_dependent/Circulation_holdsqueue.t
  t/db_dependent/DecreaseLoanHighHolds.t
  t/db_dependent/Holds/DisallowHoldIfItemsAvailable.t
  t/db_dependent/Holds/RevertWaitingStatus.t
  t/db_dependent/ILSDI_Services.t
  t/db_dependent/Illrequests.t
  t/db_dependent/Koha/Account/Line.t
  t/db_dependent/Koha/Biblio.t
  t/db_dependent/Koha/Items.t
  t/db_dependent/Koha/Object.t
  t/db_dependent/Koha/Patrons.t
  t/db_dependent/Koha/Pseudonymization.t
  t/db_dependent/Koha/Template/Plugin/CirculationRules.t
  t/db_dependent/Letters/TemplateToolkit.t
  t/db_dependent/Members/GetAllIssues.t
  t/db_dependent/Members/IssueSlip.t
  t/db_dependent/Patron/Borrower_Discharge.t
  t/db_dependent/Patron/Borrower_PrevCheckout.t
  t/db_dependent/SIP/ILS.t
  t/db_dependent/Holds.t
  t/db_dependent/Holds/LocalHoldsPriority.t
  t/db_dependent/Holds/HoldFulfillmentPolicy.t
  t/db_dependent/Holds/HoldItemtypeLimit.t
  t/db_dependent/Reserves/GetReserveFee.t
  t/db_dependent/api/v1/return_claims.t
  t/db_dependent/api/v1/biblios.t
  t/db_dependent/api/v1/checkouts.t
  t/db_dependent/Reserves.t
  t/db_dependent/HoldsQueue.t
  t/db_dependent/selenium/regressions.t
  t/db_dependent/Koha/Plugins/Circulation_hooks.t
  t/db_dependent/Koha/Plugins/Recall_hooks.t
  t/db_dependent/Koha/Recalls.t
  t/db_dependent/Koha/Recall.t
  t/db_dependent/Circulation/_CalculateAndUpdateFine.t

Sponsored-by: Gothenburg University Library

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
2023-09-22 10:52:39 -03:00

360 lines
14 KiB
Perl
Executable file

#!/usr/bin/perl
use Modern::Perl;
use Test::More tests => 19;
use Test::MockModule;
use DBI;
use DateTime;
use t::lib::Mocks;
use t::lib::TestBuilder;
use C4::Calendar qw( new insert_single_holiday delete_holiday insert_week_day_holiday );
use Koha::CirculationRules;
use_ok('C4::Circulation', qw( CalcDateDue ));
my $schema = Koha::Database->new->schema;
$schema->storage->txn_begin;
my $builder = t::lib::TestBuilder->new;
my $library = $builder->build_object({ class => 'Koha::Libraries' })->store;
my $dateexpiry = '2013-01-01';
my $patron_category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { category_type => 'B' } })->store;
my $borrower = $builder->build_object(
{
class => 'Koha::Patrons',
value => {
categorycode => $patron_category->categorycode,
dateexpiry => $dateexpiry,
}
}
)->store;
my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' })->store->itemtype;
my $issuelength = 10;
my $renewalperiod = 5;
my $lengthunit = 'days';
Koha::CirculationRules->search()->delete();
Koha::CirculationRules->set_rules(
{
categorycode => $patron_category->categorycode,
itemtype => $itemtype,
branchcode => $library->branchcode,
rules => {
issuelength => $issuelength,
renewalperiod => $renewalperiod,
lengthunit => $lengthunit,
}
}
);
#Set syspref ReturnBeforeExpiry = 1 and useDaysMode = 'Days'
t::lib::Mocks::mock_preference('ReturnBeforeExpiry', 1);
t::lib::Mocks::mock_preference('useDaysMode', 'Days');
my $branchcode = $library->branchcode;
my $cache = Koha::Caches->get_instance();
my $key = $branchcode . "_holidays";
$cache->clear_from_cache($key);
my $start_date = DateTime->new({year => 2013, month => 2, day => 9});
my $date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
is($date, $dateexpiry . 'T23:59:00', 'date expiry');
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
#Set syspref ReturnBeforeExpiry = 1 and useDaysMode != 'Days'
t::lib::Mocks::mock_preference('ReturnBeforeExpiry', 1);
t::lib::Mocks::mock_preference('useDaysMode', 'noDays');
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
is($date, $dateexpiry . 'T23:59:00', 'date expiry with useDaysMode to noDays');
# Let's add a special holiday on 2013-01-01. With ReturnBeforeExpiry and
# useDaysMode different from 'Days', return should forward the dateexpiry.
my $calendar = C4::Calendar->new(branchcode => $branchcode);
$calendar->insert_single_holiday(
day => 1,
month => 1,
year => 2013,
title =>'holidayTest',
description => 'holidayDesc'
);
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
is($date, '2012-12-31T23:59:00', 'date expiry should be 2013-01-01 -1 day');
$calendar->insert_single_holiday(
day => 31,
month => 12,
year => 2012,
title =>'holidayTest',
description => 'holidayDesc'
);
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
is($date, '2012-12-30T23:59:00', 'date expiry should be 2013-01-01 -2 day');
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
#Set syspref ReturnBeforeExpiry = 0 and useDaysMode = 'Days'
t::lib::Mocks::mock_preference('ReturnBeforeExpiry', 0);
t::lib::Mocks::mock_preference('useDaysMode', 'Days');
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
is($date, '2013-02-' . (9 + $issuelength) . 'T23:59:00', "date expiry ( 9 + $issuelength )");
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
is($date, '2013-02-' . (9 + $renewalperiod) . 'T23:59:00', "date expiry ( 9 + $renewalperiod )");
# Now we want to test the Dayweek useDaysMode option
# For this we need a loan period that is a mutiple of 7 days
# But, since we currently don't have that, let's test it does the
# right thing in that case, it should act as though useDaysMode is set to
# Datedue
#Set syspref ReturnBeforeExpiry = 0 and useDaysMode = 'Dayweek'
t::lib::Mocks::mock_preference('ReturnBeforeExpiry', 0);
t::lib::Mocks::mock_preference('useDaysMode', 'Dayweek');
# No closed day interfering, so we should get the regular due date
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
is($date, '2013-02-' . (9 + $issuelength) . 'T23:59:00', "useDaysMode = Dayweek, no closed days, issue date expiry ( start + $issuelength )");
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
is($date, '2013-02-' . (9 + $renewalperiod) . 'T23:59:00', "useDaysMode = Dayweek, no closed days, renewal date expiry ( start + $renewalperiod )");
# Now let's add a closed day on the expected renewal date, it should
# roll forward as per Datedue (i.e. one day at a time)
# For issues...
$calendar->insert_single_holiday(
day => 9 + $issuelength,
month => 2,
year => 2013,
title =>'DayweekTest1',
description => 'DayweekTest1'
);
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
is($date, '2013-02-' . (9 + $issuelength + 1) . 'T23:59:00', "useDaysMode = Dayweek, closed on due date, 10 day loan (should not trigger 7 day roll forward), issue date expiry ( start + $issuelength + 1 )");
# Remove the holiday we just created
$calendar->delete_holiday(
day => 9 + $issuelength,
month => 2,
year => 2013
);
# ...and for renewals...
$calendar->insert_single_holiday(
day => 9 + $renewalperiod,
month => 2,
year => 2013,
title =>'DayweekTest2',
description => 'DayweekTest2'
);
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
is($date, '2013-02-' . (9 + $renewalperiod + 1) . 'T23:59:00', "useDaysMode = Dayweek, closed on due date, 5 day renewal (should not trigger 7 day roll forward), renewal date expiry ( start + $renewalperiod + 1 )");
# Remove the holiday we just created
$calendar->delete_holiday(
day => 9 + $renewalperiod,
month => 2,
year => 2013,
);
# Now we test it does the right thing if the loan and renewal periods
# are a multiple of 7 days
my $dayweek_issuelength = 14;
my $dayweek_renewalperiod = 7;
my $dayweek_lengthunit = 'days';
$patron_category = $builder->build_object({ class => 'Koha::Patron::Categories', value => { category_type => 'K' } })->store;
Koha::CirculationRules->set_rules(
{
categorycode => $patron_category->categorycode,
itemtype => $itemtype,
branchcode => $branchcode,
rules => {
issuelength => $dayweek_issuelength,
renewalperiod => $dayweek_renewalperiod,
lengthunit => $dayweek_lengthunit,
}
}
);
my $dayweek_borrower = $builder->build_object(
{
class => 'Koha::Patrons',
value => {
categorycode => $patron_category->categorycode,
dateexpiry => $dateexpiry,
}
}
);
# For issues...
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
$calendar->insert_single_holiday(
day => 9 + $dayweek_issuelength,
month => 2,
year => 2013,
title =>'DayweekTest3',
description => 'DayweekTest3'
);
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
my $issue_should_add = $dayweek_issuelength + 7;
my $dayweek_issue_expected = $start_date->add( days => $issue_should_add );
is($date, $dayweek_issue_expected->strftime('%F') . 'T23:59:00', "useDaysMode = Dayweek, closed on due date, 14 day loan (should trigger 7 day roll forward), issue date expiry ( start + $issue_should_add )");
# Remove the holiday we just created
$calendar->delete_holiday(
day => 9 + $dayweek_issuelength,
month => 2,
year => 2013,
);
# ...and for renewals...
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
$calendar->insert_single_holiday(
day => 9 + $dayweek_renewalperiod,
month => 2,
year => 2013,
title => 'DayweekTest4',
description => 'DayweekTest4'
);
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower, 1 );
my $renewal_should_add = $dayweek_renewalperiod + 7;
my $dayweek_renewal_expected = $start_date->add( days => $renewal_should_add );
is($date, $dayweek_renewal_expected->strftime('%F') . 'T23:59:00', "useDaysMode = Dayweek, closed on due date, 7 day renewal (should trigger 7 day roll forward), renewal date expiry ( start + $renewal_should_add )");
# Remove the holiday we just created
$calendar->delete_holiday(
day => 9 + $dayweek_renewalperiod,
month => 2,
year => 2013,
);
# Now test it continues to roll forward by 7 days until it finds
# an open day, so we create a 3 week period of closed Saturdays
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
my $expected_rolled_date = DateTime->new({year => 2013, month => 3, day => 9});
my $holiday = $start_date->clone();
$holiday->add(days => 7);
$calendar->insert_single_holiday(
day => $holiday->day,
month => $holiday->month,
year => 2013,
title =>'DayweekTest5',
description => 'DayweekTest5'
);
$holiday->add(days => 7);
$calendar->insert_single_holiday(
day => $holiday->day,
month => $holiday->month,
year => 2013,
title =>'DayweekTest6',
description => 'DayweekTest6'
);
$holiday->add(days => 7);
$calendar->insert_single_holiday(
day => $holiday->day,
month => $holiday->month,
year => 2013,
title =>'DayweekTest7',
description => 'DayweekTest7'
);
# For issues...
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
$dayweek_issue_expected = $start_date->add( days => $issue_should_add );
is($date, $expected_rolled_date->strftime('%F') . 'T23:59:00', "useDaysMode = Dayweek, closed on due date and two subequent due dates, 14 day loan (should trigger 2 x 7 day roll forward), issue date expiry ( start + 28 )");
# ...and for renewals...
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower, 1 );
$dayweek_issue_expected = $start_date->add( days => $renewal_should_add );
is($date, $expected_rolled_date->strftime('%F') . 'T23:59:00', "useDaysMode = Dayweek, closed on due date and three subsequent due dates, 7 day renewal (should trigger 3 x 7 day roll forward), issue date expiry ( start + 28 )");
# Remove the holidays we just created
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
my $del_holiday = $start_date->clone();
$del_holiday->add(days => 7);
$calendar->delete_holiday(
day => $del_holiday->day,
month => $del_holiday->month,
year => 2013
);
$del_holiday->add(days => 7);
$calendar->delete_holiday(
day => $del_holiday->day,
month => $del_holiday->month,
year => 2013
);
$del_holiday->add(days => 7);
$calendar->delete_holiday(
day => $del_holiday->day,
month => $del_holiday->month,
year => 2013
);
# Now test that useDaysMode "Dayweek" doesn't try to roll forward onto
# a permanently closed day and instead rolls forward just one day
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
# Our tests are concerned with Saturdays, so let's close on Saturdays
$calendar->insert_week_day_holiday(
weekday => 6,
title => "Saturday closure",
description => "Closed on Saturdays"
);
# For issues...
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
$dayweek_issue_expected = $start_date->add( days => $dayweek_issuelength + 1 );
is($date, $dayweek_issue_expected->strftime('%F') . 'T23:59:00', "useDaysMode = Dayweek, due on Saturday, closed on Saturdays, 14 day loan (should trigger 1 day roll forward), issue date expiry ( start + 15 )");
# ...and for renewals...
$start_date = DateTime->new({year => 2013, month => 2, day => 9});
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower, 1 );
$dayweek_renewal_expected = $start_date->add( days => $dayweek_renewalperiod + 1 );
is($date, $dayweek_renewal_expected->strftime('%F') . 'T23:59:00', "useDaysMode = Dayweek, due on Saturday, closed on Saturdays, 7 day renewal (should trigger 1 day roll forward), issue date expiry ( start + 8 )");
# Remove the holiday we just created
$calendar->delete_holiday(
weekday => 6
);
# Renewal period of 0 is valid
Koha::CirculationRules->search()->delete();
Koha::CirculationRules->set_rules(
{
categorycode => undef,
itemtype => undef,
branchcode => undef,
rules => {
issuelength => 9999,
renewalperiod => 0,
lengthunit => 'days',
daysmode => 'Days',
}
}
);
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
is( $date->ymd, $start_date->ymd, "Dates should match for renewalperiod of 0" );
# Renewal period of "" should trigger fallover to issuelength for renewal
Koha::CirculationRules->search()->delete();
Koha::CirculationRules->set_rules(
{
categorycode => undef,
itemtype => undef,
branchcode => undef,
rules => {
issuelength => 7,
renewalperiod => q{},
lengthunit => 'days',
daysmode => 'Days',
}
}
);
my $renewed_date = $start_date->clone->add( days => 7 );
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
is( $date->ymd, $renewed_date->ymd, 'Renewal period of "" should trigger fallover to issuelength for renewal' );
$cache->clear_from_cache($key);
$schema->storage->txn_rollback;