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

(-)a/Koha/Calendar.pm (-535 lines)
Lines 1-535 Link Here
1
package Koha::Calendar;
2
use strict;
3
use warnings;
4
use 5.010;
5
6
use DateTime;
7
use DateTime::Set;
8
use DateTime::Duration;
9
use C4::Context;
10
use Koha::Caches;
11
use Carp;
12
13
sub new {
14
    my ( $classname, %options ) = @_;
15
    my $self = {};
16
    bless $self, $classname;
17
    for my $o_name ( keys %options ) {
18
        my $o = lc $o_name;
19
        $self->{$o} = $options{$o_name};
20
    }
21
    if ( !defined $self->{branchcode} ) {
22
        croak 'No branchcode argument passed to Koha::Calendar->new';
23
    }
24
    $self->_init();
25
    return $self;
26
}
27
28
sub _init {
29
    my $self       = shift;
30
    my $branch     = $self->{branchcode};
31
    my $dbh        = C4::Context->dbh();
32
    my $weekly_closed_days_sth = $dbh->prepare(
33
'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL'
34
    );
35
    $weekly_closed_days_sth->execute( $branch );
36
    $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ];
37
    while ( my $tuple = $weekly_closed_days_sth->fetchrow_hashref ) {
38
        $self->{weekly_closed_days}->[ $tuple->{weekday} ] = 1;
39
    }
40
    my $day_month_closed_days_sth = $dbh->prepare(
41
'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL'
42
    );
43
    $day_month_closed_days_sth->execute( $branch );
44
    $self->{day_month_closed_days} = {};
45
    while ( my $tuple = $day_month_closed_days_sth->fetchrow_hashref ) {
46
        $self->{day_month_closed_days}->{ $tuple->{month} }->{ $tuple->{day} } =
47
          1;
48
    }
49
50
    $self->{days_mode}       ||= C4::Context->preference('useDaysMode');
51
    $self->{test}            = 0;
52
    return;
53
}
54
55
sub exception_holidays {
56
    my ( $self ) = @_;
57
58
    my $cache  = Koha::Caches->get_instance();
59
    my $cached = $cache->get_from_cache('exception_holidays');
60
    return $cached if $cached;
61
62
    my $dbh = C4::Context->dbh;
63
    my $branch = $self->{branchcode};
64
    my $exception_holidays_sth = $dbh->prepare(
65
'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1'
66
    );
67
    $exception_holidays_sth->execute( $branch );
68
    my $dates = [];
69
    while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) {
70
        push @{$dates},
71
          DateTime->new(
72
            day       => $day,
73
            month     => $month,
74
            year      => $year,
75
            time_zone => "floating",
76
          )->truncate( to => 'day' );
77
    }
78
    $self->{exception_holidays} =
79
      DateTime::Set->from_datetimes( dates => $dates );
80
    $cache->set_in_cache( 'exception_holidays', $self->{exception_holidays} );
81
    return $self->{exception_holidays};
82
}
83
84
sub single_holidays {
85
    my ( $self, $date ) = @_;
86
    my $branchcode = $self->{branchcode};
87
    my $cache           = Koha::Caches->get_instance();
88
    my $single_holidays = $cache->get_from_cache('single_holidays');
89
90
    # $single_holidays looks like:
91
    # {
92
    #   CPL =>  [
93
    #        [0] 20131122,
94
    #         ...
95
    #    ],
96
    #   ...
97
    # }
98
99
    unless ($single_holidays) {
100
        my $dbh = C4::Context->dbh;
101
        $single_holidays = {};
102
103
        # push holidays for each branch
104
        my $branches_sth =
105
          $dbh->prepare('SELECT distinct(branchcode) FROM special_holidays');
106
        $branches_sth->execute();
107
        while ( my $br = $branches_sth->fetchrow ) {
108
            my $single_holidays_sth = $dbh->prepare(
109
'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0'
110
            );
111
            $single_holidays_sth->execute($br);
112
113
            my @ymd_arr;
114
            while ( my ( $day, $month, $year ) =
115
                $single_holidays_sth->fetchrow )
116
            {
117
                my $dt = DateTime->new(
118
                    day       => $day,
119
                    month     => $month,
120
                    year      => $year,
121
                    time_zone => 'floating',
122
                )->truncate( to => 'day' );
123
                push @ymd_arr, $dt->ymd('');
124
            }
125
            $single_holidays->{$br} = \@ymd_arr;
126
        }    # br
127
        $cache->set_in_cache( 'single_holidays', $single_holidays,
128
            { expiry => 76800 } )    #24 hrs ;
129
    }
130
    my $holidays  = ( $single_holidays->{$branchcode} );
131
    for my $hols  (@$holidays ) {
132
            return 1 if ( $date == $hols )   #match ymds;
133
    }
134
    return 0;
135
}
136
137
sub addDate {
138
    my ( $self, $startdate, $add_duration, $unit ) = @_;
139
140
    # Default to days duration (legacy support I guess)
141
    if ( ref $add_duration ne 'DateTime::Duration' ) {
142
        $add_duration = DateTime::Duration->new( days => $add_duration );
143
    }
144
145
    $unit ||= 'days'; # default days ?
146
    my $dt;
147
148
    if ( $unit eq 'hours' ) {
149
        # Fixed for legacy support. Should be set as a branch parameter
150
        my $return_by_hour = 10;
151
152
        $dt = $self->addHours($startdate, $add_duration, $return_by_hour);
153
    } else {
154
        # days
155
        $dt = $self->addDays($startdate, $add_duration);
156
    }
157
158
    return $dt;
159
}
160
161
sub addHours {
162
    my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_;
163
    my $base_date = $startdate->clone();
164
165
    $base_date->add_duration($hours_duration);
166
167
    # If we are using the calendar behave for now as if Datedue
168
    # was the chosen option (current intended behaviour)
169
170
    if ( $self->{days_mode} ne 'Days' &&
171
          $self->is_holiday($base_date) ) {
172
173
        if ( $hours_duration->is_negative() ) {
174
            $base_date = $self->prev_open_day($base_date);
175
        } else {
176
            $base_date = $self->next_open_day($base_date);
177
        }
178
179
        $base_date->set_hour($return_by_hour);
180
181
    }
182
183
    return $base_date;
184
}
185
186
sub addDays {
187
    my ( $self, $startdate, $days_duration ) = @_;
188
    my $base_date = $startdate->clone();
189
190
    $self->{days_mode} ||= q{};
191
192
    if ( $self->{days_mode} eq 'Calendar' ) {
193
        # use the calendar to skip all days the library is closed
194
        # when adding
195
        my $days = abs $days_duration->in_units('days');
196
197
        if ( $days_duration->is_negative() ) {
198
            while ($days) {
199
                $base_date = $self->prev_open_day($base_date);
200
                --$days;
201
            }
202
        } else {
203
            while ($days) {
204
                $base_date = $self->next_open_day($base_date);
205
                --$days;
206
            }
207
        }
208
209
    } else { # Days or Datedue
210
        # use straight days, then use calendar to push
211
        # the date to the next open day if Datedue
212
        $base_date->add_duration($days_duration);
213
214
        if ( $self->{days_mode} eq 'Datedue' ) {
215
            # Datedue, then use the calendar to push
216
            # the date to the next open day if holiday
217
            if ( $self->is_holiday($base_date) ) {
218
219
                if ( $days_duration->is_negative() ) {
220
                    $base_date = $self->prev_open_day($base_date);
221
                } else {
222
                    $base_date = $self->next_open_day($base_date);
223
                }
224
            }
225
        }
226
    }
227
228
    return $base_date;
229
}
230
231
sub is_holiday {
232
    my ( $self, $dt ) = @_;
233
234
    my $localdt = $dt->clone();
235
    my $day   = $localdt->day;
236
    my $month = $localdt->month;
237
238
    #Change timezone to "floating" before doing any calculations or comparisons
239
    $localdt->set_time_zone("floating");
240
    $localdt->truncate( to => 'day' );
241
242
243
    if ( $self->exception_holidays->contains($localdt) ) {
244
        # exceptions are not holidays
245
        return 0;
246
    }
247
248
    my $dow = $localdt->day_of_week;
249
    # Representation fix
250
    # DateTime object dow (1-7) where Monday is 1
251
    # Arrays are 0-based where 0 = Sunday, not 7.
252
    if ( $dow == 7 ) {
253
        $dow = 0;
254
    }
255
256
    if ( $self->{weekly_closed_days}->[$dow] == 1 ) {
257
        return 1;
258
    }
259
260
    if ( exists $self->{day_month_closed_days}->{$month}->{$day} ) {
261
        return 1;
262
    }
263
264
    my $ymd   = $localdt->ymd('')  ;
265
    if ($self->single_holidays(  $ymd  ) == 1 ) {
266
        return 1;
267
    }
268
269
    # damn have to go to work after all
270
    return 0;
271
}
272
273
sub next_open_day {
274
    my ( $self, $dt ) = @_;
275
    my $base_date = $dt->clone();
276
277
    $base_date->add(days => 1);
278
279
    while ($self->is_holiday($base_date)) {
280
        $base_date->add(days => 1);
281
    }
282
283
    return $base_date;
284
}
285
286
sub prev_open_day {
287
    my ( $self, $dt ) = @_;
288
    my $base_date = $dt->clone();
289
290
    $base_date->add(days => -1);
291
292
    while ($self->is_holiday($base_date)) {
293
        $base_date->add(days => -1);
294
    }
295
296
    return $base_date;
297
}
298
299
sub days_forward {
300
    my $self     = shift;
301
    my $start_dt = shift;
302
    my $num_days = shift;
303
304
    return $start_dt unless $num_days > 0;
305
306
    my $base_dt = $start_dt->clone();
307
308
    while ($num_days--) {
309
        $base_dt = $self->next_open_day($base_dt);
310
    }
311
312
    return $base_dt;
313
}
314
315
sub days_between {
316
    my $self     = shift;
317
    my $start_dt = shift;
318
    my $end_dt   = shift;
319
320
    # Change time zone for date math and swap if needed
321
    $start_dt = $start_dt->clone->set_time_zone('floating');
322
    $end_dt = $end_dt->clone->set_time_zone('floating');
323
    if( $start_dt->compare($end_dt) > 0 ) {
324
        ( $start_dt, $end_dt ) = ( $end_dt, $start_dt );
325
    }
326
327
    # start and end should not be closed days
328
    my $days = $start_dt->delta_days($end_dt)->delta_days;
329
    while( $start_dt->compare($end_dt) < 1 ) {
330
        $days-- if $self->is_holiday($start_dt);
331
        $start_dt->add( days => 1 );
332
    }
333
    return DateTime::Duration->new( days => $days );
334
}
335
336
sub hours_between {
337
    my ($self, $start_date, $end_date) = @_;
338
    my $start_dt = $start_date->clone()->set_time_zone('floating');
339
    my $end_dt = $end_date->clone()->set_time_zone('floating');
340
    my $duration = $end_dt->delta_ms($start_dt);
341
    $start_dt->truncate( to => 'day' );
342
    $end_dt->truncate( to => 'day' );
343
    # NB this is a kludge in that it assumes all days are 24 hours
344
    # However for hourly loans the logic should be expanded to
345
    # take into account open/close times then it would be a duration
346
    # of library open hours
347
    my $skipped_days = 0;
348
    for (my $dt = $start_dt->clone();
349
        $dt <= $end_dt;
350
        $dt->add(days => 1)
351
    ) {
352
        if ($self->is_holiday($dt)) {
353
            ++$skipped_days;
354
        }
355
    }
356
    if ($skipped_days) {
357
        $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days));
358
    }
359
360
    return $duration;
361
362
}
363
364
sub set_daysmode {
365
    my ( $self, $mode ) = @_;
366
367
    # if not testing this is a no op
368
    if ( $self->{test} ) {
369
        $self->{days_mode} = $mode;
370
    }
371
372
    return;
373
}
374
375
sub clear_weekly_closed_days {
376
    my $self = shift;
377
    $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ];    # Sunday only
378
    return;
379
}
380
381
1;
382
__END__
383
384
=head1 NAME
385
386
Koha::Calendar - Object containing a branches calendar
387
388
=head1 SYNOPSIS
389
390
  use Koha::Calendar
391
392
  my $c = Koha::Calendar->new( branchcode => 'MAIN' );
393
  my $dt = DateTime->now();
394
395
  # are we open
396
  $open = $c->is_holiday($dt);
397
  # when will item be due if loan period = $dur (a DateTime::Duration object)
398
  $duedate = $c->addDate($dt,$dur,'days');
399
400
401
=head1 DESCRIPTION
402
403
  Implements those features of C4::Calendar needed for Staffs Rolling Loans
404
405
=head1 METHODS
406
407
=head2 new : Create a calendar object
408
409
my $calendar = Koha::Calendar->new( branchcode => 'MAIN' );
410
411
The option branchcode is required
412
413
414
=head2 addDate
415
416
    my $dt = $calendar->addDate($date, $dur, $unit)
417
418
C<$date> is a DateTime object representing the starting date of the interval.
419
420
C<$offset> is a DateTime::Duration to add to it
421
422
C<$unit> is a string value 'days' or 'hours' toflag granularity of duration
423
424
Currently unit is only used to invoke Staffs return Monday at 10 am rule this
425
parameter will be removed when issuingrules properly cope with that
426
427
428
=head2 addHours
429
430
    my $dt = $calendar->addHours($date, $dur, $return_by_hour )
431
432
C<$date> is a DateTime object representing the starting date of the interval.
433
434
C<$offset> is a DateTime::Duration to add to it
435
436
C<$return_by_hour> is an integer value representing the opening hour for the branch
437
438
439
=head2 addDays
440
441
    my $dt = $calendar->addDays($date, $dur)
442
443
C<$date> is a DateTime object representing the starting date of the interval.
444
445
C<$offset> is a DateTime::Duration to add to it
446
447
C<$unit> is a string value 'days' or 'hours' toflag granularity of duration
448
449
Currently unit is only used to invoke Staffs return Monday at 10 am rule this
450
parameter will be removed when issuingrules properly cope with that
451
452
453
=head2 single_holidays
454
455
my $rc = $self->single_holidays(  $ymd  );
456
457
Passed a $date in Ymd (yyyymmdd) format -  returns 1 if date is a single_holiday, or 0 if not.
458
459
460
=head2 is_holiday
461
462
$yesno = $calendar->is_holiday($dt);
463
464
passed a DateTime object returns 1 if it is a closed day
465
0 if not according to the calendar
466
467
=head2 days_between
468
469
$duration = $calendar->days_between($start_dt, $end_dt);
470
471
Passed two dates returns a DateTime::Duration object measuring the length between them
472
ignoring closed days. Always returns a positive number irrespective of the
473
relative order of the parameters
474
475
=head2 next_open_day
476
477
$datetime = $calendar->next_open_day($duedate_dt)
478
479
Passed a Datetime returns another Datetime representing the next open day. It is
480
intended for use to calculate the due date when useDaysMode syspref is set to either
481
'Datedue' or 'Calendar'.
482
483
=head2 prev_open_day
484
485
$datetime = $calendar->prev_open_day($duedate_dt)
486
487
Passed a Datetime returns another Datetime representing the previous open day. It is
488
intended for use to calculate the due date when useDaysMode syspref is set to either
489
'Datedue' or 'Calendar'.
490
491
=head2 set_daysmode
492
493
For testing only allows the calling script to change days mode
494
495
=head2 clear_weekly_closed_days
496
497
In test mode changes the testing set of closed days to a new set with
498
no closed days. TODO passing an array of closed days to this would
499
allow testing of more configurations
500
501
=head2 add_holiday
502
503
Passed a datetime object this will add it to the calendar's list of
504
closed days. This is for testing so that we can alter the Calenfar object's
505
list of specified dates
506
507
=head1 DIAGNOSTICS
508
509
Will croak if not passed a branchcode in new
510
511
=head1 BUGS AND LIMITATIONS
512
513
This only contains a limited subset of the functionality in C4::Calendar
514
Only enough to support Staffs Rolling loans
515
516
=head1 AUTHOR
517
518
Colin Campbell colin.campbell@ptfs-europe.com
519
520
=head1 LICENSE AND COPYRIGHT
521
522
Copyright (c) 2011 PTFS-Europe Ltd All rights reserved
523
524
This program is free software: you can redistribute it and/or modify
525
it under the terms of the GNU General Public License as published by
526
the Free Software Foundation, either version 2 of the License, or
527
(at your option) any later version.
528
529
This program is distributed in the hope that it will be useful,
530
but WITHOUT ANY WARRANTY; without even the implied warranty of
531
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
532
GNU General Public License for more details.
533
534
You should have received a copy of the GNU General Public License
535
along with this program.  If not, see <http://www.gnu.org/licenses/>.
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc (-1 / +1 lines)
Lines 104-110 Link Here
104
<h5>Additional tools</h5>
104
<h5>Additional tools</h5>
105
<ul>
105
<ul>
106
    [% IF ( CAN_user_tools_edit_calendar ) %]
106
    [% IF ( CAN_user_tools_edit_calendar ) %]
107
	<li><a href="/cgi-bin/koha/tools/holidays.pl">Calendar</a></li>
107
    <li><a href="/cgi-bin/koha/tools/discrete_calendar.pl">Calendar</a></li>
108
    [% END %]
108
    [% END %]
109
    [% IF ( CAN_user_tools_manage_csv_profiles ) %]
109
    [% IF ( CAN_user_tools_manage_csv_profiles ) %]
110
	<li><a href="/cgi-bin/koha/tools/csv-profiles.pl">CSV profiles</a></li>
110
	<li><a href="/cgi-bin/koha/tools/csv-profiles.pl">CSV profiles</a></li>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt (-6 / +1 lines)
Lines 85-96 Link Here
85
[% END %]
85
[% END %]
86
<dl>
86
<dl>
87
    [% IF ( CAN_user_tools_edit_calendar ) %]
87
    [% IF ( CAN_user_tools_edit_calendar ) %]
88
    <dt><a href="/cgi-bin/koha/tools/holidays.pl">Calendar</a></dt>
88
    <dt><a href="/cgi-bin/koha/tools/discrete_calendar.pl">Calendar</a></dt>
89
    <dd>Define days when the library is closed</dd>
90
    [% END %]
91
92
    [% IF ( CAN_user_tools_edit_calendar ) %]
93
    <dt><a href="/cgi-bin/koha/tools/discrete_calendar.pl">Discrete Calendar</a></dt>
94
    <dd>Define days when the library is closed</dd>
89
    <dd>Define days when the library is closed</dd>
95
    [% END %]
90
    [% END %]
96
91
(-)a/t/Calendar.t (-340 lines)
Lines 1-340 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More;
21
use Test::MockModule;
22
23
use DateTime;
24
use DateTime::Duration;
25
use Koha::Caches;
26
use Koha::DateUtils;
27
28
use t::lib::Mocks;
29
30
use Module::Load::Conditional qw/check_install/;
31
32
BEGIN {
33
    if ( check_install( module => 'Test::DBIx::Class' ) ) {
34
        plan tests => 39;
35
    } else {
36
        plan skip_all => "Need Test::DBIx::Class"
37
    }
38
}
39
40
use_ok('Koha::Calendar');
41
42
use Test::DBIx::Class;
43
44
my $db = Test::MockModule->new('Koha::Database');
45
$db->mock(
46
    _new_schema => sub { return Schema(); }
47
);
48
49
# We need to mock the C4::Context->preference method for
50
# simplicity and re-usability of the session definition. Any
51
# syspref fits for syspref-agnostic tests.
52
my $module_context = new Test::MockModule('C4::Context');
53
$module_context->mock(
54
    'preference',
55
    sub {
56
        return 'Calendar';
57
    }
58
);
59
60
fixtures_ok [
61
    # weekly holidays
62
    RepeatableHoliday => [
63
        [ qw( branchcode day month weekday title description) ],
64
        [ 'MPL', undef, undef, 0, '', '' ], # sundays
65
        [ 'MPL', undef, undef, 6, '', '' ],# saturdays
66
        [ 'MPL', 1, 1, undef, '', ''], # new year's day
67
        [ 'MPL', 25, 12, undef, '', ''], # chrismas
68
    ],
69
    # exception holidays
70
    SpecialHoliday => [
71
        [qw( branchcode day month year title description isexception )],
72
        [ 'MPL', 11, 11, 2012, '', '', 1 ],    # sunday exception
73
        [ 'MPL', 1,  6,  2011, '', '', 0 ],
74
        [ 'MPL', 4,  7,  2012, '', '', 0 ],
75
        [ 'CPL', 6,  8,  2012, '', '', 0 ],
76
      ],
77
], "add fixtures";
78
79
my $cache = Koha::Caches->get_instance();
80
$cache->clear_from_cache( 'single_holidays' ) ;
81
$cache->clear_from_cache( 'exception_holidays' ) ;
82
83
# 'MPL' branch is arbitrary, is not used at all but is needed for initialization
84
my $cal = Koha::Calendar->new( branchcode => 'MPL' );
85
86
isa_ok( $cal, 'Koha::Calendar', 'Calendar class returned' );
87
88
my $saturday = DateTime->new(
89
    year      => 2012,
90
    month     => 11,
91
    day       => 24,
92
);
93
94
my $sunday = DateTime->new(
95
    year      => 2012,
96
    month     => 11,
97
    day       => 25,
98
);
99
100
my $monday = DateTime->new(
101
    year      => 2012,
102
    month     => 11,
103
    day       => 26,
104
);
105
106
my $new_year = DateTime->new(
107
    year        => 2013,
108
    month       => 1,
109
    day         => 1,
110
);
111
112
my $single_holiday = DateTime->new(
113
    year      => 2011,
114
    month     => 6,
115
    day       => 1,
116
);    # should be a holiday
117
118
my $notspecial = DateTime->new(
119
    year      => 2011,
120
    month     => 6,
121
    day       => 2
122
);    # should NOT be a holiday
123
124
my $sunday_exception = DateTime->new(
125
    year      => 2012,
126
    month     => 11,
127
    day       => 11
128
);
129
130
my $day_after_christmas = DateTime->new(
131
    year    => 2012,
132
    month   => 12,
133
    day     => 26
134
);  # for testing negative addDate
135
136
my $holiday_for_another_branch = DateTime->new(
137
    year => 2012,
138
    month => 8,
139
    day => 6, # This is a monday
140
);
141
142
{   # Syspref-agnostic tests
143
    is ( $saturday->day_of_week, 6, '\'$saturday\' is actually a saturday (6th day of week)');
144
    is ( $sunday->day_of_week, 7, '\'$sunday\' is actually a sunday (7th day of week)');
145
    is ( $monday->day_of_week, 1, '\'$monday\' is actually a monday (1st day of week)');
146
    is ( $cal->is_holiday($saturday), 1, 'Saturday is a closed day' );
147
    is ( $cal->is_holiday($sunday), 1, 'Sunday is a closed day' );
148
    is ( $cal->is_holiday($monday), 0, 'Monday is not a closed day' );
149
    is ( $cal->is_holiday($new_year), 1, 'Month/Day closed day test (New year\'s day)' );
150
    is ( $cal->is_holiday($single_holiday), 1, 'Single holiday closed day test' );
151
    is ( $cal->is_holiday($notspecial), 0, 'Fixed single date that is not a holiday test' );
152
    is ( $cal->is_holiday($sunday_exception), 0, 'Exception holiday is not a closed day test' );
153
    is ( $cal->is_holiday($holiday_for_another_branch), 0, 'Holiday defined for another branch should not be defined as an holiday' );
154
}
155
156
{   # Bugzilla #8966 - is_holiday truncates referenced date
157
    my $later_dt = DateTime->new(    # Monday
158
        year      => 2012,
159
        month     => 9,
160
        day       => 17,
161
        hour      => 17,
162
        minute    => 30,
163
        time_zone => 'Europe/London',
164
    );
165
166
167
    is( $cal->is_holiday($later_dt), 0, 'bz-8966 (1/2) Apply is_holiday for the next test' );
168
    cmp_ok( $later_dt, 'eq', '2012-09-17T17:30:00', 'bz-8966 (2/2) Date should be the same after is_holiday' );
169
}
170
171
{   # Bugzilla #8800 - is_holiday should use truncated date for 'contains' call
172
    my $single_holiday_time = DateTime->new(
173
        year  => 2011,
174
        month => 6,
175
        day   => 1,
176
        hour  => 11,
177
        minute  => 2
178
    );
179
180
    is( $cal->is_holiday($single_holiday_time),
181
        $cal->is_holiday($single_holiday) ,
182
        'bz-8800 is_holiday should truncate the date for holiday validation' );
183
}
184
185
    my $one_day_dur = DateTime::Duration->new( days => 1 );
186
    my $two_day_dur = DateTime::Duration->new( days => 2 );
187
    my $seven_day_dur = DateTime::Duration->new( days => 7 );
188
189
    my $dt = dt_from_string( '2012-07-03','iso' ); #tuesday
190
191
    my $test_dt = DateTime->new(    # Monday
192
        year      => 2012,
193
        month     => 7,
194
        day       => 23,
195
        hour      => 11,
196
        minute    => 53,
197
    );
198
199
    my $later_dt = DateTime->new(    # Monday
200
        year      => 2012,
201
        month     => 9,
202
        day       => 17,
203
        hour      => 17,
204
        minute    => 30,
205
        time_zone => 'Europe/London',
206
    );
207
208
{    ## 'Datedue' tests
209
210
    $module_context->unmock('preference');
211
    $module_context->mock(
212
        'preference',
213
        sub {
214
            return 'Datedue';
215
        }
216
    );
217
218
    $cal = Koha::Calendar->new( branchcode => 'MPL' );
219
220
    is($cal->addDate( $dt, $one_day_dur, 'days' ), # tuesday
221
        dt_from_string('2012-07-05','iso'),
222
        'Single day add (Datedue, matches holiday, shift)' );
223
224
    is($cal->addDate( $dt, $two_day_dur, 'days' ),
225
        dt_from_string('2012-07-05','iso'),
226
        'Two days add, skips holiday (Datedue)' );
227
228
    cmp_ok($cal->addDate( $test_dt, $seven_day_dur, 'days' ), 'eq',
229
        '2012-07-30T11:53:00',
230
        'Add 7 days (Datedue)' );
231
232
    is( $cal->addDate( $saturday, $one_day_dur, 'days' )->day_of_week, 1,
233
        'addDate skips closed Sunday (Datedue)' );
234
235
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-24',
236
        'Negative call to addDate (Datedue)' );
237
238
    ## Note that the days_between API says closed days are not considered.
239
    ## This tests are here as an API test.
240
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
241
                '==', 40, 'days_between calculates correctly (Days)' );
242
243
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
244
                '==', 40, 'Test parameter order not relevant (Days)' );
245
}
246
247
{   ## 'Calendar' tests'
248
249
    $module_context->unmock('preference');
250
    $module_context->mock(
251
        'preference',
252
        sub {
253
            return 'Calendar';
254
        }
255
    );
256
257
    $cal = Koha::Calendar->new( branchcode => 'MPL' );
258
259
    $dt = dt_from_string('2012-07-03','iso');
260
261
    is($cal->addDate( $dt, $one_day_dur, 'days' ),
262
        dt_from_string('2012-07-05','iso'),
263
        'Single day add (Calendar)' );
264
265
    cmp_ok($cal->addDate( $test_dt, $seven_day_dur, 'days' ), 'eq',
266
       '2012-08-01T11:53:00',
267
       'Add 7 days (Calendar)' );
268
269
    is( $cal->addDate( $saturday, $one_day_dur, 'days' )->day_of_week, 1,
270
            'addDate skips closed Sunday (Calendar)' );
271
272
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-24',
273
            'Negative call to addDate (Calendar)' );
274
275
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
276
                '==', 40, 'days_between calculates correctly (Calendar)' );
277
278
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
279
                '==', 40, 'Test parameter order not relevant (Calendar)' );
280
}
281
282
283
{   ## 'Days' tests
284
    $module_context->unmock('preference');
285
    $module_context->mock(
286
        'preference',
287
        sub {
288
            return 'Days';
289
        }
290
    );
291
292
    $cal = Koha::Calendar->new( branchcode => 'MPL' );
293
294
    $dt = dt_from_string('2012-07-03','iso');
295
296
    is($cal->addDate( $dt, $one_day_dur, 'days' ),
297
        dt_from_string('2012-07-04','iso'),
298
        'Single day add (Days)' );
299
300
    cmp_ok($cal->addDate( $test_dt, $seven_day_dur, 'days' ),'eq',
301
        '2012-07-30T11:53:00',
302
        'Add 7 days (Days)' );
303
304
    is( $cal->addDate( $saturday, $one_day_dur, 'days' )->day_of_week, 7,
305
        'addDate doesn\'t skip closed Sunday (Days)' );
306
307
    is( $cal->addDate($day_after_christmas, -1, 'days')->ymd(), '2012-12-25',
308
        'Negative call to addDate (Days)' );
309
310
    ## Note that the days_between API says closed days are not considered.
311
    ## This tests are here as an API test.
312
    cmp_ok( $cal->days_between( $test_dt, $later_dt )->in_units('days'),
313
                '==', 40, 'days_between calculates correctly (Days)' );
314
315
    cmp_ok( $cal->days_between( $later_dt, $test_dt )->in_units('days'),
316
                '==', 40, 'Test parameter order not relevant (Days)' );
317
318
}
319
320
{
321
    $cal = Koha::Calendar->new( branchcode => 'CPL' );
322
    is ( $cal->is_holiday($single_holiday), 0, 'Single holiday for MPL, not CPL' );
323
    is ( $cal->is_holiday($holiday_for_another_branch), 1, 'Holiday defined for CPL should be defined as an holiday' );
324
}
325
326
subtest 'days_mode parameter' => sub {
327
    plan tests => 2;
328
329
    t::lib::Mocks::mock_preference('useDaysMode', 'Days');
330
    my $cal = Koha::Calendar->new( branchcode => 'CPL' );
331
    is( $cal->{days_mode}, 'Days', q|If not set, days_mode defaults to syspref's value|);
332
333
    $cal = Koha::Calendar->new( branchcode => 'CPL', days_mode => 'Calendar' );
334
    is( $cal->{days_mode}, 'Calendar', q|If set, days_mode is correctly set|);
335
};
336
337
END {
338
    $cache->clear_from_cache( 'single_holidays' ) ;
339
    $cache->clear_from_cache( 'exception_holidays' ) ;
340
};
(-)a/t/db_dependent/Calendar.t (-85 lines)
Lines 1-85 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 6;
21
use t::lib::TestBuilder;
22
23
use DateTime;
24
use Koha::Caches;
25
use Koha::DateUtils;
26
27
use_ok('Koha::Calendar');
28
29
my $schema  = Koha::Database->new->schema;
30
$schema->storage->txn_begin;
31
32
my $today = dt_from_string();
33
my $holiday_dt = $today->clone;
34
$holiday_dt->add(days => 15);
35
36
Koha::Caches->get_instance()->flush_all();
37
38
my $builder = t::lib::TestBuilder->new();
39
my $holiday = $builder->build({
40
    source => 'SpecialHoliday',
41
    value => {
42
        branchcode => 'LIB1',
43
        day => $holiday_dt->day,
44
        month => $holiday_dt->month,
45
        year => $holiday_dt->year,
46
        title => 'My holiday',
47
        isexception => 0
48
    },
49
});
50
51
my $calendar = Koha::Calendar->new( branchcode => 'LIB1');
52
my $forwarded_dt = $calendar->days_forward($today, 10);
53
54
my $expected = $today->clone;
55
$expected->add(days => 10);
56
is($forwarded_dt->ymd, $expected->ymd, 'With no holiday on the perioddays_forward should add 10 days');
57
58
$forwarded_dt = $calendar->days_forward($today, 20);
59
60
$expected->add(days => 11);
61
is($forwarded_dt->ymd, $expected->ymd, 'With holiday on the perioddays_forward should add 20 days + 1 day for holiday');
62
63
$forwarded_dt = $calendar->days_forward($today, 0);
64
is($forwarded_dt->ymd, $today->ymd, '0 day should return start dt');
65
66
$forwarded_dt = $calendar->days_forward($today, -2);
67
is($forwarded_dt->ymd, $today->ymd, 'negative day should return start dt');
68
69
subtest 'crossing_DST' => sub {
70
71
    plan tests => 3;
72
73
    my $tz = DateTime::TimeZone->new( name => 'America/New_York' );
74
    my $start_date = dt_from_string( "2016-03-09 02:29:00",undef,$tz );
75
    my $end_date = dt_from_string( "2017-01-01 00:00:00", undef, $tz );
76
    my $days_between = $calendar->days_between($start_date,$end_date);
77
    is( $days_between->delta_days, 298, "Days calculated correctly" );
78
    $days_between = $calendar->days_between($end_date,$start_date);
79
    is( $days_between->delta_days, 298, "Swapping returns the same" );
80
    my $hours_between = $calendar->hours_between($start_date,$end_date);
81
    is( $hours_between->delta_minutes, 298 * 24 * 60 - 149, "Hours (in minutes) calculated correctly" );
82
83
};
84
85
$schema->storage->txn_rollback();
(-)a/t/db_dependent/Holidays.t (-205 lines)
Lines 1-205 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Test::More tests => 16;
21
22
use DateTime;
23
use DateTime::TimeZone;
24
25
use t::lib::TestBuilder;
26
use C4::Context;
27
use Koha::Database;
28
use Koha::DateUtils;
29
30
31
BEGIN {
32
    use_ok('Koha::Calendar');
33
    use_ok('C4::Calendar');
34
}
35
36
my $schema = Koha::Database->new->schema;
37
my $dbh = C4::Context->dbh;
38
my $builder = t::lib::TestBuilder->new;
39
40
subtest 'exception_holidays() tests' => sub {
41
42
    plan tests => 1;
43
44
    $schema->storage->txn_begin;
45
46
    $dbh->do("DELETE FROM special_holidays");
47
    # Clear cache
48
    Koha::Caches->get_instance->flush_all;
49
50
    # Artificially set timezone
51
    my $timezone = 'America/Santiago';
52
    $ENV{TZ} = $timezone;
53
    use POSIX qw(tzset);
54
    tzset;
55
56
    my $branch = $builder->build( { source => 'Branch' } )->{branchcode};
57
    my $calendar = Koha::Calendar->new( branchcode => $branch );
58
59
    C4::Calendar->new( branchcode => $branch )->insert_exception_holiday(
60
        day         => 6,
61
        month       => 9,
62
        year        => 2015,
63
        title       => 'Invalid date',
64
        description => 'Invalid date description',
65
    );
66
67
    my $exception_holiday = $calendar->exception_holidays->iterator->next;
68
    my $now_dt            = DateTime->now;
69
70
    my $diff;
71
    eval { $diff = $calendar->days_between( $now_dt, $exception_holiday ) };
72
    unlike(
73
        $@,
74
        qr/Invalid local time for date in time zone: America\/Santiago/,
75
        'Avoid invalid datetime due to DST'
76
    );
77
78
    $schema->storage->txn_rollback;
79
};
80
81
$schema->storage->txn_begin;
82
83
# Create two fresh branches for the tests
84
my $branch_1 = $builder->build({ source => 'Branch' })->{ branchcode };
85
my $branch_2 = $builder->build({ source => 'Branch' })->{ branchcode };
86
87
C4::Calendar->new( branchcode => $branch_1 )->insert_week_day_holiday(
88
    weekday     => 0,
89
    title       => '',
90
    description => 'Sundays',
91
);
92
93
my $holiday2add = dt_from_string("2015-01-01");
94
C4::Calendar->new( branchcode => $branch_1 )->insert_day_month_holiday(
95
    day         => $holiday2add->day(),
96
    month       => $holiday2add->month(),
97
    year        => $holiday2add->year(),
98
    title       => '',
99
    description => "New Year's Day",
100
);
101
$holiday2add = dt_from_string("2014-12-25");
102
C4::Calendar->new( branchcode => $branch_1 )->insert_day_month_holiday(
103
    day         => $holiday2add->day(),
104
    month       => $holiday2add->month(),
105
    year        => $holiday2add->year(),
106
    title       => '',
107
    description => 'Christmas',
108
);
109
110
my $koha_calendar = Koha::Calendar->new( branchcode => $branch_1 );
111
my $c4_calendar = C4::Calendar->new( branchcode => $branch_1 );
112
113
isa_ok( $koha_calendar, 'Koha::Calendar', 'Koha::Calendar class returned' );
114
isa_ok( $c4_calendar,   'C4::Calendar',   'C4::Calendar class returned' );
115
116
my $sunday = DateTime->new(
117
    year  => 2011,
118
    month => 6,
119
    day   => 26,
120
);
121
my $monday = DateTime->new(
122
    year  => 2011,
123
    month => 6,
124
    day   => 27,
125
);
126
my $christmas = DateTime->new(
127
    year  => 2032,
128
    month => 12,
129
    day   => 25,
130
);
131
my $newyear = DateTime->new(
132
    year  => 2035,
133
    month => 1,
134
    day   => 1,
135
);
136
137
is( $koha_calendar->is_holiday($sunday),    1, 'Sunday is a closed day' );
138
is( $koha_calendar->is_holiday($monday),    0, 'Monday is not a closed day' );
139
is( $koha_calendar->is_holiday($christmas), 1, 'Christmas is a closed day' );
140
is( $koha_calendar->is_holiday($newyear),   1, 'New Years day is a closed day' );
141
142
$dbh->do("DELETE FROM repeatable_holidays");
143
$dbh->do("DELETE FROM special_holidays");
144
145
my $custom_holiday = DateTime->new(
146
    year  => 2013,
147
    month => 11,
148
    day   => 12,
149
);
150
151
my $today = dt_from_string();
152
C4::Calendar->new( branchcode => $branch_2 )->insert_single_holiday(
153
    day         => $today->day(),
154
    month       => $today->month(),
155
    year        => $today->year(),
156
    title       => "$today",
157
    description => "$today",
158
);
159
160
is( Koha::Calendar->new( branchcode => $branch_2 )->is_holiday( $today ), 1, "Today is a holiday for $branch_2" );
161
is( Koha::Calendar->new( branchcode => $branch_1 )->is_holiday( $today ), 0, "Today is not a holiday for $branch_1");
162
163
# Few tests for exception holidays
164
my ( $diff, $cal, $special );
165
$dbh->do("DELETE FROM special_holidays");
166
_add_exception( $today, $branch_1, 'Today' );
167
$cal = Koha::Calendar->new( branchcode => $branch_1 );
168
$special = $cal->exception_holidays;
169
is( $special->count, 1, 'One exception holiday added' );
170
171
my $tomorrow= dt_from_string();
172
$tomorrow->add_duration( DateTime::Duration->new(days => 1) );
173
_add_exception( $tomorrow, $branch_1, 'Tomorrow' );
174
$cal = Koha::Calendar->new( branchcode => $branch_1 );
175
$special = $cal->exception_holidays;
176
is( $special->count, 2, 'Set of exception holidays contains two dates' );
177
178
$diff = $today->delta_days( $special->min )->in_units('days');
179
is( $diff, 0, 'Lowest exception holiday is today' );
180
$diff = $tomorrow->delta_days( $special->max )->in_units('days');
181
is( $diff, 0, 'Highest exception holiday is tomorrow' );
182
183
C4::Calendar->new( branchcode => $branch_1 )->delete_holiday(
184
    weekday => $tomorrow->day_of_week,
185
    day     => $tomorrow->day,
186
    month   => $tomorrow->month,
187
    year    => $tomorrow->year,
188
);
189
$cal = Koha::Calendar->new( branchcode => $branch_1 );
190
$special = $cal->exception_holidays;
191
is( $special->count, 1, 'Set of exception holidays back to one' );
192
193
sub _add_exception {
194
    my ( $dt, $branch, $descr ) = @_;
195
    C4::Calendar->new( branchcode => $branch )->insert_exception_holiday(
196
        day         => $dt->day,
197
        month       => $dt->month,
198
        year        => $dt->year,
199
        title       => $descr,
200
        description => $descr,
201
    );
202
}
203
204
$schema->storage->txn_rollback;
205
(-)a/tools/copy-holidays.pl (-38 lines)
Lines 1-38 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2012 Catalyst IT
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it
8
# under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Koha is distributed in the hope that it will be useful, but
13
# WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with Koha; if not, see <http://www.gnu.org/licenses>.
19
20
use Modern::Perl;
21
22
use CGI qw ( -utf8 );
23
24
use C4::Auth;
25
use C4::Output;
26
27
28
use C4::Calendar;
29
30
my $input               = new CGI;
31
my $dbh                 = C4::Context->dbh();
32
33
my $branchcode          = $input->param('branchcode');
34
my $from_branchcode     = $input->param('from_branchcode');
35
36
C4::Calendar->new(branchcode => $from_branchcode)->copy_to_branch($branchcode) if $from_branchcode && $branchcode;
37
38
print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=".($branchcode || $from_branchcode));
(-)a/tools/exceptionHolidays.pl (-123 lines)
Lines 1-123 Link Here
1
#!/usr/bin/perl
2
3
use Modern::Perl;
4
5
use CGI qw ( -utf8 );
6
7
use C4::Auth;
8
use C4::Output;
9
use DateTime;
10
11
use C4::Calendar;
12
use Koha::DateUtils;
13
14
my $input = new CGI;
15
my $dbh = C4::Context->dbh();
16
17
my $branchcode = $input->param('showBranchName');
18
my $weekday = $input->param('showWeekday');
19
my $day = $input->param('showDay');
20
my $month = $input->param('showMonth');
21
my $year = $input->param('showYear');
22
my $title = $input->param('showTitle');
23
my $description = $input->param('showDescription');
24
my $holidaytype = $input->param('showHolidayType');
25
my $datecancelrange_dt = eval { dt_from_string( scalar $input->param('datecancelrange') ) };
26
my $calendardate = sprintf("%04d-%02d-%02d", $year, $month, $day);
27
28
my $calendar = C4::Calendar->new(branchcode => $branchcode);
29
30
$title || ($title = '');
31
if ($description) {
32
    $description =~ s/\r/\\r/g;
33
    $description =~ s/\n/\\n/g;
34
} else {
35
    $description = '';
36
}   
37
38
# We make an array with holiday's days
39
my @holiday_list;
40
if ($datecancelrange_dt){
41
            my $first_dt = DateTime->new(year => $year, month  => $month,  day => $day);
42
43
            for (my $dt = $first_dt->clone();
44
                $dt <= $datecancelrange_dt;
45
                $dt->add(days => 1) )
46
                {
47
                push @holiday_list, $dt->clone();
48
                }
49
}
50
if ($input->param('showOperation') eq 'exception') {
51
	$calendar->insert_exception_holiday(day => $day,
52
										month => $month,
53
									    year => $year,
54
						                title => $title,
55
						                description => $description);
56
} elsif ($input->param('showOperation') eq 'exceptionrange' ) {
57
        if (@holiday_list){
58
            foreach my $date (@holiday_list){
59
                $calendar->insert_exception_holiday(
60
                    day         => $date->{local_c}->{day},
61
                    month       => $date->{local_c}->{month},
62
                    year       => $date->{local_c}->{year},
63
                    title       => $title,
64
                    description => $description
65
                    );
66
            }
67
        }
68
} elsif ($input->param('showOperation') eq 'edit') {
69
    if($holidaytype eq 'weekday') {
70
      $calendar->ModWeekdayholiday(weekday => $weekday,
71
                                   title => $title,
72
                                   description => $description);
73
    } elsif ($holidaytype eq 'daymonth') {
74
      $calendar->ModDaymonthholiday(day => $day,
75
                                    month => $month,
76
                                    title => $title,
77
                                    description => $description);
78
    } elsif ($holidaytype eq 'ymd') {
79
      $calendar->ModSingleholiday(day => $day,
80
                                  month => $month,
81
                                  year => $year,
82
                                  title => $title,
83
                                  description => $description);
84
    } elsif ($holidaytype eq 'exception') {
85
      $calendar->ModExceptionholiday(day => $day,
86
                                  month => $month,
87
                                  year => $year,
88
                                  title => $title,
89
                                  description => $description);
90
    }
91
} elsif ($input->param('showOperation') eq 'delete') {
92
	$calendar->delete_holiday(weekday => $weekday,
93
	                          day => $day,
94
  	                          month => $month,
95
				              year => $year);
96
}elsif ($input->param('showOperation') eq 'deleterange') {
97
    if (@holiday_list){
98
        foreach my $date (@holiday_list){
99
            $calendar->delete_holiday_range(weekday => $weekday,
100
                                            day => $date->{local_c}->{day},
101
                                            month => $date->{local_c}->{month},
102
                                            year => $date->{local_c}->{year});
103
            }
104
    }
105
}elsif ($input->param('showOperation') eq 'deleterangerepeat') {
106
    if (@holiday_list){
107
        foreach my $date (@holiday_list){
108
           $calendar->delete_holiday_range_repeatable(weekday => $weekday,
109
                                         day => $date->{local_c}->{day},
110
                                         month => $date->{local_c}->{month});
111
        }
112
    }
113
}elsif ($input->param('showOperation') eq 'deleterangerepeatexcept') {
114
    if (@holiday_list){
115
        foreach my $date (@holiday_list){
116
           $calendar->delete_exception_holiday_range(weekday => $weekday,
117
                                         day => $date->{local_c}->{day},
118
                                         month => $date->{local_c}->{month},
119
                                         year => $date->{local_c}->{year});
120
        }
121
    }
122
}
123
print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=$branchcode&calendardate=$calendardate");
(-)a/tools/holidays.pl (-132 lines)
Lines 1-132 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
#####Sets holiday periods for each branch. Datedues will be extended if branch is closed -TG
19
use Modern::Perl;
20
21
use CGI qw ( -utf8 );
22
23
use C4::Auth;
24
use C4::Output;
25
26
use C4::Calendar;
27
use Koha::DateUtils;
28
29
my $input = new CGI;
30
31
my $dbh = C4::Context->dbh();
32
# Get the template to use
33
my ($template, $loggedinuser, $cookie)
34
    = get_template_and_user({template_name => "tools/holidays.tt",
35
                             type => "intranet",
36
                             query => $input,
37
                             authnotrequired => 0,
38
                             flagsrequired => {tools => 'edit_calendar'},
39
                             debug => 1,
40
                           });
41
42
# calendardate - date passed in url for human readability (syspref)
43
# if the url has an invalid date default to 'now.'
44
my $calendarinput_dt = eval { dt_from_string( scalar $input->param('calendardate') ); } || dt_from_string;
45
my $calendardate = output_pref( { dt => $calendarinput_dt, dateonly => 1 } );
46
47
# keydate - date passed to calendar.js.  calendar.js does not process dashes within a date.
48
my $keydate = output_pref( { dt => $calendarinput_dt, dateonly => 1, dateformat => 'iso' } );
49
$keydate =~ s/-/\//g;
50
51
my $branch= $input->param('branch') || C4::Context->userenv->{'branch'};
52
53
# Get all the holidays
54
55
my $calendar = C4::Calendar->new(branchcode => $branch);
56
my $week_days_holidays = $calendar->get_week_days_holidays();
57
my @week_days;
58
foreach my $weekday (keys %$week_days_holidays) {
59
# warn "WEEK DAY : $weekday";
60
    my %week_day;
61
    %week_day = (KEY => $weekday,
62
                 TITLE => $week_days_holidays->{$weekday}{title},
63
                 DESCRIPTION => $week_days_holidays->{$weekday}{description});
64
    push @week_days, \%week_day;
65
}
66
67
my $day_month_holidays = $calendar->get_day_month_holidays();
68
my @day_month_holidays;
69
foreach my $monthDay (keys %$day_month_holidays) {
70
    # Determine date format on month and day.
71
    my $day_monthdate;
72
    my $day_monthdate_sort;
73
    if (C4::Context->preference("dateformat") eq "metric") {
74
      $day_monthdate_sort = "$day_month_holidays->{$monthDay}{month}-$day_month_holidays->{$monthDay}{day}";
75
      $day_monthdate = "$day_month_holidays->{$monthDay}{day}/$day_month_holidays->{$monthDay}{month}";
76
    } elsif (C4::Context->preference("dateformat") eq "dmydot") {
77
      $day_monthdate_sort = "$day_month_holidays->{$monthDay}{month}.$day_month_holidays->{$monthDay}{day}";
78
      $day_monthdate = "$day_month_holidays->{$monthDay}{day}.$day_month_holidays->{$monthDay}{month}";
79
    }elsif (C4::Context->preference("dateformat") eq "us") {
80
      $day_monthdate = "$day_month_holidays->{$monthDay}{month}/$day_month_holidays->{$monthDay}{day}";
81
      $day_monthdate_sort = $day_monthdate;
82
    } else {
83
      $day_monthdate = "$day_month_holidays->{$monthDay}{month}-$day_month_holidays->{$monthDay}{day}";
84
      $day_monthdate_sort = $day_monthdate;
85
    }
86
    my %day_month;
87
    %day_month = (KEY => $monthDay,
88
                  DATE_SORT => $day_monthdate_sort,
89
                  DATE => $day_monthdate,
90
                  TITLE => $day_month_holidays->{$monthDay}{title},
91
                  DESCRIPTION => $day_month_holidays->{$monthDay}{description});
92
    push @day_month_holidays, \%day_month;
93
}
94
95
my $exception_holidays = $calendar->get_exception_holidays();
96
my @exception_holidays;
97
foreach my $yearMonthDay (keys %$exception_holidays) {
98
    my $exceptiondate = eval { dt_from_string( $exception_holidays->{$yearMonthDay}{date} ) };
99
    my %exception_holiday;
100
    %exception_holiday = (KEY => $yearMonthDay,
101
                          DATE_SORT => $exception_holidays->{$yearMonthDay}{date},
102
                          DATE => output_pref( { dt => $exceptiondate, dateonly => 1 } ),
103
                          TITLE => $exception_holidays->{$yearMonthDay}{title},
104
                          DESCRIPTION => $exception_holidays->{$yearMonthDay}{description});
105
    push @exception_holidays, \%exception_holiday;
106
}
107
108
my $single_holidays = $calendar->get_single_holidays();
109
my @holidays;
110
foreach my $yearMonthDay (keys %$single_holidays) {
111
    my $holidaydate_dt = eval { dt_from_string( $single_holidays->{$yearMonthDay}{date} ) };
112
    my %holiday;
113
    %holiday = (KEY => $yearMonthDay,
114
                DATE_SORT => $single_holidays->{$yearMonthDay}{date},
115
                DATE => output_pref( { dt => $holidaydate_dt, dateonly => 1 } ),
116
                TITLE => $single_holidays->{$yearMonthDay}{title},
117
                DESCRIPTION => $single_holidays->{$yearMonthDay}{description});
118
    push @holidays, \%holiday;
119
}
120
121
$template->param(
122
    WEEK_DAYS_LOOP           => \@week_days,
123
    HOLIDAYS_LOOP            => \@holidays,
124
    EXCEPTION_HOLIDAYS_LOOP  => \@exception_holidays,
125
    DAY_MONTH_HOLIDAYS_LOOP  => \@day_month_holidays,
126
    calendardate             => $calendardate,
127
    keydate                  => $keydate,
128
    branch                   => $branch,
129
);
130
131
# Shows the template with the real values replaced
132
output_html_with_http_headers $input, $cookie, $template->output;
(-)a/tools/newHolidays.pl (-148 lines)
Lines 1-147 Link Here
1
#!/usr/bin/perl
2
#FIXME: perltidy this file
3
4
# This file is part of Koha.
5
#
6
# Koha is free software; you can redistribute it and/or modify it
7
# under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# Koha is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public Lic# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
# along with Koha; if not, see <http://www.gnu.org/licenses>.
18
19
20
use Modern::Perl;
21
22
use CGI qw ( -utf8 );
23
24
use C4::Auth;
25
use C4::Output;
26
27
use Koha::Caches;
28
29
use C4::Calendar;
30
use DateTime;
31
use Koha::DateUtils;
32
33
my $input               = new CGI;
34
my $dbh                 = C4::Context->dbh();
35
36
our $branchcode          = $input->param('newBranchName');
37
my $originalbranchcode  = $branchcode;
38
our $weekday             = $input->param('newWeekday');
39
our $day                 = $input->param('newDay');
40
our $month               = $input->param('newMonth');
41
our $year                = $input->param('newYear');
42
my $dateofrange         = $input->param('dateofrange');
43
our $title               = $input->param('newTitle');
44
our $description         = $input->param('newDescription');
45
our $newoperation        = $input->param('newOperation');
46
my $allbranches         = $input->param('allBranches');
47
48
49
my $first_dt = DateTime->new(year => $year, month  => $month,  day => $day);
50
my $end_dt   = eval { dt_from_string( $dateofrange ); };
51
52
my $calendardate = output_pref( { dt => $first_dt, dateonly => 1, dateformat => 'iso' } );
53
54
$title || ($title = '');
55
if ($description) {
56
	$description =~ s/\r/\\r/g;
57
	$description =~ s/\n/\\n/g;
58
} else {
59
	$description = '';
60
}
61
62
# We make an array with holiday's days
63
our @holiday_list;
64
if ($end_dt){
65
    for (my $dt = $first_dt->clone();
66
    $dt <= $end_dt;
67
    $dt->add(days => 1) )
68
    {
69
        push @holiday_list, $dt->clone();
70
    }
71
}
72
73
if($allbranches) {
74
    my $libraries = Koha::Libraries->search;
75
    while ( my $library = $libraries->next ) {
76
        add_holiday($newoperation, $library->branchcode, $weekday, $day, $month, $year, $title, $description);
77
    }
78
} else {
79
    add_holiday($newoperation, $branchcode, $weekday, $day, $month, $year, $title, $description);
80
}
81
82
print $input->redirect("/cgi-bin/koha/tools/holidays.pl?branch=$originalbranchcode&calendardate=$calendardate");
83
84
#FIXME: move add_holiday() to a better place
85
sub add_holiday {
86
	($newoperation, $branchcode, $weekday, $day, $month, $year, $title, $description) = @_;  
87
	my $calendar = C4::Calendar->new(branchcode => $branchcode);
88
89
	if ($newoperation eq 'weekday') {
90
		unless ( $weekday && ($weekday ne '') ) { 
91
			# was dow calculated by javascript?  original code implies it was supposed to be.
92
			# if not, we need it.
93
			$weekday = &Date::Calc::Day_of_Week($year, $month, $day) % 7 unless($weekday);
94
		}
95
		unless($calendar->isHoliday($day, $month, $year)) {
96
			$calendar->insert_week_day_holiday(weekday => $weekday,
97
							           title => $title,
98
							           description => $description);
99
		}
100
	} elsif ($newoperation eq 'repeatable') {
101
		unless($calendar->isHoliday($day, $month, $year)) {
102
			$calendar->insert_day_month_holiday(day => $day,
103
	                                    month => $month,
104
							            title => $title,
105
							            description => $description);
106
		}
107
	} elsif ($newoperation eq 'holiday') {
108
		unless($calendar->isHoliday($day, $month, $year)) {
109
			$calendar->insert_single_holiday(day => $day,
110
	                                 month => $month,
111
						             year => $year,
112
						             title => $title,
113
						             description => $description);
114
		}
115
116
	} elsif ( $newoperation eq 'holidayrange' ) {
117
        if (@holiday_list){
118
            foreach my $date (@holiday_list){
119
                unless ( $calendar->isHoliday( $date->{local_c}->{day}, $date->{local_c}->{month}, $date->{local_c}->{year} ) ) {
120
                    $calendar->insert_single_holiday(
121
                        day         => $date->{local_c}->{day},
122
                        month       => $date->{local_c}->{month},
123
                        year        => $date->{local_c}->{year},
124
                        title       => $title,
125
                        description => $description
126
                    );
127
                }
128
            }
129
        }
130
    } elsif ( $newoperation eq 'holidayrangerepeat' ) {
131
        if (@holiday_list){
132
            foreach my $date (@holiday_list){
133
                unless ( $calendar->isHoliday( $date->{local_c}->{day}, $date->{local_c}->{month}, $date->{local_c}->{year} ) ) {
134
                    $calendar->insert_day_month_holiday(
135
                        day         => $date->{local_c}->{day},
136
                        month       => $date->{local_c}->{month},
137
                        title       => $title,
138
                        description => $description
139
                    );
140
                }
141
            }
142
        }
143
    }
144
    # we updated the single_holidays table, so wipe its cache
145
    my $cache = Koha::Caches->get_instance();
146
    $cache->clear_from_cache( 'single_holidays') ;
147
}
148
- 

Return to bug 17015