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

(-)a/C4/Circulation.pm (-7 / +3 lines)
Lines 20-26 package C4::Circulation; Link Here
20
20
21
use Modern::Perl;
21
use Modern::Perl;
22
use DateTime;
22
use DateTime;
23
use POSIX qw( floor );
23
use POSIX qw( floor ceil );
24
use YAML::XS;
24
use YAML::XS;
25
use Encode;
25
use Encode;
26
26
Lines 2699-2712 sub _calculate_new_debar_dt { Link Here
2699
    );
2699
    );
2700
    my $finedays = $issuing_rule ? $issuing_rule->{finedays} : undef;
2700
    my $finedays = $issuing_rule ? $issuing_rule->{finedays} : undef;
2701
    my $unit     = $issuing_rule ? $issuing_rule->{lengthunit} : undef;
2701
    my $unit     = $issuing_rule ? $issuing_rule->{lengthunit} : undef;
2702
    my $chargeable_units = C4::Overdues::get_chargeable_units($unit, $dt_due, $return_date, $branchcode);
2702
    my $chargeable_units = C4::Overdues::get_chargeable_units('days', $dt_due, $return_date, $branchcode);
2703
2703
2704
    return unless $finedays;
2704
    return unless $finedays;
2705
2705
2706
    # finedays is in days, so hourly loans must multiply by 24
2707
    # thus 1 hour late equals 1 day suspension * finedays rate
2708
    $finedays = $finedays * 24 if ( $unit eq 'hours' );
2709
2710
    # grace period is measured in the same units as the loan
2706
    # grace period is measured in the same units as the loan
2711
    my $grace =
2707
    my $grace =
2712
      DateTime::Duration->new( $unit => $issuing_rule->{firstremind} // 0);
2708
      DateTime::Duration->new( $unit => $issuing_rule->{firstremind} // 0);
Lines 2721-2727 sub _calculate_new_debar_dt { Link Here
2721
        if ( defined $issuing_rule->{suspension_chargeperiod} && $issuing_rule->{suspension_chargeperiod} > 1 ) {
2717
        if ( defined $issuing_rule->{suspension_chargeperiod} && $issuing_rule->{suspension_chargeperiod} > 1 ) {
2722
            # No need to / 1 and do not consider / 0
2718
            # No need to / 1 and do not consider / 0
2723
            $suspension_days = DateTime::Duration->new(
2719
            $suspension_days = DateTime::Duration->new(
2724
                days => floor( $suspension_days->in_units('days') / $issuing_rule->{suspension_chargeperiod} )
2720
                days => ceil( $suspension_days->in_units('days') / $issuing_rule->{suspension_chargeperiod} )
2725
            );
2721
            );
2726
        }
2722
        }
2727
2723
(-)a/C4/Overdues.pm (-11 / +6 lines)
Lines 321-327 sub get_chargeable_units { Link Here
321
321
322
    my $charge_units = 0;
322
    my $charge_units = 0;
323
    my $charge_duration;
323
    my $charge_duration;
324
    if ($unit eq 'hours') {
325
        if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') {
324
        if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') {
326
            my $calendar = Koha::Calendar->new( branchcode => $branchcode );
325
            my $calendar = Koha::Calendar->new( branchcode => $branchcode );
327
            $charge_duration = $calendar->hours_between( $date_due, $date_returned );
326
            $charge_duration = $calendar->hours_between( $date_due, $date_returned );
Lines 331-346 sub get_chargeable_units { Link Here
331
        if($charge_duration->in_units('hours') == 0 && $charge_duration->in_units('seconds') > 0){
330
        if($charge_duration->in_units('hours') == 0 && $charge_duration->in_units('seconds') > 0){
332
            return 1;
331
            return 1;
333
        }
332
        }
334
        return $charge_duration->in_units('hours');
333
335
    }
334
    my $hours = $charge_duration->in_units('hours');
336
    else { # days
335
    if ($unit eq 'hours') {
337
        if(C4::Context->preference('finesCalendar') eq 'noFinesWhenClosed') {
336
        return $hours;
338
            my $calendar = Koha::Calendar->new( branchcode => $branchcode );
337
    } else {
339
            $charge_duration = $calendar->days_between( $date_due, $date_returned );
338
        return ( $hours > 0 ? ceil($hours / 24) : 0 );
340
        } else {
341
            $charge_duration = $date_returned->delta_days( $date_due );
342
        }
343
        return $charge_duration->in_units('days');
344
    }
339
    }
345
}
340
}
346
341
(-)a/t/db_dependent/Circulation/IssuingRules/maxsuspensiondays.t (-1 / +133 lines)
Line 0 Link Here
0
- 
1
use Modern::Perl;
2
use Test::More tests => 3;
3
4
use MARC::Record;
5
use MARC::Field;
6
use C4::Context;
7
8
use C4::Circulation qw( AddIssue AddReturn );
9
use C4::Items qw( AddItem );
10
use C4::Biblio qw( AddBiblio );
11
use Koha::Database;
12
use Koha::DateUtils;
13
use Koha::Patron::Debarments qw( GetDebarments DelDebarment );
14
use Koha::Patrons;
15
16
use t::lib::TestBuilder;
17
use t::lib::Mocks;
18
19
my $schema = Koha::Database->schema;
20
$schema->storage->txn_begin;
21
my $builder = t::lib::TestBuilder->new;
22
my $dbh = C4::Context->dbh;
23
$dbh->{RaiseError} = 1;
24
25
my $branchcode = $builder->build({ source => 'Branch' })->{branchcode};
26
my $itemtype   = $builder->build({ source => 'Itemtype' })->{itemtype};
27
my $patron_category = $builder->build({ source => 'Category' });
28
29
t::lib::Mocks::mock_userenv({ branchcode => $branchcode });
30
31
# Test without maxsuspensiondays set
32
Koha::IssuingRules->search->delete;
33
$builder->build(
34
    {
35
        source => 'Issuingrule',
36
        value  => {
37
            categorycode => '*',
38
            itemtype     => '*',
39
            branchcode   => '*',
40
            firstremind  => 0,
41
            finedays     => 2,
42
            lengthunit   => 'days',
43
            suspension_chargeperiod => 1,
44
        }
45
    }
46
);
47
48
my $borrowernumber = Koha::Patron->new({
49
    firstname =>  'my firstname',
50
    surname => 'my surname',
51
    categorycode => $patron_category->{categorycode},
52
    branchcode => $branchcode,
53
})->store->borrowernumber;
54
my $borrower = Koha::Patrons->find( $borrowernumber )->unblessed;
55
56
my $record = MARC::Record->new();
57
$record->append_fields(
58
    MARC::Field->new('100', ' ', ' ', a => 'My author'),
59
    MARC::Field->new('245', ' ', ' ', a => 'My title'),
60
);
61
62
my $barcode = 'bc_maxsuspensiondays';
63
my ($biblionumber, $biblioitemnumber) = AddBiblio($record, '');
64
my (undef, undef, $itemnumber) = AddItem({
65
        homebranch => $branchcode,
66
        holdingbranch => $branchcode,
67
        barcode => $barcode,
68
        itype => $itemtype
69
    } , $biblionumber);
70
71
# clear any holidays to avoid throwing off the suspension day
72
# calculations
73
$dbh->do('DELETE FROM special_holidays');
74
$dbh->do('DELETE FROM repeatable_holidays');
75
76
my $daysago20 = dt_from_string->add_duration(DateTime::Duration->new(days => -20));
77
my $daysafter40 = dt_from_string->add_duration(DateTime::Duration->new(days => 40));
78
79
AddIssue( $borrower, $barcode, $daysago20 );
80
AddReturn( $barcode, $branchcode );
81
my $debarments = GetDebarments({borrowernumber => $borrower->{borrowernumber}});
82
is(
83
    $debarments->[0]->{expiration},
84
    output_pref({ dt => $daysafter40, dateformat => 'iso', dateonly => 1 }),
85
    'calculate suspension with no maximum set'
86
);
87
DelDebarment( $debarments->[0]->{borrower_debarment_id} );
88
89
# Test with maxsuspensiondays = 10 days
90
my $issuing_rule = Koha::IssuingRules->search->next;
91
$issuing_rule->maxsuspensiondays( 10 )->store;
92
93
my $daysafter10 = dt_from_string->add_duration(DateTime::Duration->new(days => 10));
94
AddIssue( $borrower, $barcode, $daysago20 );
95
AddReturn( $barcode, $branchcode );
96
$debarments = GetDebarments({borrowernumber => $borrower->{borrowernumber}});
97
is(
98
    $debarments->[0]->{expiration},
99
    output_pref({ dt => $daysafter10, dateformat => 'iso', dateonly => 1 }),
100
    'calculate suspension with a maximum set'
101
);
102
DelDebarment( $debarments->[0]->{borrower_debarment_id} );
103
104
# Test with lengthunit => 'hours'
105
Koha::IssuingRules->search->delete;
106
$builder->build(
107
    {
108
        source => 'Issuingrule',
109
        value  => {
110
            categorycode => '*',
111
            itemtype     => '*',
112
            branchcode   => '*',
113
            firstremind  => 0,
114
            finedays     => 2,
115
            lengthunit   => 'hours',
116
            suspension_chargeperiod => 1,
117
            maxsuspensiondays => 100,
118
        }
119
    }
120
);
121
122
$daysafter10 = dt_from_string->add_duration(DateTime::Duration->new(days => 10));
123
AddIssue( $borrower, $barcode, $daysago20 );
124
AddReturn( $barcode, $branchcode );
125
$debarments = GetDebarments({borrowernumber => $borrower->{borrowernumber}});
126
is(
127
    $debarments->[0]->{expiration},
128
    output_pref({ dt => $daysafter40, dateformat => 'iso', dateonly => 1 }),
129
    'calculate suspension with lengthunit hours.'
130
);
131
DelDebarment( $debarments->[0]->{borrower_debarment_id} );
132
133
$schema->storage->txn_rollback;

Return to bug 14293