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 164-169 sub is_holiday { Link Here
164
    return 0;
200
    return 0;
165
}
201
}
166
202
203
sub next_open_day {
204
    my ( $self, $dt ) = @_;
205
    my $base_date = $dt->clone();
206
207
    $base_date->add(days => 1);
208
209
    while ($self->is_holiday($base_date)) {
210
        $base_date->add(days => 1);
211
    }
212
213
    return $base_date;
214
}
215
216
sub prev_open_day {
217
    my ( $self, $dt ) = @_;
218
    my $base_date = $dt->clone();
219
220
    $base_date->add(days => -1);
221
222
    while ($self->is_holiday($base_date)) {
223
        $base_date->add(days => -1);
224
    }
225
226
    return $base_date;
227
}
228
167
sub days_between {
229
sub days_between {
168
    my $self     = shift;
230
    my $self     = shift;
169
    my $start_dt = shift;
231
    my $start_dt = shift;
Lines 273-281 This documentation refers to Koha::Calendar version 0.0.1 Link Here
273
335
274
=head1 SYNOPSIS
336
=head1 SYNOPSIS
275
337
276
  use Koha::Calendat
338
  use Koha::Calendar
277
339
278
  my $c = Koha::Calender->new( branchcode => 'MAIN' );
340
  my $c = Koha::Calendar->new( branchcode => 'MAIN' );
279
  my $dt = DateTime->now();
341
  my $dt = DateTime->now();
280
342
281
  # are we open
343
  # are we open
Lines 311-321 Currently unit is only used to invoke Staffs return Monday at 10 am rule this Link Here
311
parameter will be removed when issuingrules properly cope with that
373
parameter will be removed when issuingrules properly cope with that
312
374
313
375
376
=head2 addHours
377
378
    my $dt = $calendar->addHours($date, $dur, $return_by_hour )
379
380
C<$date> is a DateTime object representing the starting date of the interval.
381
382
C<$offset> is a DateTime::Duration to add to it
383
384
C<$return_by_hour> is an integer value representing the opening hour for the branch
385
386
387
=head2 addDays
388
389
    my $dt = $calendar->addDays($date, $dur)
390
391
C<$date> is a DateTime object representing the starting date of the interval.
392
393
C<$offset> is a DateTime::Duration to add to it
394
395
C<$unit> is a string value 'days' or 'hours' toflag granularity of duration
396
397
Currently unit is only used to invoke Staffs return Monday at 10 am rule this
398
parameter will be removed when issuingrules properly cope with that
399
400
314
=head2 is_holiday
401
=head2 is_holiday
315
402
316
$yesno = $calendar->is_holiday($dt);
403
$yesno = $calendar->is_holiday($dt);
317
404
318
passed at DateTime object returns 1 if it is a closed day
405
passed a DateTime object returns 1 if it is a closed day
319
0 if not according to the calendar
406
0 if not according to the calendar
320
407
321
=head2 days_between
408
=head2 days_between
Lines 326-331 Passed two dates returns a DateTime::Duration object measuring the length betwee Link Here
326
ignoring closed days. Always returns a positive number irrespective of the
413
ignoring closed days. Always returns a positive number irrespective of the
327
relative order of the parameters
414
relative order of the parameters
328
415
416
=head2 next_open_day
417
418
$datetime = $calendar->next_open_day($duedate_dt)
419
420
Passed a Datetime returns another Datetime representing the next open day. It is
421
intended for use to calculate the due date when useDaysMode syspref is set to either
422
'Datedue' or 'Calendar'.
423
424
=head2 prev_open_day
425
426
$datetime = $calendar->prev_open_day($duedate_dt)
427
428
Passed a Datetime returns another Datetime representing the previous open day. It is
429
intended for use to calculate the due date when useDaysMode syspref is set to either
430
'Datedue' or 'Calendar'.
431
329
=head2 set_daysmode
432
=head2 set_daysmode
330
433
331
For testing only allows the calling script to change days mode
434
For testing only allows the calling script to change days mode
(-)a/t/Calendar.t (-2 / +51 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 => 21;
6
use DateTime::Duration;
7
use Test::More tests => 26;
7
use Koha::DateUtils;
8
use Koha::DateUtils;
8
9
9
BEGIN {
10
BEGIN {
Lines 127-129 $cal->add_holiday( dt_from_string('2012-07-07','iso') ); Link Here
127
$daycount = $cal->days_between( dt_from_string("2012-07-01",'iso'),
128
$daycount = $cal->days_between( dt_from_string("2012-07-01",'iso'),
128
    dt_from_string("2012-07-15",'iso') )->in_units('days');
129
    dt_from_string("2012-07-15",'iso') )->in_units('days');
129
cmp_ok( $daycount, '==', 12, 'multiple holidays correctly recognized' );
130
cmp_ok( $daycount, '==', 12, 'multiple holidays correctly recognized' );
130
- 
131
132
# next_open_day tests
133
$dt = dt_from_string('2012-07-07','iso');
134
cmp_ok( $dt->add(days => 1), '==', $cal->next_open_day(dt_from_string('2012-07-07','iso')), 'Next open day correctly calculated' );
135
136
# prev_open_day tests
137
# 2012-07-07 and 2012-07-06 are set to holidays previously, so previous open day should match 2012-07-05
138
$dt = dt_from_string('2012-07-05','iso');
139
cmp_ok( $dt, '==', $cal->prev_open_day(dt_from_string('2012-07-08','iso')), 'Previous open day correctly calculated' );
140
141
######################
142
# useDaysMode='Datedue' case tests
143
subtest 'useDaysMode=Datedue' => sub { 
144
    my $cal = Koha::Calendar->new( TEST_MODE => 1 );
145
    my $dur = DateTime::Duration->new( days => 1 );
146
    $cal->set_daysmode( 'Datedue' );
147
    $cal->add_holiday( dt_from_string('2012-07-04','iso') );
148
    $dt = dt_from_string( '2012-07-03','iso' );
149
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-05','iso'), 'Single day add (Datedue, matches holiday, shift)' );
150
    $dur = DateTime::Duration->new( days => 2 );
151
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-05','iso'), 'Two days add, skips holiday (Datedue)' );
152
153
};
154
#######################
155
156
#######################
157
# useDaysMode='Calendar' case tests
158
subtest 'useDaysMode=Calendar' => sub {
159
    my $cal = Koha::Calendar->new( TEST_MODE => 1 );
160
    my $dur = DateTime::Duration->new( days => 1 );
161
    $cal->set_daysmode('Calendar');
162
    $cal->add_holiday( dt_from_string('2012-07-04','iso') );
163
    $dt = dt_from_string('2012-07-03','iso');
164
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-05','iso'), 'Single day add (Calendar)' );
165
};
166
#######################
167
168
#######################
169
# useDaysMode='Days' case tests
170
subtest 'useDaysMode=Days' => sub {
171
    my $cal = Koha::Calendar->new( TEST_MODE => 1 );
172
    my $dur = DateTime::Duration->new( days => 1 );
173
    $cal->set_daysmode('Days');
174
    $cal->add_holiday( dt_from_string('2012-07-04','iso') );
175
    $dt = dt_from_string('2012-07-03','iso');
176
    is($cal->addDate( $dt, $dur, 'days' ), dt_from_string('2012-07-04','iso'), 'Single day add (Days)' );
177
};
178
#######################
179

Return to bug 8800