View | Details | Raw Unified | Return to bug 11055
Collapse All | Expand All

(-)a/C4/Circulation.pm (-2 / +9 lines)
Lines 2104-2109 sub _debar_user_on_return { Link Here
2104
        # finedays is in days, so hourly loans must multiply by 24
2104
        # finedays is in days, so hourly loans must multiply by 24
2105
        # thus 1 hour late equals 1 day suspension * finedays rate
2105
        # thus 1 hour late equals 1 day suspension * finedays rate
2106
        $finedays = $finedays * 24 if ( $unit eq 'hours' );
2106
        $finedays = $finedays * 24 if ( $unit eq 'hours' );
2107
        $finedays = $finedays * 24 * 60 if ( $unit eq 'minutes' );
2108
2107
2109
2108
        # grace period is measured in the same units as the loan
2110
        # grace period is measured in the same units as the loan
2109
        my $grace =
2111
        my $grace =
Lines 3234-3241 C<$isrenewal> = Boolean: is true if we want to calculate the date due for a rene Link Here
3234
sub CapDateDue{
3236
sub CapDateDue{
3235
    my ( $calcDueDate, $loanlength, $branch) = @_;
3237
    my ( $calcDueDate, $loanlength, $branch) = @_;
3236
3238
3237
    # for hourly loans, we will limit the due date to close time
3239
    # for hours and minutes, we will limit the due date to close time
3238
    return $calcDueDate unless ($loanlength->{lengthunit} eq 'hours');
3240
    return $calcDueDate unless ($loanlength->{lengthunit} eq 'hours' || $loanlength->{lengthunit} eq 'minutes');
3239
3241
3240
#    my $now = DateTime->now( time_zone => C4::Context->tz() );
3242
#    my $now = DateTime->now( time_zone => C4::Context->tz() );
3241
    my $branchHours = getOpeningHours();
3243
    my $branchHours = getOpeningHours();
Lines 3286-3291 sub CalcDateDue { Link Here
3286
            } else {
3288
            } else {
3287
                $datedue->add( hours => $loanlength->{issuelength} );
3289
                $datedue->add( hours => $loanlength->{issuelength} );
3288
            }
3290
            }
3291
        } elsif ( $loanlength->{lengthunit} eq 'minutes' ) {
3292
                $datedue->add( minutes => $loanlength->{issuelength} );
3289
        }else {    # days
3293
        }else {    # days
3290
            $datedue->add( days => $loanlength->{$length_key} );
3294
            $datedue->add( days => $loanlength->{$length_key} );
3291
            $datedue->set_hour(23);
3295
            $datedue->set_hour(23);
Lines 3296-3301 sub CalcDateDue { Link Here
3296
        if ($loanlength->{lengthunit} eq 'hours') {
3300
        if ($loanlength->{lengthunit} eq 'hours') {
3297
            $dur = DateTime::Duration->new( hours => $loanlength->{$length_key});
3301
            $dur = DateTime::Duration->new( hours => $loanlength->{$length_key});
3298
        }
3302
        }
3303
        elsif ($loanlength->{lengthunit} eq 'minutes') {
3304
            $dur = DateTime::Duration->new( minutes => $loanlength->{issuelength});
3305
        }
3299
        else { # days
3306
        else { # days
3300
            $dur = DateTime::Duration->new( days => $loanlength->{$length_key});
3307
            $dur = DateTime::Duration->new( days => $loanlength->{$length_key});
3301
        }
3308
        }
(-)a/C4/Overdues.pm (-2 / +2 lines)
Lines 139-145 LEFT JOIN biblioitems USING (biblioitemnumber) Link Here
139
    }
139
    }
140
140
141
    if($params->{'shortrun'}){
141
    if($params->{'shortrun'}){
142
        $statement .= " and issuingrules.lengthunit in ('hours')  " ;
142
        $statement .= " and issuingrules.lengthunit in ('hours', 'minutes')  " ;
143
    }
143
    }
144
144
145
    $statement .= 'ORDER BY borrowernumber';
145
    $statement .= 'ORDER BY borrowernumber';
Lines 292-298 sub _get_chargeable_units { Link Here
292
    my ($unit, $dt1, $dt2, $branchcode, $openingHours) = @_;
292
    my ($unit, $dt1, $dt2, $branchcode, $openingHours) = @_;
293
    my $charge_units = 0;
293
    my $charge_units = 0;
294
    my $charge_duration;
294
    my $charge_duration;
295
    if ($unit eq 'hours') {
295
    if ($unit eq 'hours' || $unit eq 'minutes') {
296
        if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') {
296
        if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') {
297
            if (!defined $openingHours->{$branchcode}{'Calendar'}){
297
            if (!defined $openingHours->{$branchcode}{'Calendar'}){
298
                $openingHours->{$branchcode}{'Calendar'} = Koha::Calendar->new( branchcode => $branchcode );
298
                $openingHours->{$branchcode}{'Calendar'} = Koha::Calendar->new( branchcode => $branchcode );
(-)a/Koha/Calendar.pm (-1 / +1 lines)
Lines 125-131 sub addDate { Link Here
125
    $unit ||= 'days'; # default days ?
125
    $unit ||= 'days'; # default days ?
126
    my $dt;
126
    my $dt;
127
127
128
    if ( $unit eq 'hours' ) {
128
    if ( $unit eq 'hours' || $unit eq 'minutes') {
129
        # Fixed for legacy support. Should be set as a branch parameter
129
        # Fixed for legacy support. Should be set as a branch parameter
130
        Readonly::Scalar my $return_by_hour => 10;
130
        Readonly::Scalar my $return_by_hour => 10;
131
131
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (-1 / +2 lines)
Lines 242-247 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
242
                      <select name="lengthunit" id="lengthunit">
242
                      <select name="lengthunit" id="lengthunit">
243
                        <option value="days" selected>Days</option>
243
                        <option value="days" selected>Days</option>
244
                        <option value="hours">Hours</option>
244
                        <option value="hours">Hours</option>
245
                        <option value="minutes">Minutes</option>
245
                      </select>
246
                      </select>
246
                    </td>
247
                    </td>
247
                    <td>
248
                    <td>
Lines 253-259 for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidde Link Here
253
                        <input type="text" size="10" id="hardduedate" name="hardduedate" value="[% hardduedate %]" class="datepicker" />
254
                        <input type="text" size="10" id="hardduedate" name="hardduedate" value="[% hardduedate %]" class="datepicker" />
254
                        <div class="hint">[% INCLUDE 'date-format.inc' %]</div>
255
                        <div class="hint">[% INCLUDE 'date-format.inc' %]</div>
255
                    </td>
256
                    </td>
256
                    <td><input type="text" name="fine" id="fine" size="4" /></td>
257
                    <td><input type="text" name="fine" id="fFine" size="4" /></td>
257
                    <td><input type="text" name="chargeperiod" id="chargeperiod" size="2" /></td>
258
                    <td><input type="text" name="chargeperiod" id="chargeperiod" size="2" /></td>
258
                    <td><input type="text" name="firstremind" id="firstremind" size="2" /> </td>
259
                    <td><input type="text" name="firstremind" id="firstremind" size="2" /> </td>
259
                    <td><input type="text" name="overduefinescap" id="overduefinescap" size="6" /> </td>
260
                    <td><input type="text" name="overduefinescap" id="overduefinescap" size="6" /> </td>
(-)a/misc/cronjobs/fines.pl (-1 / +1 lines)
Lines 65-71 This script has the following parameters : Link Here
65
    -l --log: log the output to a file (optional if the -o parameter is given)
65
    -l --log: log the output to a file (optional if the -o parameter is given)
66
    -o --out:  ouput directory for logs (defaults to env or /tmp if !exist)
66
    -o --out:  ouput directory for logs (defaults to env or /tmp if !exist)
67
    -v --verbose
67
    -v --verbose
68
    -s --short: only verifies the short duration borrowing (hourly)
68
    -s --short: only verifies the short duration borrowing (minutes and hourly ones)
69
69
70
ENDUSAGE
70
ENDUSAGE
71
71
(-)a/t/Circulation/minuteloan.t (-1 / +166 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
use strict;
4
use warnings;
5
use Data::Dumper;
6
use DateTime;
7
use DateTime::Duration;
8
use Test::More tests => 7;
9
use Test::MockModule;
10
use DBD::Mock;
11
use Koha::DateUtils;
12
use C4::Calendar qw(getOpeningHours);
13
use C4::Circulation qw(CalcDateDue);
14
use C4::Overdues qw(_get_chargeable_units Getoverdues);
15
16
BEGIN {
17
    die "DBD::Mock v$DBD::Mock::VERSION is too old. This test requires v1.45 or higher.", 33
18
    unless $DBD::Mock::VERSION >= 1.45;
19
20
    use_ok('Koha::Calendar');
21
    use_ok('C4::Calendar');
22
    use_ok('C4::Circulation');
23
    use_ok('C4::Overdues');
24
}
25
26
my $module_context = new Test::MockModule('C4::Context');
27
$module_context->mock(
28
    '_new_dbh',
29
    sub {
30
        my $dbh = DBI->connect( 'DBI:Mock:', '', '' )
31
          || die "Cannot create handle: $DBI::errstr\n";
32
        return $dbh;
33
    }
34
);
35
36
# Initialize the global $dbh variable
37
my $dbh = C4::Context->dbh();
38
39
{ # C4::Circulation
40
    $module_context->mock('preference',sub {return 'Calendar';});
41
42
    my $sessionCirc = DBD::Mock::Session->new('sessionCirc' => (
43
        {
44
           statement => qr/\s*SELECT issuelength, lengthunit, renewalperiod/,
45
           results  => [
46
                            [ 'issuelength', 'lengthunit', 'renewalperiod' ],
47
                            [ 30, 'minutes' , 0 ]
48
                        ]
49
        },
50
        {
51
            statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL',
52
            results => DBD::Mock->NULL_RESULTSET
53
        },
54
        {
55
            statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL',
56
            results => [
57
                            ['day', 'month'],
58
                            [24,6]
59
                        ]
60
        },
61
        {
62
            statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1',
63
            results => DBD::Mock->NULL_RESULTSET
64
        },
65
        {
66
            statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0',
67
            results => DBD::Mock->NULL_RESULTSET
68
        },
69
        { #GetIssuingRules called in GetHardDueDate
70
            statement => qr/select \* from issuingrules/,
71
            results => [
72
                            ['hardduedate', 'hardduedatecompare'],
73
                            [undef,-1]
74
                        ]
75
        },
76
        { #Opening hours
77
            statement => 'SELECT * FROM openinghours ',
78
            results => [
79
                            ['branchcode', 'weekcode', 'openhour', 'closehour'],
80
                            ['BIB', 0, '09:00:00', '17:00:00'],
81
                            ['BIB', 1, '09:00:00', '17:00:00'],
82
                            ['BIB', 2, '09:00:00', '17:00:00'],
83
                            ['BIB', 3, '09:00:00', '17:00:00'],
84
                            ['BIB', 4, '09:00:00', '17:00:00'],
85
                            ['BIB', 5, '09:00:00', '17:00:00'],
86
                            ['BIB', 6, '09:00:00', '17:00:00']
87
                        ]
88
        }
89
    ));
90
    $dbh->{ mock_session } = $sessionCirc;
91
    print "\nTesting C4::Circulation\n";
92
    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.");
93
}
94
95
{ #C4::Overdues
96
    print "\nTesting C4::Overdues\n";
97
    $module_context->mock('preference',sub {return 'noFinesWhenClosed';});
98
    print "  finesCalendar syspref set to 'noFinesWhenClosed'\n";
99
    my $sessionOver = DBD::Mock::Session->new('sessionOver' =>(
100
        { #Opening hours TEST #6
101
            statement => 'SELECT * FROM openinghours ',
102
            results => [
103
                            ['branchcode', 'weekcode', 'openhour', 'closehour'],
104
                            ['BIB', 0, '09:00:00', '17:00:00'],
105
                            ['BIB', 1, '09:00:00', '17:00:00'],
106
                            ['BIB', 2, '09:00:00', '17:00:00'],
107
                            ['BIB', 3, '09:00:00', '17:00:00'],
108
                            ['BIB', 4, '09:00:00', '17:00:00'],
109
                            ['BIB', 5, '09:00:00', '17:00:00'],
110
                            ['BIB', 6, '09:00:00', '17:00:00']
111
                        ]
112
        },
113
        {
114
            statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL',
115
            results => DBD::Mock->NULL_RESULTSET
116
        },
117
        {
118
            statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL',
119
            results => [
120
                            ['day', 'month'],
121
                            [24,6]
122
                       ]
123
        },
124
        { #Opening hours TEST #7
125
            statement => 'SELECT * FROM openinghours ',
126
            results => [
127
                            ['branchcode', 'weekcode', 'openhour', 'closehour'],
128
                            ['BIB', 0, '09:00:00', '17:00:00'],
129
                            ['BIB', 1, '09:00:00', '17:00:00'],
130
                            ['BIB', 2, '09:00:00', '17:00:00'],
131
                            ['BIB', 3, '09:00:00', '17:00:00'],
132
                            ['BIB', 4, '09:00:00', '17:00:00'],
133
                            ['BIB', 5, '09:00:00', '17:00:00'],
134
                            ['BIB', 6, '09:00:00', '17:00:00']
135
                        ]
136
        },
137
        {
138
            statement => qr/select \* from issuingrules/,
139
            results  => [
140
                            [ 'issuelength', 'lengthunit', 'fine', 'chargeperiod', 'firstremind'],
141
                            [ 30, 'minutes' , 0.25, 1, 0 ]
142
                        ]
143
        },
144
        {
145
            statement => 'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL',
146
            results => DBD::Mock->NULL_RESULTSET
147
        },
148
        {
149
            statement => 'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL',
150
            results => DBD::Mock->NULL_RESULTSET
151
        },
152
        {
153
            statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1',
154
            results => DBD::Mock->NULL_RESULTSET
155
        },
156
        {
157
            statement => 'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0',
158
            results => DBD::Mock->NULL_RESULTSET
159
        }
160
    ));
161
    $dbh->{ mock_session } = $sessionOver;
162
    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.");
163
164
    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());
165
    is($fine, 15, 'Fines are calculated correctly for minute loans');
166
}

Return to bug 11055