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

(-)a/C4/Circulation.pm (-3 / +4 lines)
Lines 3007-3026 sub CalcDateDue { Link Here
3007
    } else {
3007
    } else {
3008
3008
3009
        # otherwise, calculate the datedue as normal
3009
        # otherwise, calculate the datedue as normal
3010
        if ( C4::Context->preference('useDaysMode') eq 'Days' )
3010
        if ( C4::Context->preference('useDaysMode') ne 'Calendar' )
3011
        {    # ignoring calendar
3011
        {    # ignoring calendar
3012
            my $dt =
3012
            my $dt =
3013
              DateTime->now( time_zone => C4::Context->tz() )
3013
              DateTime->now( time_zone => C4::Context->tz() )
3014
              ->truncate( to => 'minute' );
3014
              ->truncate( to => 'minute' );
3015
            if ( $loanlength->{lengthunit} eq 'hours' ) {
3015
            if ( $loanlength->{lengthunit} eq 'hours' ) {
3016
                $dt->add( hours => $loanlength->{issuelength} );
3016
                $dt->add( hours => $loanlength->{issuelength} );
3017
                return $dt;
3018
            } else {    # days
3017
            } else {    # days
3019
                $dt->add( days => $loanlength->{issuelength} );
3018
                $dt->add( days => $loanlength->{issuelength} );
3020
                $dt->set_hour(23);
3019
                $dt->set_hour(23);
3021
                $dt->set_minute(59);
3020
                $dt->set_minute(59);
3022
                return $dt;
3023
            }
3021
            }
3022
3023
            return $dt;
3024
3024
        } else {
3025
        } else {
3025
            my $dur;
3026
            my $dur;
3026
            if ($loanlength->{lengthunit} eq 'hours') {
3027
            if ($loanlength->{lengthunit} eq 'hours') {
(-)a/Koha/Calendar.pm (-38 / +141 lines)
Lines 85-141 sub _init { Link Here
85
85
86
sub addDate {
86
sub addDate {
87
    my ( $self, $startdate, $add_duration, $unit ) = @_;
87
    my ( $self, $startdate, $add_duration, $unit ) = @_;
88
    my $base_date = $startdate->clone();
88
89
    # Default to days duration (legacy support I guess)
89
    if ( ref $add_duration ne 'DateTime::Duration' ) {
90
    if ( ref $add_duration ne 'DateTime::Duration' ) {
90
        $add_duration = DateTime::Duration->new( days => $add_duration );
91
        $add_duration = DateTime::Duration->new( days => $add_duration );
91
    }
92
    }
92
    $unit ||= q{};    # default days ?
93
93
    my $days_mode = $self->{days_mode};
94
    $unit ||= 'days'; # default days ?
94
    Readonly::Scalar my $return_by_hour => 10;
95
    my $dt;
95
    my $day_dur = DateTime::Duration->new( days => 1 );
96
96
    if ( $add_duration->is_negative() ) {
97
    if ( $unit eq 'hours' ) {
97
        $day_dur = DateTime::Duration->new( days => -1 );
98
        # Fixed for legacy support. Should be set as a branch parameter
99
        Readonly::Scalar my $return_by_hour => 10;
100
101
        $dt = $self->addHours($startdate, $add_duration, $return_by_hour);
102
    } else {
103
        # days
104
        $dt = $self->addDays($startdate, $add_duration);
98
    }
105
    }
99
    if ( $days_mode eq 'Datedue' ) {
100
106
101
        my $dt = $base_date + $add_duration;
107
    return $dt;
102
        while ( $self->is_holiday($dt) ) {
108
}
103
109
104
            $dt->add_duration($day_dur);
110
sub addHours {
105
            if ( $unit eq 'hours' ) {
111
    my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_;
106
                $dt->set_hour($return_by_hour);    # Staffs specific
112
    my $base_date = $startdate->clone();
107
            }
113
114
    $base_date->add_duration($hours_duration);
115
116
    # If we are using the calendar behave for now as if Datedue
117
    # was the chosen option (current intended behaviour)
118
119
    if ( $self->{days_mode} ne 'Days' &&
120
          $self->is_holiday($base_date) ) {
121
122
        if ( $hours_duration->is_negative() ) {
123
            $base_date = $self->prev_open_day($base_date);
124
        } else {
125
            $base_date = $self->next_open_day($base_date);
108
        }
126
        }
109
        return $dt;
110
    } elsif ( $days_mode eq 'Calendar' ) {
111
        if ( $unit eq 'hours' ) {
112
            $base_date->add_duration($add_duration);
113
            while ( $self->is_holiday($base_date) ) {
114
                $base_date->add_duration($day_dur);
115
127
116
            }
128
        $base_date->set_hour($return_by_hour);
129
130
    }
131
132
    return $base_date;
133
}
117
134
135
sub addDays {
136
    my ( $self, $startdate, $days_duration ) = @_;
137
    my $base_date = $startdate->clone();
138
139
    if ( $self->{days_mode} eq 'Calendar' ) {
140
        # use the calendar to skip all days the library is closed
141
        # when adding
142
        my $days = abs $days_duration->in_units('days');
143
144
        if ( $days_duration->is_negative() ) {
145
            while ($days) {
146
                $base_date = $self->prev_open_day($base_date);
147
                --$days;
148
            }
118
        } else {
149
        } else {
119
            my $days = abs $add_duration->in_units('days');
120
            while ($days) {
150
            while ($days) {
121
                $base_date->add_duration($day_dur);
151
                $base_date = $self->next_open_day($base_date);
122
                if ( $self->is_holiday($base_date) ) {
152
                --$days;
123
                    next;
124
                } else {
125
                    --$days;
126
                }
127
            }
153
            }
128
        }
154
        }
129
        if ( $unit eq 'hours' ) {
155
130
            my $dt = $base_date->clone()->subtract( days => 1 );
156
    } else { # Days or Datedue
131
            if ( $self->is_holiday($dt) ) {
157
        # use straight days, then use calendar to push
132
                $base_date->set_hour($return_by_hour);    # Staffs specific
158
        # the date to the next open day if Datedue
159
        $base_date->add_duration($days_duration);
160
161
        if ( $self->{days_mode} eq 'Datedue' ) {
162
            # Datedue, then use the calendar to push
163
            # the date to the next open day if holiday
164
            if ( $self->is_holiday($base_date) ) {
165
                if ( $days_duration->is_negative() ) {
166
                    $base_date = $self->prev_open_day($base_date);
167
                } else {
168
                    $base_date = $self->next_open_day($base_date);
169
                }
133
            }
170
            }
134
        }
171
        }
135
        return $base_date;
136
    } else {    # Days
137
        return $base_date + $add_duration;
138
    }
172
    }
173
174
    return $base_date;
139
}
175
}
140
176
141
sub is_holiday {
177
sub is_holiday {
Lines 165-170 sub is_holiday { Link Here
165
    return 0;
201
    return 0;
166
}
202
}
167
203
204
sub next_open_day {
205
    my ( $self, $dt ) = @_;
206
    my $base_date = $dt->clone();
207
208
    $base_date->add(days => 1);
209
210
    while ($self->is_holiday($base_date)) {
211
        $base_date->add(days => 1);
212
    }
213
214
    return $base_date;
215
}
216
217
sub prev_open_day {
218
    my ( $self, $dt ) = @_;
219
    my $base_date = $dt->clone();
220
221
    $base_date->add(days => -1);
222
223
    while ($self->is_holiday($base_date)) {
224
        $base_date->add(days => -1);
225
    }
226
227
    return $base_date;
228
}
229
168
sub days_between {
230
sub days_between {
169
    my $self     = shift;
231
    my $self     = shift;
170
    my $start_dt = shift;
232
    my $start_dt = shift;
Lines 274-282 This documentation refers to Koha::Calendar version 0.0.1 Link Here
274
336
275
=head1 SYNOPSIS
337
=head1 SYNOPSIS
276
338
277
  use Koha::Calendat
339
  use Koha::Calendar
278
340
279
  my $c = Koha::Calender->new( branchcode => 'MAIN' );
341
  my $c = Koha::Calendar->new( branchcode => 'MAIN' );
280
  my $dt = DateTime->now();
342
  my $dt = DateTime->now();
281
343
282
  # are we open
344
  # are we open
Lines 312-322 Currently unit is only used to invoke Staffs return Monday at 10 am rule this Link Here
312
parameter will be removed when issuingrules properly cope with that
374
parameter will be removed when issuingrules properly cope with that
313
375
314
376
377
=head2 addHours
378
379
    my $dt = $calendar->addHours($date, $dur, $return_by_hour )
380
381
C<$date> is a DateTime object representing the starting date of the interval.
382
383
C<$offset> is a DateTime::Duration to add to it
384
385
C<$return_by_hour> is an integer value representing the opening hour for the branch
386
387
388
=head2 addDays
389
390
    my $dt = $calendar->addDays($date, $dur)
391
392
C<$date> is a DateTime object representing the starting date of the interval.
393
394
C<$offset> is a DateTime::Duration to add to it
395
396
C<$unit> is a string value 'days' or 'hours' toflag granularity of duration
397
398
Currently unit is only used to invoke Staffs return Monday at 10 am rule this
399
parameter will be removed when issuingrules properly cope with that
400
401
315
=head2 is_holiday
402
=head2 is_holiday
316
403
317
$yesno = $calendar->is_holiday($dt);
404
$yesno = $calendar->is_holiday($dt);
318
405
319
passed at DateTime object returns 1 if it is a closed day
406
passed a DateTime object returns 1 if it is a closed day
320
0 if not according to the calendar
407
0 if not according to the calendar
321
408
322
=head2 days_between
409
=head2 days_between
Lines 327-332 Passed two dates returns a DateTime::Duration object measuring the length betwee Link Here
327
ignoring closed days. Always returns a positive number irrespective of the
414
ignoring closed days. Always returns a positive number irrespective of the
328
relative order of the parameters
415
relative order of the parameters
329
416
417
=head2 next_open_day
418
419
$datetime = $calendar->next_open_day($duedate_dt)
420
421
Passed a Datetime returns another Datetime representing the next open day. It is
422
intended for use to calculate the due date when useDaysMode syspref is set to either
423
'Datedue' or 'Calendar'.
424
425
=head2 prev_open_day
426
427
$datetime = $calendar->prev_open_day($duedate_dt)
428
429
Passed a Datetime returns another Datetime representing the previous open day. It is
430
intended for use to calculate the due date when useDaysMode syspref is set to either
431
'Datedue' or 'Calendar'.
432
330
=head2 set_daysmode
433
=head2 set_daysmode
331
434
332
For testing only allows the calling script to change days mode
435
For testing only allows the calling script to change days mode
(-)a/t/Calendar.t (-2 / +50 lines)
Lines 3-9 Link Here
3
use strict;
3
use strict;
4
use warnings;
4
use warnings;
5
use DateTime;
5
use DateTime;
6
use Test::More tests => 23;
6
use DateTime::Duration;
7
use Test::More tests => 28;
7
use Koha::DateUtils;
8
use Koha::DateUtils;
8
9
9
BEGIN {
10
BEGIN {
Lines 131-133 $cal->add_holiday( dt_from_string('2012-07-07','iso') ); Link Here
131
$daycount = $cal->days_between( dt_from_string("2012-07-01",'iso'),
132
$daycount = $cal->days_between( dt_from_string("2012-07-01",'iso'),
132
    dt_from_string("2012-07-15",'iso') )->in_units('days');
133
    dt_from_string("2012-07-15",'iso') )->in_units('days');
133
cmp_ok( $daycount, '==', 12, 'multiple holidays correctly recognized' );
134
cmp_ok( $daycount, '==', 12, 'multiple holidays correctly recognized' );
134
- 
135
136
# next_open_day tests
137
$dt = dt_from_string('2012-07-07','iso');
138
cmp_ok( $dt->add(days => 1), '==', $cal->next_open_day(dt_from_string('2012-07-07','iso')), 'Next open day correctly calculated' );
139
140
# prev_open_day tests
141
# 2012-07-07 and 2012-07-06 are set to holidays previously, so previous open day should match 2012-07-05
142
$dt = dt_from_string('2012-07-05','iso');
143
cmp_ok( $dt, '==', $cal->prev_open_day(dt_from_string('2012-07-08','iso')), 'Previous open day correctly calculated' );
144
145
######################
146
# useDaysMode='Datedue' case tests
147
subtest 'useDaysMode=Datedue' => sub {
148
    my $cal = Koha::Calendar->new( TEST_MODE => 1 );
149
    my $dur = DateTime::Duration->new( days => 1 );
150
    $cal->set_daysmode( 'Datedue' );
151
    $cal->add_holiday( dt_from_string('2012-07-04','iso') );
152
    $dt = dt_from_string( '2012-07-03','iso' );
153
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-05','iso'), 'Single day add (Datedue, matches holiday, shift)' );
154
    $dur = DateTime::Duration->new( days => 2 );
155
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-05','iso'), 'Two days add, skips holiday (Datedue)' );
156
157
};
158
#######################
159
160
#######################
161
# useDaysMode='Calendar' case tests
162
subtest 'useDaysMode=Calendar' => sub {
163
    my $cal = Koha::Calendar->new( TEST_MODE => 1 );
164
    my $dur = DateTime::Duration->new( days => 1 );
165
    $cal->set_daysmode('Calendar');
166
    $cal->add_holiday( dt_from_string('2012-07-04','iso') );
167
    $dt = dt_from_string('2012-07-03','iso');
168
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-05','iso'), 'Single day add (Calendar)' );
169
};
170
#######################
171
172
#######################
173
# useDaysMode='Days' case tests
174
subtest 'useDaysMode=Days' => sub {
175
    my $cal = Koha::Calendar->new( TEST_MODE => 1 );
176
    my $dur = DateTime::Duration->new( days => 1 );
177
    $cal->set_daysmode('Days');
178
    $cal->add_holiday( dt_from_string('2012-07-04','iso') );
179
    $dt = dt_from_string('2012-07-03','iso');
180
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-04','iso'), 'Single day add (Days)' );
181
};
182
#######################

Return to bug 8800