From aa9e7af9e2caf6e0334b5afbe4c2d15f39110f21 Mon Sep 17 00:00:00 2001 From: mbeaulieu Date: Fri, 27 Jun 2014 16:46:43 -0400 Subject: [PATCH] Bug 11055 - Add 'Minutes' as a load period unit WARNING: This patch is dependent on http://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=8133. My patch on bug 8133 ensures proper calculation of overdues. Minutes are added as a unit in circulation rules. A test script is provided: 't/Circulation/minuteloan.t'. --- C4/Circulation.pm | 11 +- C4/Overdues.pm | 4 +- Koha/Calendar.pm | 2 +- .../prog/en/modules/admin/smart-rules.tt | 3 +- misc/cronjobs/fines.pl | 2 +- t/Circulation/minuteloan.t | 166 ++++++++++++++++++++ 6 files changed, 181 insertions(+), 7 deletions(-) create mode 100755 t/Circulation/minuteloan.t diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 6650fcb..e782347 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -2104,6 +2104,8 @@ sub _debar_user_on_return { # finedays is in days, so hourly loans must multiply by 24 # thus 1 hour late equals 1 day suspension * finedays rate $finedays = $finedays * 24 if ( $unit eq 'hours' ); + $finedays = $finedays * 24 * 60 if ( $unit eq 'minutes' ); + # grace period is measured in the same units as the loan my $grace = @@ -3234,8 +3236,8 @@ C<$isrenewal> = Boolean: is true if we want to calculate the date due for a rene sub CapDateDue{ my ( $calcDueDate, $loanlength, $branch) = @_; - # for hourly loans, we will limit the due date to close time - return $calcDueDate unless ($loanlength->{lengthunit} eq 'hours'); + # for hours and minutes, we will limit the due date to close time + return $calcDueDate unless ($loanlength->{lengthunit} eq 'hours' || $loanlength->{lengthunit} eq 'minutes'); # my $now = DateTime->now( time_zone => C4::Context->tz() ); my $branchHours = getOpeningHours(); @@ -3286,6 +3288,8 @@ sub CalcDateDue { } else { $datedue->add( hours => $loanlength->{issuelength} ); } + } elsif ( $loanlength->{lengthunit} eq 'minutes' ) { + $datedue->add( minutes => $loanlength->{issuelength} ); }else { # days $datedue->add( days => $loanlength->{$length_key} ); $datedue->set_hour(23); @@ -3296,6 +3300,9 @@ sub CalcDateDue { if ($loanlength->{lengthunit} eq 'hours') { $dur = DateTime::Duration->new( hours => $loanlength->{$length_key}); } + elsif ($loanlength->{lengthunit} eq 'minutes') { + $dur = DateTime::Duration->new( minutes => $loanlength->{issuelength}); + } else { # days $dur = DateTime::Duration->new( days => $loanlength->{$length_key}); } diff --git a/C4/Overdues.pm b/C4/Overdues.pm index 3ed86f0..5f81507 100644 --- a/C4/Overdues.pm +++ b/C4/Overdues.pm @@ -139,7 +139,7 @@ LEFT JOIN biblioitems USING (biblioitemnumber) } if($params->{'shortrun'}){ - $statement .= " and issuingrules.lengthunit in ('hours') " ; + $statement .= " and issuingrules.lengthunit in ('hours', 'minutes') " ; } $statement .= 'ORDER BY borrowernumber'; @@ -292,7 +292,7 @@ sub _get_chargeable_units { my ($unit, $dt1, $dt2, $branchcode, $openingHours) = @_; my $charge_units = 0; my $charge_duration; - if ($unit eq 'hours') { + if ($unit eq 'hours' || $unit eq 'minutes') { if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') { if (!defined $openingHours->{$branchcode}{'Calendar'}){ $openingHours->{$branchcode}{'Calendar'} = Koha::Calendar->new( branchcode => $branchcode ); diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm index 7ef78d3..1edb538 100644 --- a/Koha/Calendar.pm +++ b/Koha/Calendar.pm @@ -125,7 +125,7 @@ sub addDate { $unit ||= 'days'; # default days ? my $dt; - if ( $unit eq 'hours' ) { + if ( $unit eq 'hours' || $unit eq 'minutes') { # Fixed for legacy support. Should be set as a branch parameter Readonly::Scalar my $return_by_hour => 10; diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt index a7fe76e..aa9ffce 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt @@ -242,6 +242,7 @@ for="tobranch">Clone these rules to: + @@ -253,7 +254,7 @@ for="tobranch">Clone these rules to:
[% INCLUDE 'date-format.inc' %]
- + diff --git a/misc/cronjobs/fines.pl b/misc/cronjobs/fines.pl index 2e7391e..b4d775b 100755 --- a/misc/cronjobs/fines.pl +++ b/misc/cronjobs/fines.pl @@ -65,7 +65,7 @@ This script has the following parameters : -l --log: log the output to a file (optional if the -o parameter is given) -o --out: ouput directory for logs (defaults to env or /tmp if !exist) -v --verbose - -s --short: only verifies the short duration borrowing (hourly) + -s --short: only verifies the short duration borrowing (minutes and hourly ones) ENDUSAGE diff --git a/t/Circulation/minuteloan.t b/t/Circulation/minuteloan.t new file mode 100755 index 0000000..0da4a7d --- /dev/null +++ b/t/Circulation/minuteloan.t @@ -0,0 +1,166 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use Data::Dumper; +use DateTime; +use DateTime::Duration; +use Test::More tests => 7; +use Test::MockModule; +use DBD::Mock; +use Koha::DateUtils; +use C4::Calendar qw(getOpeningHours); +use C4::Circulation qw(CalcDateDue); +use C4::Overdues qw(_get_chargeable_units Getoverdues); + +BEGIN { + die "DBD::Mock v$DBD::Mock::VERSION is too old. This test requires v1.45 or higher.", 33 + unless $DBD::Mock::VERSION >= 1.45; + + use_ok('Koha::Calendar'); + use_ok('C4::Calendar'); + use_ok('C4::Circulation'); + use_ok('C4::Overdues'); +} + +my $module_context = new Test::MockModule('C4::Context'); +$module_context->mock( + '_new_dbh', + sub { + my $dbh = DBI->connect( 'DBI:Mock:', '', '' ) + || die "Cannot create handle: $DBI::errstr\n"; + return $dbh; + } +); + +# Initialize the global $dbh variable +my $dbh = C4::Context->dbh(); + +{ # C4::Circulation + $module_context->mock('preference',sub {return 'Calendar';}); + + my $sessionCirc = DBD::Mock::Session->new('sessionCirc' => ( + { + statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/, + results => [ + [ 'issuelength', 'lengthunit', 'renewalperiod' ], + [ 30, 'minutes' , 0 ] + ] + }, + { + statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', + results => DBD::Mock->NULL_RESULTSET + }, + { + statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', + results => [ + ['day', 'month'], + [24,6] + ] + }, + { + statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1', + results => DBD::Mock->NULL_RESULTSET + }, + { + statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0', + results => DBD::Mock->NULL_RESULTSET + }, + { #GetIssuingRules called in GetHardDueDate + statement => qr/select \* from issuingrules/, + results => [ + ['hardduedate', 'hardduedatecompare'], + [undef,-1] + ] + }, + { #Opening hours + statement => 'SELECT * FROM openinghours ', + results => [ + ['branchcode', 'weekcode', 'openhour', 'closehour'], + ['BIB', 0, '09:00:00', '17:00:00'], + ['BIB', 1, '09:00:00', '17:00:00'], + ['BIB', 2, '09:00:00', '17:00:00'], + ['BIB', 3, '09:00:00', '17:00:00'], + ['BIB', 4, '09:00:00', '17:00:00'], + ['BIB', 5, '09:00:00', '17:00:00'], + ['BIB', 6, '09:00:00', '17:00:00'] + ] + } + )); + $dbh->{ mock_session } = $sessionCirc; + print "\nTesting C4::Circulation\n"; + is(CalcDateDue(dt_from_string('2014-06-23T16:40:00', 'iso'), 0, 'BIB',{categorycode => 0, dateexpiry => '2020'}, 0), dt_from_string('2014-06-23T17:00:00', 'iso'), "Testing minute loans. Due time capped at close time."); +} + +{ #C4::Overdues + print "\nTesting C4::Overdues\n"; + $module_context->mock('preference',sub {return 'noFinesWhenClosed';}); + print " finesCalendar syspref set to 'noFinesWhenClosed'\n"; + my $sessionOver = DBD::Mock::Session->new('sessionOver' =>( + { #Opening hours TEST #6 + statement => 'SELECT * FROM openinghours ', + results => [ + ['branchcode', 'weekcode', 'openhour', 'closehour'], + ['BIB', 0, '09:00:00', '17:00:00'], + ['BIB', 1, '09:00:00', '17:00:00'], + ['BIB', 2, '09:00:00', '17:00:00'], + ['BIB', 3, '09:00:00', '17:00:00'], + ['BIB', 4, '09:00:00', '17:00:00'], + ['BIB', 5, '09:00:00', '17:00:00'], + ['BIB', 6, '09:00:00', '17:00:00'] + ] + }, + { + statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', + results => DBD::Mock->NULL_RESULTSET + }, + { + statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', + results => [ + ['day', 'month'], + [24,6] + ] + }, + { #Opening hours TEST #7 + statement => 'SELECT * FROM openinghours ', + results => [ + ['branchcode', 'weekcode', 'openhour', 'closehour'], + ['BIB', 0, '09:00:00', '17:00:00'], + ['BIB', 1, '09:00:00', '17:00:00'], + ['BIB', 2, '09:00:00', '17:00:00'], + ['BIB', 3, '09:00:00', '17:00:00'], + ['BIB', 4, '09:00:00', '17:00:00'], + ['BIB', 5, '09:00:00', '17:00:00'], + ['BIB', 6, '09:00:00', '17:00:00'] + ] + }, + { + statement => qr/select \* from issuingrules/, + results => [ + [ 'issuelength', 'lengthunit', 'fine', 'chargeperiod', 'firstremind'], + [ 30, 'minutes' , 0.25, 1, 0 ] + ] + }, + { + statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL', + results => DBD::Mock->NULL_RESULTSET + }, + { + statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL', + results => DBD::Mock->NULL_RESULTSET + }, + { + statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1', + results => DBD::Mock->NULL_RESULTSET + }, + { + statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0', + results => DBD::Mock->NULL_RESULTSET + } + )); + $dbh->{ mock_session } = $sessionOver; + is(_get_chargeable_units('minutes', dt_from_string('2014-06-23T12:00:00', 'iso'), dt_from_string('2014-06-25T10:00:00', 'iso'), 'BIB', getOpeningHours()), 360, "Test if _get_chargeable_units takes opening hours and holidays into account."); + + my ($fine) = CalcFine( {itemtype=>'item'}, 0, 'BIB' ,dt_from_string('2014-6-23T12:00:00', 'iso'), dt_from_string('2014-6-23T13:00:00', 'iso'), getOpeningHours()); + is($fine, 15, 'Fines are calculated correctly for minute loans'); +} -- 1.7.9.5