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

(-)a/t/db_dependent/Calendar.t (-718 lines)
Lines 1-718 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::NoWarnings;
21
use Test::More tests => 7;
22
use Time::Fake;
23
24
use t::lib::Mocks;
25
use t::lib::TestBuilder;
26
27
use DateTime;
28
use DateTime::Duration;
29
use Koha::Caches;
30
use Koha::Calendar;
31
use Koha::Database;
32
use Koha::DateUtils qw( dt_from_string );
33
34
my $schema  = Koha::Database->new->schema;
35
my $builder = t::lib::TestBuilder->new;
36
$schema->storage->txn_begin;
37
38
my $today      = dt_from_string();
39
my $holiday_dt = $today->clone;
40
$holiday_dt->add( days => 3 );
41
42
Koha::Caches->get_instance()->flush_all();
43
44
subtest 'Original tests from t' => sub {
45
46
    # We need to mock the C4::Context->preference method for
47
    # simplicity and re-usability of the session definition. Any
48
    # syspref fits for syspref-agnostic tests.
49
    my $module_context = Test::MockModule->new('C4::Context');
50
    $module_context->mock(
51
        'preference',
52
        sub {
53
            return 'Calendar';
54
        }
55
    );
56
57
    my $mpl  = $builder->build_object( { class => 'Koha::Libraries' } )->branchcode;
58
    my $cpl  = $builder->build_object( { class => 'Koha::Libraries' } )->branchcode;
59
    my $rows = [    # add weekly holidays
60
        { branchcode => $mpl, weekday => 0 },                  # sundays
61
        { branchcode => $mpl, weekday => 6 },                  # saturdays
62
        { branchcode => $mpl, day     => 1,  month => 1 },     # new year's day
63
        { branchcode => $mpl, day     => 25, month => 12 },    # chrismas
64
    ];
65
    $schema->resultset('RepeatableHoliday')->delete_all;
66
    $schema->resultset('RepeatableHoliday')->create( { %$_, description => q{} } ) for @$rows;
67
68
    $rows = [                                                  # exception holidays
69
        { branchcode => $mpl, day => 11, month => 11, year => 2012, isexception => 1 },    # sunday exception
70
        { branchcode => $mpl, day => 1,  month => 6,  year => 2011, isexception => 0 },
71
        { branchcode => $mpl, day => 4,  month => 7,  year => 2012, isexception => 0 },
72
        { branchcode => $cpl, day => 6,  month => 8,  year => 2012, isexception => 0 },
73
        { branchcode => $mpl, day => 7,  month => 7,  year => 2012, isexception => 1 },    # holiday exception
74
        { branchcode => $mpl, day => 7,  month => 7,  year => 2012, isexception => 0 },    # holiday
75
    ];
76
    $schema->resultset('SpecialHoliday')->delete_all;
77
    $schema->resultset('SpecialHoliday')->create( { %$_, description => q{} } ) for @$rows;
78
79
    my $cache = Koha::Caches->get_instance();
80
    $cache->clear_from_cache( $mpl . '_holidays' );
81
    $cache->clear_from_cache( $cpl . '_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 addDuration
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
    my $holiday_excepted = DateTime->new(
143
        year  => 2012,
144
        month => 7,
145
        day   => 7,      # Both a holiday and exception
146
    );
147
148
    {                    # Syspref-agnostic tests
149
        is( $saturday->day_of_week,              6, '\'$saturday\' is actually a saturday (6th day of week)' );
150
        is( $sunday->day_of_week,                7, '\'$sunday\' is actually a sunday (7th day of week)' );
151
        is( $monday->day_of_week,                1, '\'$monday\' is actually a monday (1st day of week)' );
152
        is( $cal->is_holiday($saturday),         1, 'Saturday is a closed day' );
153
        is( $cal->is_holiday($sunday),           1, 'Sunday is a closed day' );
154
        is( $cal->is_holiday($monday),           0, 'Monday is not a closed day' );
155
        is( $cal->is_holiday($new_year),         1, 'Month/Day closed day test (New year\'s day)' );
156
        is( $cal->is_holiday($single_holiday),   1, 'Single holiday closed day test' );
157
        is( $cal->is_holiday($notspecial),       0, 'Fixed single date that is not a holiday test' );
158
        is( $cal->is_holiday($sunday_exception), 0, 'Exception holiday is not a closed day test' );
159
        is(
160
            $cal->is_holiday($holiday_for_another_branch), 0,
161
            'Holiday defined for another branch should not be defined as an holiday'
162
        );
163
        is( $cal->is_holiday($holiday_excepted), 0, 'Holiday defined and excepted should not be a holiday' );
164
    }
165
166
    {    # Bugzilla #8966 - is_holiday truncates referenced date
167
        my $later_dt = DateTime->new(    # Monday
168
            year      => 2012,
169
            month     => 9,
170
            day       => 17,
171
            hour      => 17,
172
            minute    => 30,
173
            time_zone => 'Europe/London',
174
        );
175
176
        is( $cal->is_holiday($later_dt), 0, 'bz-8966 (1/2) Apply is_holiday for the next test' );
177
        cmp_ok( $later_dt, 'eq', '2012-09-17T17:30:00', 'bz-8966 (2/2) Date should be the same after is_holiday' );
178
    }
179
180
    {    # Bugzilla #8800 - is_holiday should use truncated date for 'contains' call
181
        my $single_holiday_time = DateTime->new(
182
            year   => 2011,
183
            month  => 6,
184
            day    => 1,
185
            hour   => 11,
186
            minute => 2
187
        );
188
189
        is(
190
            $cal->is_holiday($single_holiday_time),
191
            $cal->is_holiday($single_holiday),
192
            'bz-8800 is_holiday should truncate the date for holiday validation'
193
        );
194
    }
195
196
    my $one_day_dur   = DateTime::Duration->new( days => 1 );
197
    my $two_day_dur   = DateTime::Duration->new( days => 2 );
198
    my $seven_day_dur = DateTime::Duration->new( days => 7 );
199
200
    my $dt = dt_from_string( '2012-07-03', 'iso' );    #tuesday
201
202
    my $test_dt = DateTime->new(                       # Monday
203
        year   => 2012,
204
        month  => 7,
205
        day    => 23,
206
        hour   => 11,
207
        minute => 53,
208
    );
209
210
    my $later_dt = DateTime->new(                      # Monday
211
        year      => 2012,
212
        month     => 9,
213
        day       => 17,
214
        hour      => 17,
215
        minute    => 30,
216
        time_zone => 'Europe/London',
217
    );
218
219
    {                                                  ## 'Datedue' tests
220
221
        $cal = Koha::Calendar->new( branchcode => $mpl, days_mode => 'Datedue' );
222
223
        is(
224
            $cal->addDuration( $dt, $one_day_dur, 'days' ),    # tuesday
225
            dt_from_string( '2012-07-05', 'iso' ),
226
            'Single day add (Datedue, matches holiday, shift)'
227
        );
228
229
        is(
230
            $cal->addDuration( $dt, $two_day_dur, 'days' ),
231
            dt_from_string( '2012-07-05', 'iso' ),
232
            'Two days add, skips holiday (Datedue)'
233
        );
234
235
        cmp_ok(
236
            $cal->addDuration( $test_dt, $seven_day_dur, 'days' ), 'eq',
237
            '2012-07-30T11:53:00',
238
            'Add 7 days (Datedue)'
239
        );
240
241
        is(
242
            $cal->addDuration( $saturday, $one_day_dur, 'days' )->day_of_week, 1,
243
            'addDuration skips closed Sunday (Datedue)'
244
        );
245
246
        is(
247
            $cal->addDuration( $day_after_christmas, -1, 'days' )->ymd(), '2012-12-24',
248
            'Negative call to addDuration (Datedue)'
249
        );
250
251
        ## Note that the days_between API says closed days are not considered.
252
        ## This tests are here as an API test.
253
        cmp_ok(
254
            $cal->days_between( $test_dt, $later_dt )->in_units('days'),
255
            '==', 40, 'days_between calculates correctly (Days)'
256
        );
257
258
        cmp_ok(
259
            $cal->days_between( $later_dt, $test_dt )->in_units('days'),
260
            '==', 40, 'Test parameter order not relevant (Days)'
261
        );
262
    }
263
264
    {    ## 'Calendar' tests'
265
266
        $cal = Koha::Calendar->new( branchcode => $mpl, days_mode => 'Calendar' );
267
268
        $dt = dt_from_string( '2012-07-03', 'iso' );
269
270
        is(
271
            $cal->addDuration( $dt, $one_day_dur, 'days' ),
272
            dt_from_string( '2012-07-05', 'iso' ),
273
            'Single day add (Calendar)'
274
        );
275
276
        cmp_ok(
277
            $cal->addDuration( $test_dt, $seven_day_dur, 'days' ), 'eq',
278
            '2012-08-01T11:53:00',
279
            'Add 7 days (Calendar)'
280
        );
281
282
        is(
283
            $cal->addDuration( $saturday, $one_day_dur, 'days' )->day_of_week, 1,
284
            'addDuration skips closed Sunday (Calendar)'
285
        );
286
287
        is(
288
            $cal->addDuration( $day_after_christmas, -1, 'days' )->ymd(), '2012-12-24',
289
            'Negative call to addDuration (Calendar)'
290
        );
291
292
        cmp_ok(
293
            $cal->days_between( $test_dt, $later_dt )->in_units('days'),
294
            '==', 40, 'days_between calculates correctly (Calendar)'
295
        );
296
297
        cmp_ok(
298
            $cal->days_between( $later_dt, $test_dt )->in_units('days'),
299
            '==', 40, 'Test parameter order not relevant (Calendar)'
300
        );
301
    }
302
303
    {    ## 'Days' tests
304
305
        $cal = Koha::Calendar->new( branchcode => $mpl, days_mode => 'Days' );
306
307
        $dt = dt_from_string( '2012-07-03', 'iso' );
308
309
        is(
310
            $cal->addDuration( $dt, $one_day_dur, 'days' ),
311
            dt_from_string( '2012-07-04', 'iso' ),
312
            'Single day add (Days)'
313
        );
314
315
        cmp_ok(
316
            $cal->addDuration( $test_dt, $seven_day_dur, 'days' ), 'eq',
317
            '2012-07-30T11:53:00',
318
            'Add 7 days (Days)'
319
        );
320
321
        is(
322
            $cal->addDuration( $saturday, $one_day_dur, 'days' )->day_of_week, 7,
323
            'addDuration doesn\'t skip closed Sunday (Days)'
324
        );
325
326
        is(
327
            $cal->addDuration( $day_after_christmas, -1, 'days' )->ymd(), '2012-12-25',
328
            'Negative call to addDuration (Days)'
329
        );
330
331
        ## Note that the days_between API says closed days are not considered.
332
        ## This tests are here as an API test.
333
        cmp_ok(
334
            $cal->days_between( $test_dt, $later_dt )->in_units('days'),
335
            '==', 40, 'days_between calculates correctly (Days)'
336
        );
337
338
        cmp_ok(
339
            $cal->days_between( $later_dt, $test_dt )->in_units('days'),
340
            '==', 40, 'Test parameter order not relevant (Days)'
341
        );
342
343
    }
344
345
    {
346
        $cal = Koha::Calendar->new( branchcode => $cpl );
347
        is( $cal->is_holiday($single_holiday), 0, 'Single holiday for MPL, not CPL' );
348
        is(
349
            $cal->is_holiday($holiday_for_another_branch), 1,
350
            'Holiday defined for CPL should be defined as an holiday'
351
        );
352
    }
353
354
    subtest 'days_mode parameter' => sub {
355
        plan tests => 1;
356
357
        t::lib::Mocks::mock_preference( 'useDaysMode', 'Days' );
358
359
        $cal = Koha::Calendar->new( branchcode => $cpl, days_mode => 'Calendar' );
360
        is( $cal->{days_mode}, 'Calendar', q|If set, days_mode is correctly set| );
361
    };
362
363
    $cache->clear_from_cache( $mpl . '_holidays' );
364
    $cache->clear_from_cache( $cpl . '_holidays' );
365
};
366
367
my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
368
my $calendar = Koha::Calendar->new( branchcode => $library->branchcode, days_mode => 'Calendar' );
369
my $holiday  = $builder->build(
370
    {
371
        source => 'SpecialHoliday',
372
        value  => {
373
            branchcode  => $library->branchcode,
374
            day         => $holiday_dt->day,
375
            month       => $holiday_dt->month,
376
            year        => $holiday_dt->year,
377
            title       => 'My holiday',
378
            isexception => 0
379
        },
380
    }
381
);
382
383
subtest 'days_forward' => sub {
384
    plan tests => 4;
385
386
    my $forwarded_dt = $calendar->days_forward( $today, 2 );
387
    my $expected     = $today->clone->add( days => 2 );
388
    is( $forwarded_dt->ymd, $expected->ymd, 'With no holiday on the perioddays_forward should add 2 days' );
389
390
    $forwarded_dt = $calendar->days_forward( $today, 5 );
391
    $expected     = $today->clone->add( days => 6 );
392
    is(
393
        $forwarded_dt->ymd, $expected->ymd,
394
        'With holiday on the perioddays_forward should add 5 days + 1 day for holiday'
395
    );
396
397
    $forwarded_dt = $calendar->days_forward( $today, 0 );
398
    is( $forwarded_dt->ymd, $today->ymd, '0 day should return start dt' );
399
400
    $forwarded_dt = $calendar->days_forward( $today, -2 );
401
    is( $forwarded_dt->ymd, $today->ymd, 'negative day should return start dt' );
402
};
403
404
subtest 'crossing_DST' => sub {
405
406
    plan tests => 3;
407
408
    my $tz           = DateTime::TimeZone->new( name => 'America/New_York' );
409
    my $start_date   = dt_from_string( "2016-03-09 02:29:00", undef, $tz );
410
    my $end_date     = dt_from_string( "2017-01-01 00:00:00", undef, $tz );
411
    my $days_between = $calendar->days_between( $start_date, $end_date );
412
    is( $days_between->delta_days, 298, "Days calculated correctly" );
413
    $days_between = $calendar->days_between( $end_date, $start_date );
414
    is( $days_between->delta_days, 298, "Swapping returns the same" );
415
    my $hours_between = $calendar->hours_between( $start_date, $end_date );
416
    is(
417
        $hours_between->delta_minutes,
418
        298 * 24 * 60 - 149,
419
        "Hours (in minutes) calculated correctly"
420
    );
421
};
422
423
subtest 'hours_between | days_between' => sub {
424
425
    plan tests => 2;
426
427
    #    November 2019
428
    # Su Mo Tu We Th Fr Sa
429
    #                 1  2
430
    #  3  4 *5* 6  7  8  9
431
    # 10 11 12 13 14 15 16
432
    # 17 18 19 20 21 22 23
433
    # 24 25 26 27 28 29 30
434
435
    my $now    = dt_from_string('2019-11-05 12:34:56');    # Today is 2019 Nov 5th
436
    my $nov_6  = dt_from_string('2019-11-06 12:34:56');
437
    my $nov_7  = dt_from_string('2019-11-07 12:34:56');
438
    my $nov_12 = dt_from_string('2019-11-12 12:34:56');
439
    my $nov_13 = dt_from_string('2019-11-13 12:34:56');
440
    my $nov_15 = dt_from_string('2019-11-15 12:34:56');
441
    Time::Fake->offset( $now->epoch );
442
443
    subtest 'No holiday' => sub {
444
445
        plan tests => 2;
446
447
        my $library  = $builder->build_object( { class => 'Koha::Libraries' } );
448
        my $calendar = Koha::Calendar->new( branchcode => $library->branchcode );
449
450
        subtest 'Same hours' => sub {
451
452
            plan tests => 8;
453
454
            # Between 5th and 6th
455
            my $diff_hours = $calendar->hours_between( $now, $nov_6 )->hours;
456
            is( $diff_hours, 1 * 24, 'hours: 1 day, no holiday' );
457
            my $diff_days = $calendar->days_between( $now, $nov_6 )->delta_days;
458
            is( $diff_days, 1, 'days: 1 day, no holiday' );
459
460
            # Between 5th and 7th
461
            $diff_hours = $calendar->hours_between( $now, $nov_7 )->hours;
462
            is( $diff_hours, 2 * 24, 'hours: 2 days, no holiday' );
463
            $diff_days = $calendar->days_between( $now, $nov_7 )->delta_days;
464
            is( $diff_days, 2, 'days: 2 days, no holiday' );
465
466
            # Between 5th and 12th
467
            $diff_hours = $calendar->hours_between( $now, $nov_12 )->hours;
468
            is( $diff_hours, 7 * 24, 'hours: 7 days, no holiday' );
469
            $diff_days = $calendar->days_between( $now, $nov_12 )->delta_days;
470
            is( $diff_days, 7, 'days: 7 days, no holiday' );
471
472
            # Between 5th and 15th
473
            $diff_hours = $calendar->hours_between( $now, $nov_15 )->hours;
474
            is( $diff_hours, 10 * 24, 'hours: 10 days, no holiday' );
475
            $diff_days = $calendar->days_between( $now, $nov_15 )->delta_days;
476
            is( $diff_days, 10, 'days: 10 days, no holiday' );
477
        };
478
479
        subtest 'Different hours' => sub {
480
481
            plan tests => 10;
482
483
            # Between 5th and 5th (Same day short hours loan)
484
            my $diff_hours = $calendar->hours_between( $now, $now->clone->add( hours => 3 ) )->hours;
485
            is( $diff_hours, 3, 'hours: 3 hours, no holidays' );
486
            my $diff_days = $calendar->days_between( $now, $now->clone->add( hours => 3 ) )->delta_days;
487
            is( $diff_days, 0, 'days: 3 hours, no holidays' );
488
489
            # Between 5th and 6th
490
            $diff_hours = $calendar->hours_between( $now, $nov_6->clone->subtract( hours => 3 ) )->hours;
491
            is( $diff_hours, 1 * 24 - 3, 'hours: 21 hours, no holidays' );
492
            $diff_days = $calendar->days_between( $now, $nov_6->clone->subtract( hours => 3 ) )->delta_days;
493
            is( $diff_days, 1, 'days: 21 hours, no holidays' );
494
495
            # Between 5th and 7th
496
            $diff_hours = $calendar->hours_between( $now, $nov_7->clone->subtract( hours => 3 ) )->hours;
497
            is( $diff_hours, 2 * 24 - 3, 'hours: 45 hours, no holidays' );
498
            $diff_days = $calendar->days_between( $now, $nov_7->clone->subtract( hours => 3 ) )->delta_days;
499
            is( $diff_days, 2, 'days: 45 hours, no holidays' );
500
501
            # Between 5th and 12th
502
            $diff_hours = $calendar->hours_between( $now, $nov_12->clone->subtract( hours => 3 ) )->hours;
503
            is( $diff_hours, 7 * 24 - 3, 'hours: 165 hours, no holidays' );
504
            $diff_days = $calendar->days_between( $now, $nov_12->clone->subtract( hours => 3 ) )->delta_days;
505
            is( $diff_days, 7, 'days: 165 hours, no holidays' );
506
507
            # Between 5th and 15th
508
            $diff_hours = $calendar->hours_between( $now, $nov_15->clone->subtract( hours => 3 ) )->hours;
509
            is( $diff_hours, 10 * 24 - 3, 'hours: 237 hours, no holidays' );
510
            $diff_days = $calendar->days_between( $now, $nov_15->clone->subtract( hours => 3 ) )->delta_days;
511
            is( $diff_days, 10, 'days: 237 hours, no holidays' );
512
        };
513
    };
514
515
    subtest 'With holiday' => sub {
516
        plan tests => 2;
517
518
        my $library = $builder->build_object( { class => 'Koha::Libraries' } );
519
520
        # Wednesdays are closed
521
        my $dbh = C4::Context->dbh;
522
        $dbh->do(
523
            q|
524
            INSERT INTO repeatable_holidays (branchcode,weekday,day,month,title,description)
525
            VALUES ( ?, ?, NULL, NULL, ?, '' )
526
        |, undef, $library->branchcode, 3, 'Closed on Wednesday'
527
        );
528
529
        my $calendar = Koha::Calendar->new( branchcode => $library->branchcode );
530
531
        subtest 'Same hours' => sub {
532
            plan tests => 12;
533
534
            my ( $diff_hours, $diff_days );
535
536
            # Between 5th and 6th (This case should never happen in real code, one cannot return on a closed day)
537
            $diff_hours = $calendar->hours_between( $now, $nov_6 )->hours;
538
            is( $diff_hours, 0 * 24, 'hours: 1 day, end_dt = holiday' );    # FIXME Is this really should be 0?
539
            $diff_days = $calendar->days_between( $now, $nov_6 )->delta_days;
540
            is( $diff_days, 0, 'days: 1 day, end_dt = holiday' );           # FIXME Is this really should be 0?
541
542
            # Between 6th and 7th (This case should never happen in real code, one cannot issue on a closed day)
543
            $diff_hours = $calendar->hours_between( $nov_6, $nov_7 )->hours;
544
            is( $diff_hours, 0 * 24, 'hours: 1 day, start_dt = holiday' );    # FIXME Is this really should be 0?
545
            $diff_days = $calendar->days_between( $nov_6, $nov_7 )->delta_days;
546
            is( $diff_days, 0, 'days: 1 day, start_dt = holiday' );           # FIXME Is this really should be 0?
547
548
            # Between 5th and 7th
549
            $diff_hours = $calendar->hours_between( $now, $nov_7 )->hours;
550
            is( $diff_hours, 2 * 24 - 1 * 24, 'hours: 2 days, 1 holiday' );
551
            $diff_days = $calendar->days_between( $now, $nov_7 )->delta_days;
552
            is( $diff_days, 2 - 1, 'days: 2 days, 1 holiday' );
553
554
            # Between 5th and 12th
555
            $diff_hours = $calendar->hours_between( $now, $nov_12 )->hours;
556
            is( $diff_hours, 7 * 24 - 1 * 24, 'hours: 7 days, 1 holiday' );
557
            $diff_days = $calendar->days_between( $now, $nov_12 )->delta_days;
558
            is( $diff_days, 7 - 1, 'day: 7 days, 1 holiday' );
559
560
            # Between 5th and 13th
561
            $diff_hours = $calendar->hours_between( $now, $nov_13 )->hours;
562
            is( $diff_hours, 8 * 24 - 2 * 24, 'hours: 8 days, 2 holidays' );
563
            $diff_days = $calendar->days_between( $now, $nov_13 )->delta_days;
564
            is( $diff_days, 8 - 2, 'days: 8 days, 2 holidays' );
565
566
            # Between 5th and 15th
567
            $diff_hours = $calendar->hours_between( $now, $nov_15 )->hours;
568
            is( $diff_hours, 10 * 24 - 2 * 24, 'hours: 10 days, 2 holidays' );
569
            $diff_days = $calendar->days_between( $now, $nov_15 )->delta_days;
570
            is( $diff_days, 10 - 2, 'days: 10 days, 2 holidays' );
571
        };
572
573
        subtest 'Different hours' => sub {
574
            plan tests => 14;
575
576
            my ( $diff_hours, $diff_days );
577
578
            # Between 5th and 5th (Same day short hours loan)
579
            # No test - Tested above as 5th is an open day
580
581
            # Between 5th and 6th (This case should never happen in real code, one cannot return on a closed day)
582
            my $duration = $calendar->hours_between( $now, $nov_6->clone->subtract( hours => 3 ) );
583
            is( $duration->hours, abs( 0 * 24 - 3 ), 'hours: 21 hours, end_dt = holiday' )
584
                ;    # FIXME $duration->hours always return a abs
585
            is( $duration->is_negative, 1, '? is negative ?' )
586
                ;    # FIXME Do really test for that case in our calls to hours_between?
587
            $duration = $calendar->days_between( $now, $nov_6->clone->subtract( hours => 3 ) );
588
            is( $duration->hours, abs(0), 'days: 21 hours, end_dt = holiday' );    # FIXME Is this correct?
589
590
            # Between 6th and 7th (This case should never happen in real code, one cannot issue on a closed day)
591
            $duration = $calendar->hours_between( $nov_6, $nov_7->clone->subtract( hours => 3 ) );
592
            is( $duration->hours, abs( 0 * 24 - 3 ), 'hours: 21 hours, start_dt = holiday' )
593
                ;    # FIXME $duration->hours always return a abs
594
            is( $duration->is_negative, 1, '? is negative ?' )
595
                ;    # FIXME Do really test for that case in our calls to hours_between?
596
            $duration = $calendar->days_between( $nov_6, $nov_7->clone->subtract( hours => 3 ) );
597
            is( $duration->hours, abs(0), 'days: 21 hours, start_dt = holiday' );    # FIXME Is this correct?
598
599
            # Between 5th and 7th
600
            $diff_hours = $calendar->hours_between( $now, $nov_7->clone->subtract( hours => 3 ) )->hours;
601
            is( $diff_hours, 2 * 24 - 1 * 24 - 3, 'hours: 45 hours, 1 holiday' );
602
            $diff_days = $calendar->days_between( $now, $nov_7->clone->subtract( hours => 3 ) )->delta_days;
603
            is( $diff_days, 2 - 1, 'days: 45 hours, 1 holiday' );
604
605
            # Between 5th and 12th
606
            $diff_hours = $calendar->hours_between( $now, $nov_12->clone->subtract( hours => 3 ) )->hours;
607
            is( $diff_hours, 7 * 24 - 1 * 24 - 3, 'hours: 165 hours, 1 holiday' );
608
            $diff_days = $calendar->days_between( $now, $nov_12->clone->subtract( hours => 3 ) )->delta_days;
609
            is( $diff_days, 7 - 1, 'days: 165 hours, 1 holiday' );
610
611
            # Between 5th and 13th
612
            $diff_hours = $calendar->hours_between( $now, $nov_13->clone->subtract( hours => 3 ) )->hours;
613
            is( $diff_hours, 8 * 24 - 2 * 24 - 3, 'hours: 289 hours, 2 holidays ' );
614
            $diff_days = $calendar->days_between( $now, $nov_13->clone->subtract( hours => 3 ) )->delta_days;
615
            is( $diff_days, 8 - 1, 'days: 289 hours, 2 holidays' );
616
617
            # Between 5th and 15th
618
            $diff_hours = $calendar->hours_between( $now, $nov_15->clone->subtract( hours => 3 ) )->hours;
619
            is( $diff_hours, 10 * 24 - 2 * 24 - 3, 'hours: 237 hours, 2 holidays' );
620
            $diff_days = $calendar->days_between( $now, $nov_15->clone->subtract( hours => 3 ) )->delta_days;
621
            is( $diff_days, 10 - 2, 'days: 237 hours, 2 holidays' );
622
        };
623
624
    };
625
626
    Time::Fake->reset;
627
};
628
629
subtest 'is_holiday' => sub {
630
    plan tests => 1;
631
632
    subtest 'weekday holidays' => sub {
633
        plan tests => 7;
634
635
        my $library = $builder->build_object( { class => 'Koha::Libraries' } );
636
637
        my $day = dt_from_string();
638
        my $dow = scalar $day->day_of_week;
639
        $dow = 0 if $dow == 7;
640
641
        # Closed this day of the week
642
        my $dbh = C4::Context->dbh;
643
        $dbh->do(
644
            q|
645
            INSERT INTO repeatable_holidays (branchcode,weekday,day,month,title,description)
646
            VALUES ( ?, ?, NULL, NULL, ?, '' )
647
        |, undef, $library->branchcode, $dow, "TEST"
648
        );
649
650
        # Iterate 7 days
651
        my $sth = $dbh->prepare("UPDATE repeatable_holidays SET weekday = ? WHERE branchcode = ? AND title = 'TEST'");
652
        for my $i ( 0 .. 6 ) {
653
            my $calendar = Koha::Calendar->new( branchcode => $library->branchcode );
654
655
            is( $calendar->is_holiday($day), 1, $day->day_name() . " works as a repeatable holiday" );
656
657
            # Increment the date and holiday day
658
            $day->add( days => 1 );
659
            $dow++;
660
            $dow = 0 if $dow == 7;
661
            $sth->execute( $dow, $library->branchcode );
662
        }
663
    };
664
};
665
666
subtest 'get_push_amt' => sub {
667
    plan tests => 1;
668
669
    t::lib::Mocks::mock_preference( 'useDaysMode', 'Dayweek' );
670
671
    subtest 'weekday holidays' => sub {
672
        plan tests => 7;
673
674
        my $library = $builder->build_object( { class => 'Koha::Libraries' } );
675
676
        my $day = dt_from_string();
677
        my $dow = scalar $day->day_of_week;
678
        $dow = 0 if $dow == 7;
679
680
        # Closed this day of the week
681
        my $dbh = C4::Context->dbh;
682
        $dbh->do(
683
            q|
684
            INSERT INTO repeatable_holidays (branchcode,weekday,day,month,title,description)
685
            VALUES ( ?, ?, NULL, NULL, ?, '' )
686
        |, undef, $library->branchcode, $dow, "TEST"
687
        );
688
689
        # Iterate 7 days
690
        my $sth = $dbh->prepare("UPDATE repeatable_holidays SET weekday = ? WHERE branchcode = ? AND title = 'TEST'");
691
        for my $i ( 0 .. 6 ) {
692
            my $calendar = Koha::Calendar->new( branchcode => $library->branchcode, days_mode => 'Dayweek' );
693
694
            my $npa;
695
            eval {
696
                local $SIG{ALRM} = sub { die "alarm\n" };    # NB: \n required
697
                alarm 2;
698
                $npa = $calendar->next_open_days( $day, 0 );
699
                alarm 0;
700
            };
701
            if ($@) {
702
                die unless $@ eq "alarm\n";                  # propagate unexpected errors
703
                                                             # timed out
704
                ok( 0, "next_push_amt succeeded for " . $day->day_name() . " weekday holiday" );
705
            } else {
706
                ok( $npa, "next_push_amt succeeded for " . $day->day_name() . " weekday holiday" );
707
            }
708
709
            # Increment the date and holiday day
710
            $day->add( days => 1 );
711
            $dow++;
712
            $dow = 0 if $dow == 7;
713
            $sth->execute( $dow, $library->branchcode );
714
        }
715
    };
716
};
717
718
$schema->storage->txn_rollback();
(-)a/t/db_dependent/Circulation.t (-36 / +57 lines)
Lines 33-39 use t::lib::Mocks; Link Here
33
use t::lib::TestBuilder;
33
use t::lib::TestBuilder;
34
34
35
use C4::Accounts;
35
use C4::Accounts;
36
use C4::Calendar qw( new insert_single_holiday insert_week_day_holiday delete_holiday );
37
use C4::Circulation
36
use C4::Circulation
38
    qw( AddIssue AddReturn CanBookBeRenewed GetIssuingCharges AddRenewal GetSoonestRenewDate GetLatestAutoRenewDate LostItem GetUpcomingDueIssues CanBookBeIssued AddIssuingCharge MarkIssueReturned ProcessOfflinePayment transferbook );
37
    qw( AddIssue AddReturn CanBookBeRenewed GetIssuingCharges AddRenewal GetSoonestRenewDate GetLatestAutoRenewDate LostItem GetUpcomingDueIssues CanBookBeIssued AddIssuingCharge MarkIssueReturned ProcessOfflinePayment transferbook );
39
use C4::Biblio;
38
use C4::Biblio;
Lines 58-63 use Koha::Account::Offsets; Link Here
58
use Koha::ActionLogs;
57
use Koha::ActionLogs;
59
use Koha::Notice::Messages;
58
use Koha::Notice::Messages;
60
use Koha::Cache::Memory::Lite;
59
use Koha::Cache::Memory::Lite;
60
use Koha::DiscreteCalendar;
61
61
62
my $builder = t::lib::TestBuilder->new;
62
my $builder = t::lib::TestBuilder->new;
63
63
Lines 120-127 my $mocked_datetime = Test::MockModule->new('DateTime'); Link Here
120
$mocked_datetime->mock( 'now', sub { return $now_value->clone; } );
120
$mocked_datetime->mock( 'now', sub { return $now_value->clone; } );
121
121
122
my $cache = Koha::Caches->get_instance();
122
my $cache = Koha::Caches->get_instance();
123
$dbh->do(q|DELETE FROM special_holidays|);
123
$dbh->do(q|DELETE FROM discrete_calendar|);
124
$dbh->do(q|DELETE FROM repeatable_holidays|);
125
my $branches = Koha::Libraries->search();
124
my $branches = Koha::Libraries->search();
126
for my $branch ( $branches->next ) {
125
for my $branch ( $branches->next ) {
127
    my $key = $branch->branchcode . "_holidays";
126
    my $key = $branch->branchcode . "_holidays";
Lines 3477-3491 subtest 'AddReturn + suspension_chargeperiod' => sub { Link Here
3477
    t::lib::Mocks::mock_preference( 'SuspensionsCalendar', 'noSuspensionsWhenClosed' );
3476
    t::lib::Mocks::mock_preference( 'SuspensionsCalendar', 'noSuspensionsWhenClosed' );
3478
3477
3479
    # Adding a holiday 2 days ago
3478
    # Adding a holiday 2 days ago
3480
    my $calendar     = C4::Calendar->new( branchcode => $library->{branchcode} );
3479
    my $calendar     = Koha::DiscreteCalendar->new({ branchcode => $library->{branchcode} });
3481
    my $two_days_ago = $now->clone->subtract( days => 2 );
3480
    my $two_days_ago = $now->clone->subtract( days => 2 );
3482
    $calendar->insert_single_holiday(
3481
    $calendar->edit_holiday({
3483
        day         => $two_days_ago->day,
3482
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
3484
        month       => $two_days_ago->month,
3483
        override     => 1,
3485
        year        => $two_days_ago->year,
3484
        start_date   => $two_days_ago,
3486
        title       => 'holidayTest-2d',
3485
        end_date     => $two_days_ago,
3487
        description => 'holidayDesc 2 days ago'
3486
        title        => 'holidayTest-2d',
3488
    );
3487
        description  => 'holidayDesc 2 days ago'
3488
    });
3489
3489
3490
    # With 5 days of overdue, only 4 (x finedays=2) days must charged (one was an holiday)
3490
    # With 5 days of overdue, only 4 (x finedays=2) days must charged (one was an holiday)
3491
    $expected_expiration = $now->clone->add( days => floor( ( ( 5 - 0 - 1 ) / 1 ) * 2 ) );
3491
    $expected_expiration = $now->clone->add( days => floor( ( ( 5 - 0 - 1 ) / 1 ) * 2 ) );
Lines 3501-3513 subtest 'AddReturn + suspension_chargeperiod' => sub { Link Here
3501
3501
3502
    # Adding a holiday 2 days ahead, with finesCalendar=noFinesWhenClosed it should be skipped
3502
    # Adding a holiday 2 days ahead, with finesCalendar=noFinesWhenClosed it should be skipped
3503
    my $two_days_ahead = $now->clone->add( days => 2 );
3503
    my $two_days_ahead = $now->clone->add( days => 2 );
3504
    $calendar->insert_single_holiday(
3504
    $calendar->edit_holiday({
3505
        day         => $two_days_ahead->day,
3505
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
3506
        month       => $two_days_ahead->month,
3506
        start_date   => $two_days_ahead,
3507
        year        => $two_days_ahead->year,
3507
        end_date     => $two_days_ahead,
3508
        title       => 'holidayTest+2d',
3508
        title        => 'holidayTest+2d',
3509
        description => 'holidayDesc 2 days ahead'
3509
        description  => 'holidayDesc 2 days ahead'
3510
    );
3510
    });
3511
3511
3512
    # Same as above, but we should skip D+2
3512
    # Same as above, but we should skip D+2
3513
    $expected_expiration = $now->clone->add( days => floor( ( ( 5 - 0 - 1 ) / 1 ) * 2 ) + 1 );
3513
    $expected_expiration = $now->clone->add( days => floor( ( ( 5 - 0 - 1 ) / 1 ) * 2 ) + 1 );
Lines 3523-3535 subtest 'AddReturn + suspension_chargeperiod' => sub { Link Here
3523
3523
3524
    # Adding another holiday, day of expiration date
3524
    # Adding another holiday, day of expiration date
3525
    my $expected_expiration_dt = dt_from_string($expected_expiration);
3525
    my $expected_expiration_dt = dt_from_string($expected_expiration);
3526
    $calendar->insert_single_holiday(
3526
    $calendar->edit_holiday({
3527
        day         => $expected_expiration_dt->day,
3527
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
3528
        month       => $expected_expiration_dt->month,
3528
        start_date   => $expected_expiration_dt,
3529
        year        => $expected_expiration_dt->year,
3529
        end_date     => $expected_expiration_dt,
3530
        title       => 'holidayTest_exp',
3530
        title        => 'holidayTest_exp',
3531
        description => 'holidayDesc on expiration date'
3531
        description  => 'holidayDesc on expiration date'
3532
    );
3532
    });
3533
3533
3534
    # Expiration date will be the day after
3534
    # Expiration date will be the day after
3535
    test_debarment_on_checkout(
3535
    test_debarment_on_checkout(
Lines 3611-3616 subtest 'AddReturn + suspension_chargeperiod' => sub { Link Here
3611
        $message->{WasReturned} && exists $message->{PrevDebarred}, 1,
3611
        $message->{WasReturned} && exists $message->{PrevDebarred}, 1,
3612
        'Previously debarred message for Addreturn when overdue'
3612
        'Previously debarred message for Addreturn when overdue'
3613
    );
3613
    );
3614
3615
    # delete holidays
3616
    $calendar->edit_holiday({
3617
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
3618
        start_date   => $two_days_ago,
3619
        end_date     => $expected_expiration_dt,
3620
        title        => '',
3621
        description  => ''
3622
    });
3614
};
3623
};
3615
3624
3616
subtest 'CanBookBeIssued + AutoReturnCheckedOutItems' => sub {
3625
subtest 'CanBookBeIssued + AutoReturnCheckedOutItems' => sub {
Lines 5772-5790 subtest 'Incremented fee tests' => sub { Link Here
5772
    $accountline->delete();
5781
    $accountline->delete();
5773
    $issue->delete();
5782
    $issue->delete();
5774
5783
5775
    my $calendar = C4::Calendar->new( branchcode => $library->id );
5784
    my $calendar = Koha::DiscreteCalendar->new({ branchcode => $library->id });
5776
5785
5777
    # DateTime 1..7 (Mon..Sun), C4::Calender 0..6 (Sun..Sat)
5786
    # DateTime 1..7 (Mon..Sun), Koha::DiscreteCalender 1..7 (Sun..Sat)
5778
    my $closed_day =
5787
    my $closed_day =
5779
          ( $dt_from->day_of_week == 6 ) ? 0
5788
        ( $dt_from->day_of_week == 7 ) ? 1
5780
        : ( $dt_from->day_of_week == 7 ) ? 1
5789
      : $dt_from->day_of_week + 1;
5781
        :                                  $dt_from->day_of_week + 1;
5782
    my $closed_day_name = $dt_from->clone->add( days => 1 )->day_name;
5790
    my $closed_day_name = $dt_from->clone->add( days => 1 )->day_name;
5783
    $calendar->insert_week_day_holiday(
5791
    $calendar->edit_holiday({
5784
        weekday     => $closed_day,
5792
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
5785
        title       => 'Test holiday',
5793
        weekday      => $closed_day,
5786
        description => 'Test holiday'
5794
        start_date   => $dt_from,
5787
    );
5795
        end_date     => $dt_from,
5796
        title        => 'Test holiday',
5797
        description  => 'Test holiday'
5798
    });
5788
    $issue       = AddIssue( $patron, $item->barcode, $dt_to, undef, $dt_from );
5799
    $issue       = AddIssue( $patron, $item->barcode, $dt_to, undef, $dt_from );
5789
    $accountline = Koha::Account::Lines->find( { itemnumber => $item->id } );
5800
    $accountline = Koha::Account::Lines->find( { itemnumber => $item->id } );
5790
    is(
5801
    is(
Lines 5904-5910 subtest 'Incremented fee tests' => sub { Link Here
5904
    $accountline->delete();
5915
    $accountline->delete();
5905
    $issue->delete();
5916
    $issue->delete();
5906
5917
5907
    $calendar->delete_holiday( weekday => $closed_day );
5918
    $calendar->edit_holiday({
5919
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
5920
        delete_type  => 1,
5921
        override     => 1,
5922
        weekday      => $closed_day,
5923
        start_date   => $dt_from,
5924
        end_date     => $dt_from,
5925
        title        => '',
5926
        description  => '',
5927
    });
5928
5908
    $issue       = AddIssue( $patron, $item->barcode, $dt_to, undef, $dt_from );
5929
    $issue       = AddIssue( $patron, $item->barcode, $dt_to, undef, $dt_from );
5909
    $accountline = Koha::Account::Lines->find( { itemnumber => $item->id } );
5930
    $accountline = Koha::Account::Lines->find( { itemnumber => $item->id } );
5910
    is(
5931
    is(
(-)a/t/db_dependent/Circulation/CalcDateDue.t (-114 / +167 lines)
Lines 9-15 use DBI; Link Here
9
use DateTime;
9
use DateTime;
10
use t::lib::Mocks;
10
use t::lib::Mocks;
11
use t::lib::TestBuilder;
11
use t::lib::TestBuilder;
12
use C4::Calendar    qw( new insert_single_holiday delete_holiday insert_week_day_holiday );
12
use Koha::DiscreteCalendar;
13
use Koha::DateUtils qw( dt_from_string );
13
use Koha::DateUtils qw( dt_from_string );
14
use Koha::Library::Hours;
14
use Koha::Library::Hours;
15
use Koha::CirculationRules;
15
use Koha::CirculationRules;
Lines 40-45 my $issuelength = 10; Link Here
40
my $renewalperiod = 5;
40
my $renewalperiod = 5;
41
my $lengthunit    = 'days';
41
my $lengthunit    = 'days';
42
42
43
$builder->fill_discrete_calendar({ branchcode => $library->branchcode, start_date => $dateexpiry, days => 365 });
44
43
Koha::CirculationRules->search()->delete();
45
Koha::CirculationRules->search()->delete();
44
Koha::CirculationRules->set_rules(
46
Koha::CirculationRules->set_rules(
45
    {
47
    {
Lines 79-101 is( $date, $dateexpiry . 'T23:59:00', 'date expiry with useDaysMode to noDays' ) Link Here
79
81
80
# Let's add a special holiday on 2013-01-01. With ReturnBeforeExpiry and
82
# Let's add a special holiday on 2013-01-01. With ReturnBeforeExpiry and
81
# useDaysMode different from 'Days', return should forward the dateexpiry.
83
# useDaysMode different from 'Days', return should forward the dateexpiry.
82
my $calendar = C4::Calendar->new( branchcode => $branchcode );
84
my $calendar = Koha::DiscreteCalendar->new({ branchcode => $branchcode });
83
$calendar->insert_single_holiday(
85
$calendar->edit_holiday({
84
    day         => 1,
86
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
85
    month       => 1,
87
    override     => 1,
86
    year        => 2013,
88
    start_date   => dt_from_string($dateexpiry, 'iso'),
87
    title       => 'holidayTest',
89
    end_date     => dt_from_string($dateexpiry, 'iso'),
88
    description => 'holidayDesc'
90
    title        => 'holidayTest',
89
);
91
    description  => 'holidayDesc'
92
});
90
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
93
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
91
is( $date, '2012-12-31T23:59:00', 'date expiry should be 2013-01-01 -1 day' );
94
is( $date, '2012-12-31T23:59:00', 'date expiry should be 2013-01-01 -1 day' );
92
$calendar->insert_single_holiday(
95
$calendar->edit_holiday({
93
    day         => 31,
96
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
94
    month       => 12,
97
    override     => 1,
95
    year        => 2012,
98
    start_date   => dt_from_string('2012-12-31', 'iso'),
96
    title       => 'holidayTest',
99
    end_date     => dt_from_string('2012-12-31', 'iso'),
97
    description => 'holidayDesc'
100
    title        => 'holidayTest',
98
);
101
    description  => 'holidayDesc'
102
});
99
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
103
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
100
is( $date, '2012-12-30T23:59:00', 'date expiry should be 2013-01-01 -2 day' );
104
is( $date, '2012-12-30T23:59:00', 'date expiry should be 2013-01-01 -2 day' );
101
105
Lines 137-149 is( Link Here
137
# Now let's add a closed day on the expected renewal date, it should
141
# Now let's add a closed day on the expected renewal date, it should
138
# roll forward as per Datedue (i.e. one day at a time)
142
# roll forward as per Datedue (i.e. one day at a time)
139
# For issues...
143
# For issues...
140
$calendar->insert_single_holiday(
144
my $issue_date = dt_from_string('2013-02-' . (9 + $issuelength), 'iso');
141
    day         => 9 + $issuelength,
145
$calendar->edit_holiday({
142
    month       => 2,
146
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
143
    year        => 2013,
147
    override     => 1,
144
    title       => 'DayweekTest1',
148
    start_date   => $issue_date,
145
    description => 'DayweekTest1'
149
    end_date     => $issue_date,
146
);
150
    title        => 'DayweekTest1',
151
    description  => 'DayweekTest1'
152
});
147
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
153
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower );
148
is(
154
is(
149
    $date, '2013-02-' . ( 9 + $issuelength + 1 ) . 'T23:59:00',
155
    $date, '2013-02-' . ( 9 + $issuelength + 1 ) . 'T23:59:00',
Lines 151-170 is( Link Here
151
);
157
);
152
158
153
# Remove the holiday we just created
159
# Remove the holiday we just created
154
$calendar->delete_holiday(
160
$calendar->edit_holiday({
155
    day   => 9 + $issuelength,
161
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
156
    month => 2,
162
    override     => 1,
157
    year  => 2013
163
    start_date   => $issue_date,
158
);
164
    end_date     => $issue_date,
165
    title        => '',
166
    description  => '',
167
});
159
168
160
# ...and for renewals...
169
# ...and for renewals...
161
$calendar->insert_single_holiday(
170
my $renewal_date = dt_from_string('2013-02-' . (9 + $renewalperiod), 'iso');
162
    day         => 9 + $renewalperiod,
171
$calendar->edit_holiday({
163
    month       => 2,
172
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
164
    year        => 2013,
173
    override     => 1,
165
    title       => 'DayweekTest2',
174
    start_date   => $renewal_date,
166
    description => 'DayweekTest2'
175
    end_date     => $renewal_date,
167
);
176
    title        => 'DayweekTest2',
177
    description  => 'DayweekTest2'
178
});
168
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
179
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $borrower, 1 );
169
is(
180
is(
170
    $date, '2013-02-' . ( 9 + $renewalperiod + 1 ) . 'T23:59:00',
181
    $date, '2013-02-' . ( 9 + $renewalperiod + 1 ) . 'T23:59:00',
Lines 172-182 is( Link Here
172
);
183
);
173
184
174
# Remove the holiday we just created
185
# Remove the holiday we just created
175
$calendar->delete_holiday(
186
$calendar->edit_holiday({
176
    day   => 9 + $renewalperiod,
187
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
177
    month => 2,
188
    override     => 1,
178
    year  => 2013,
189
    start_date   => $renewal_date,
179
);
190
    end_date     => $renewal_date,
191
    title        => '',
192
    description  => '',
193
});
180
194
181
# Now we test it does the right thing if the loan and renewal periods
195
# Now we test it does the right thing if the loan and renewal periods
182
# are a multiple of 7 days
196
# are a multiple of 7 days
Lines 212-224 my $dayweek_borrower = $builder->build_object( Link Here
212
226
213
# For issues...
227
# For issues...
214
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
228
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
215
$calendar->insert_single_holiday(
229
my $holiday_date = $start_date->clone();
216
    day         => 9 + $dayweek_issuelength,
230
$holiday_date->add(days => $dayweek_issuelength);
217
    month       => 2,
231
$calendar->edit_holiday({
218
    year        => 2013,
232
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
219
    title       => 'DayweekTest3',
233
    override     => 1,
220
    description => 'DayweekTest3'
234
    start_date   => $holiday_date,
221
);
235
    end_date     => $holiday_date,
236
    title        => 'DayweekTest3',
237
    description  => 'DayweekTest3'
238
});
222
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
239
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
223
my $issue_should_add       = $dayweek_issuelength + 7;
240
my $issue_should_add       = $dayweek_issuelength + 7;
224
my $dayweek_issue_expected = $start_date->add( days => $issue_should_add );
241
my $dayweek_issue_expected = $start_date->add( days => $issue_should_add );
Lines 228-248 is( Link Here
228
);
245
);
229
246
230
# Remove the holiday we just created
247
# Remove the holiday we just created
231
$calendar->delete_holiday(
248
$calendar->edit_holiday({
232
    day   => 9 + $dayweek_issuelength,
249
    holiday_type    => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
233
    month => 2,
250
    override        => 1,
234
    year  => 2013,
251
    start_date      => $holiday_date,
235
);
252
    end_date        => $holiday_date,
253
    title           => '',
254
    description     => '',
255
});
236
256
237
# ...and for renewals...
257
# ...and for renewals...
238
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
258
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
239
$calendar->insert_single_holiday(
259
$holiday_date = $start_date->clone();
240
    day         => 9 + $dayweek_renewalperiod,
260
$holiday_date->add(days => $dayweek_renewalperiod);
241
    month       => 2,
261
$calendar->edit_holiday({
242
    year        => 2013,
262
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
243
    title       => 'DayweekTest4',
263
    override     => 1,
244
    description => 'DayweekTest4'
264
    start_date   => $holiday_date,
245
);
265
    end_date     => $holiday_date,
266
    title        => 'DayweekTest4',
267
    description  => 'DayweekTest4'
268
});
246
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower, 1 );
269
$date = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower, 1 );
247
my $renewal_should_add       = $dayweek_renewalperiod + 7;
270
my $renewal_should_add       = $dayweek_renewalperiod + 7;
248
my $dayweek_renewal_expected = $start_date->add( days => $renewal_should_add );
271
my $dayweek_renewal_expected = $start_date->add( days => $renewal_should_add );
Lines 252-262 is( Link Here
252
);
275
);
253
276
254
# Remove the holiday we just created
277
# Remove the holiday we just created
255
$calendar->delete_holiday(
278
$calendar->edit_holiday({
256
    day   => 9 + $dayweek_renewalperiod,
279
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
257
    month => 2,
280
    override     => 1,
258
    year  => 2013,
281
    start_date   => $holiday_date,
259
);
282
    end_date     => $holiday_date,
283
    title        => '',
284
    description  => '',
285
});
260
286
261
# Now test it continues to roll forward by 7 days until it finds
287
# Now test it continues to roll forward by 7 days until it finds
262
# an open day, so we create a 3 week period of closed Saturdays
288
# an open day, so we create a 3 week period of closed Saturdays
Lines 264-293 $start_date = DateTime->new( { year => 2013, month => 2, day => 9 } ); Link Here
264
my $expected_rolled_date = DateTime->new( { year => 2013, month => 3, day => 9 } );
290
my $expected_rolled_date = DateTime->new( { year => 2013, month => 3, day => 9 } );
265
my $holiday = $start_date->clone();
291
my $holiday = $start_date->clone();
266
$holiday->add( days => 7 );
292
$holiday->add( days => 7 );
267
$calendar->insert_single_holiday(
293
$calendar->edit_holiday({
268
    day         => $holiday->day,
294
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
269
    month       => $holiday->month,
295
    override     => 1,
270
    year        => 2013,
296
    start_date   => $holiday,
271
    title       => 'DayweekTest5',
297
    end_date     => $holiday,
272
    description => 'DayweekTest5'
298
    title        => 'DayweekTest5',
273
);
299
    description  => 'DayweekTest5'
300
});
274
$holiday->add( days => 7 );
301
$holiday->add( days => 7 );
275
$calendar->insert_single_holiday(
302
$calendar->edit_holiday({
276
    day         => $holiday->day,
303
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
277
    month       => $holiday->month,
304
    override     => 1,
278
    year        => 2013,
305
    start_date   => $holiday,
279
    title       => 'DayweekTest6',
306
    end_date     => $holiday,
280
    description => 'DayweekTest6'
307
    title        => 'DayweekTest6',
281
);
308
    description  => 'DayweekTest6'
309
});
282
$holiday->add( days => 7 );
310
$holiday->add( days => 7 );
283
$calendar->insert_single_holiday(
311
$calendar->edit_holiday({
284
    day         => $holiday->day,
312
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
285
    month       => $holiday->month,
313
    override     => 1,
286
    year        => 2013,
314
    start_date   => $holiday,
287
    title       => 'DayweekTest7',
315
    end_date     => $holiday,
288
    description => 'DayweekTest7'
316
    title        => 'DayweekTest7',
289
);
317
    description  => 'DayweekTest7'
290
318
});
291
# For issues...
319
# For issues...
292
$date                   = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
320
$date                   = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
293
$dayweek_issue_expected = $start_date->add( days => $issue_should_add );
321
$dayweek_issue_expected = $start_date->add( days => $issue_should_add );
Lines 309-342 is( Link Here
309
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
337
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
310
my $del_holiday = $start_date->clone();
338
my $del_holiday = $start_date->clone();
311
$del_holiday->add( days => 7 );
339
$del_holiday->add( days => 7 );
312
$calendar->delete_holiday(
340
$calendar->edit_holiday({
313
    day   => $del_holiday->day,
341
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
314
    month => $del_holiday->month,
342
    override     => 1,
315
    year  => 2013
343
    start_date   => $del_holiday,
316
);
344
    end_date     => $del_holiday,
345
    title        => '',
346
    description  => '',
347
});
317
$del_holiday->add( days => 7 );
348
$del_holiday->add( days => 7 );
318
$calendar->delete_holiday(
349
$calendar->edit_holiday({
319
    day   => $del_holiday->day,
350
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
320
    month => $del_holiday->month,
351
    override     => 1,
321
    year  => 2013
352
    start_date   => $del_holiday,
322
);
353
    end_date     => $del_holiday,
354
    title        => '',
355
    description  => '',
356
});
323
$del_holiday->add( days => 7 );
357
$del_holiday->add( days => 7 );
324
$calendar->delete_holiday(
358
$calendar->edit_holiday({
325
    day   => $del_holiday->day,
359
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
326
    month => $del_holiday->month,
360
    override     => 1,
327
    year  => 2013
361
    start_date   => $del_holiday,
328
);
362
    end_date     => $del_holiday,
363
    title        => '',
364
    description  => '',
365
});
329
366
330
# Now test that useDaysMode "Dayweek" doesn't try to roll forward onto
367
# Now test that useDaysMode "Dayweek" doesn't try to roll forward onto
331
# a permanently closed day and instead rolls forward just one day
368
# a permanently closed day and instead rolls forward just one day
332
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
369
$start_date = DateTime->new( { year => 2013, month => 2, day => 9 } );
333
370
334
# Our tests are concerned with Saturdays, so let's close on Saturdays
371
# Our tests are concerned with Saturdays, so let's close on Saturdays
335
$calendar->insert_week_day_holiday(
372
$calendar->edit_holiday({
336
    weekday     => 6,
373
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
337
    title       => "Saturday closure",
374
    weekday      => 7,
338
    description => "Closed on Saturdays"
375
    override     => 1,
339
);
376
    start_date   => $start_date,
377
    end_date     => $start_date,
378
    title        => "Saturday closure",
379
    description  => "Closed on Saturdays"
380
});
340
381
341
# For issues...
382
# For issues...
342
$date                   = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
383
$date                   = C4::Circulation::CalcDateDue( $start_date, $itemtype, $branchcode, $dayweek_borrower );
Lines 356-362 is( Link Here
356
);
397
);
357
398
358
# Remove the holiday we just created
399
# Remove the holiday we just created
359
$calendar->delete_holiday( weekday => 6 );
400
$calendar->edit_holiday({
401
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
402
    weekday      => 7,
403
    override     => 1,
404
    delete_type  => 1,
405
    start_date   => $start_date,
406
    end_date     => $start_date,
407
    title        => '',
408
    description  => '',
409
});
360
410
361
# Renewal period of 0 is valid
411
# Renewal period of 0 is valid
362
Koha::CirculationRules->search()->delete();
412
Koha::CirculationRules->search()->delete();
Lines 415-420 my $open = DateTime->new( year => 2023, month => 5, day => 1, hour => 10 )->hms Link Here
415
my $close = DateTime->new( year => 2023, month => 5, day => 1, hour => 16 )->hms;
465
my $close = DateTime->new( year => 2023, month => 5, day => 1, hour => 16 )->hms;
416
my $now   = DateTime->new( year => 2023, month => 5, day => 1, hour => 14 );
466
my $now   = DateTime->new( year => 2023, month => 5, day => 1, hour => 14 );
417
467
468
$builder->fill_discrete_calendar({ branchcode => $library1->{branchcode}, start_date => $now });
469
418
foreach ( 0 .. 6 ) {
470
foreach ( 0 .. 6 ) {
419
471
420
    # library opened 4 hours ago and closes in 2 hours.
472
    # library opened 4 hours ago and closes in 2 hours.
Lines 449-462 is( Link Here
449
my $holiday_tomorrow = $now->clone->add( days => 1 );
501
my $holiday_tomorrow = $now->clone->add( days => 1 );
450
502
451
# consider calendar
503
# consider calendar
452
my $library1_calendar = C4::Calendar->new( branchcode => $library1->{branchcode} );
504
my $library1_calendar = Koha::DiscreteCalendar->new({ branchcode => $library1->{branchcode} });
453
$library1_calendar->insert_single_holiday(
505
$library1_calendar->edit_holiday({
454
    day         => $holiday_tomorrow->day,
506
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
455
    month       => $holiday_tomorrow->month,
507
    start_date  => $holiday_tomorrow,
456
    year        => $holiday_tomorrow->year,
508
    end_date    => $holiday_tomorrow,
457
    title       => 'testholiday',
509
    title       => 'testholiday',
458
    description => 'testholiday'
510
    description => 'testholiday',
459
);
511
    override    => 1,
512
});
460
Koha::CirculationRules->set_rules(
513
Koha::CirculationRules->set_rules(
461
    {
514
    {
462
        categorycode => $patron_category->categorycode,
515
        categorycode => $patron_category->categorycode,
(-)a/t/db_dependent/Circulation/CalcFine.t (+1 lines)
Lines 29-34 my $branch = $builder->build( Link Here
29
        source => 'Branch',
29
        source => 'Branch',
30
    }
30
    }
31
);
31
);
32
$builder->fill_discrete_calendar({ branchcode => $branch->{branchcode}, start_date => '2000-01-01' });
32
33
33
my $category = $builder->build(
34
my $category = $builder->build(
34
    {
35
    {
(-)a/t/db_dependent/Circulation/maxsuspensiondays.t (-5 / +10 lines)
Lines 21-26 $schema->storage->txn_begin; Link Here
21
my $builder = t::lib::TestBuilder->new;
21
my $builder = t::lib::TestBuilder->new;
22
my $dbh     = C4::Context->dbh;
22
my $dbh     = C4::Context->dbh;
23
23
24
# clear any holidays to avoid throwing off the suspension day
25
# calculations
26
$dbh->do('DELETE FROM discrete_calendar');
27
24
my $branchcode      = $builder->build( { source => 'Branch' } )->{branchcode};
28
my $branchcode      = $builder->build( { source => 'Branch' } )->{branchcode};
25
my $itemtype        = $builder->build( { source => 'Itemtype' } )->{itemtype};
29
my $itemtype        = $builder->build( { source => 'Itemtype' } )->{itemtype};
26
my $patron_category = $builder->build( { source => 'Category' } );
30
my $patron_category = $builder->build( { source => 'Category' } );
Lines 70-80 my $itemnumber = Koha::Item->new( Link Here
70
    }
74
    }
71
)->store->itemnumber;
75
)->store->itemnumber;
72
76
73
# clear any holidays to avoid throwing off the suspension day
74
# calculations
75
$dbh->do('DELETE FROM special_holidays');
76
$dbh->do('DELETE FROM repeatable_holidays');
77
78
my $daysago20   = dt_from_string->add_duration( DateTime::Duration->new( days => -20 ) );
77
my $daysago20   = dt_from_string->add_duration( DateTime::Duration->new( days => -20 ) );
79
my $daysafter40 = dt_from_string->add_duration( DateTime::Duration->new( days => 40 ) );
78
my $daysafter40 = dt_from_string->add_duration( DateTime::Duration->new( days => 40 ) );
80
79
Lines 131-136 subtest "suspension_chargeperiod" => sub { Link Here
131
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
130
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
132
    my $item   = $builder->build_sample_item;
131
    my $item   = $builder->build_sample_item;
133
132
133
    $builder->fill_discrete_calendar({ branchcode => $patron->{branchcode}, days => 365 });
134
    $builder->fill_discrete_calendar({ branchcode => $item->homebranch, days => 365 });
135
134
    my $last_year    = dt_from_string->clone->subtract( years => 1 );
136
    my $last_year    = dt_from_string->clone->subtract( years => 1 );
135
    my $today        = dt_from_string;
137
    my $today        = dt_from_string;
136
    my $new_debar_dt = C4::Circulation::_calculate_new_debar_dt( $patron, $item, $last_year, $today );
138
    my $new_debar_dt = C4::Circulation::_calculate_new_debar_dt( $patron, $item, $last_year, $today );
Lines 159-164 subtest "maxsuspensiondays" => sub { Link Here
159
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
161
    my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
160
    my $item   = $builder->build_sample_item;
162
    my $item   = $builder->build_sample_item;
161
163
164
    $builder->fill_discrete_calendar({ branchcode => $patron->{branchcode}, days => 365 });
165
    $builder->fill_discrete_calendar({ branchcode => $item->homebranch, days => 365 });
166
162
    my $last_year    = dt_from_string->clone->subtract( years => 1 );
167
    my $last_year    = dt_from_string->clone->subtract( years => 1 );
163
    my $today        = dt_from_string;
168
    my $today        = dt_from_string;
164
    my $new_debar_dt = C4::Circulation::_calculate_new_debar_dt( $patron, $item, $last_year, $today );
169
    my $new_debar_dt = C4::Circulation::_calculate_new_debar_dt( $patron, $item, $last_year, $today );
(-)a/t/db_dependent/DiscreteCalendar.t (+464 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2015 Koha Development team
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
use Test::More tests => 50;
22
use Test::MockModule;
23
24
use t::lib::TestBuilder;
25
26
use C4::Context;
27
use C4::Output;
28
use Koha::DateUtils qw ( dt_from_string );
29
use Koha::DiscreteCalendar;
30
31
32
my $module_context = Test::MockModule->new('C4::Context');
33
my $today = DateTime->today;
34
my $schema = Koha::Database->new->schema;
35
$schema->storage->txn_begin;
36
37
my $builder = t::lib::TestBuilder->new;
38
39
my $branch1 = $builder->build( { source => 'Branch' } )->{branchcode};
40
my $branch2 = $builder->build( { source => 'Branch' } )->{branchcode};
41
42
$builder->fill_discrete_calendar({ branchcode => $branch1, days => 365 });
43
44
$schema->resultset('DiscreteCalendar')->search({
45
    branchcode  => $branch1
46
})->update_all({
47
    is_opened    => 1,
48
    holiday_type => '',
49
    note         => '',
50
    open_hour    => '08:00:00',
51
    close_hour   => '16:00:00'
52
});
53
54
isnt($branch1,'', "First branch to do tests. BranchCode => $branch1");
55
isnt($branch2,'', "Second branch to do tests. BranchCode => $branch2");
56
57
#2 Calendars to make sure branches are treated separately.
58
my $calendar = Koha::DiscreteCalendar->new({branchcode => $branch1});
59
my $calendar2 = Koha::DiscreteCalendar->new({branchcode => $branch2});
60
61
my $unique_holiday = DateTime->today;
62
$calendar->edit_holiday({
63
    title => "Single holiday Today",
64
    holiday_type=> $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
65
    start_date=>$unique_holiday,
66
    end_date=>$unique_holiday
67
});
68
is($calendar->is_opened($unique_holiday), 0, "Branch closed today : $unique_holiday");
69
70
my @unique_holidays = $calendar->get_unique_holidays();
71
is(scalar @unique_holidays, 1, "Set of exception holidays at 1");
72
73
my $yesterday = DateTime->today->subtract(days => 1);
74
$calendar->edit_holiday({
75
    title => "Single holiday Today",
76
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
77
    start_date => $yesterday,
78
    end_date => $yesterday
79
});
80
is($calendar->is_opened($yesterday), 1, "Cannot edit dates in the past without override : $yesterday is not a holiday");
81
82
$calendar->edit_holiday({
83
    title => "Single holiday Today",
84
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
85
    start_date => $yesterday,
86
    end_date => $yesterday,
87
    override => 1
88
});
89
is($calendar->is_opened($yesterday), 0, "Can edit dates in the past without override : $yesterday is a holiday");
90
91
92
my $days_between_start = DateTime->today;
93
my $days_between_end = DateTime->today->add(days => 6);
94
my $days_between = $calendar->days_between($days_between_start, $days_between_end)->in_units('days');
95
is($days_between, 5, "Days between skips holiday");
96
97
my $repeatable_holiday = DateTime->today->add(days => 1);
98
$calendar->edit_holiday({
99
    title => "repeatable",
100
    holiday_type=> $Koha::DiscreteCalendar::HOLIDAYS->{REPEATABLE},
101
    start_date=>$repeatable_holiday,
102
    end_date=>$repeatable_holiday
103
});
104
is($calendar->is_opened($repeatable_holiday), 0, "Branch not opened on $repeatable_holiday");
105
106
my @repeatable_holidays = $calendar->get_repeatable_holidays();
107
is(scalar @repeatable_holidays, 1, "Set of repeatable holidays at 1");
108
109
# 1 being mysql DAYOFWEEK() for Sunday
110
$calendar->edit_holiday({
111
    title => "Weekly",
112
    weekday=>1,
113
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
114
    start_date=>$today,
115
    end_date=>$today
116
});
117
my @weekly_holidays = $calendar->get_week_days_holidays();
118
is(scalar @weekly_holidays, 1, "Set of weekly holidays at 1");
119
120
my $sunday = DateTime->today->add(days =>( 7 - $today->day_of_week));
121
is($calendar->is_opened($sunday), 0, "Branch not opened on " . $sunday->day_name ."s");
122
123
my $unique_holiday_range_start = DateTime->today->add(days => 2);
124
my $unique_holiday_range_end = DateTime->today->add(days => 7);
125
$calendar->edit_holiday({
126
    title => "Single holiday range",
127
    holiday_type=>"E",
128
    start_date=>$unique_holiday_range_start,
129
    end_date=>$unique_holiday_range_end
130
});
131
@unique_holidays = $calendar->get_unique_holidays();
132
is(scalar @unique_holidays, 7, "Set of exception holidays at 7");
133
134
my $repeatable_holiday_range_start = DateTime->today->add(days => 8);
135
my $repeatable_holiday_range_end = DateTime->today->add(days => 13);
136
$calendar->edit_holiday({
137
    title => "Repeatable holiday range",
138
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{REPEATABLE},
139
    start_date=>$repeatable_holiday_range_start,
140
    end_date=>$repeatable_holiday_range_end
141
});
142
@repeatable_holidays = $calendar->get_repeatable_holidays();
143
is(scalar @repeatable_holidays, 7, "Set of repeatable holidays at 7");
144
145
#Hourly loan
146
# ex :
147
# item due      : 2017-01-24 11:00:00
148
# item returned : 2017-01-26 10:00:00
149
# Branch closed : 2017-01-25
150
# Open/close hours : 08:00 to 16:00 (8h day)
151
# Hours due : 5 hours on 2017-01-24 + 2 hours on 2017-01-26 = 7hours
152
153
my $open_hours_since_start = dt_from_string->truncate(to => 'day')->add(days => 40, hours => 11);
154
my $open_hours_since_end = dt_from_string->truncate(to => 'day')->add(days => 42, hours => 10);
155
my $holiday_between =  dt_from_string->truncate(to => 'day')->add(days => 41);
156
$calendar->edit_holiday({
157
    title => '',
158
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
159
    start_date=>$open_hours_since_start,
160
    end_date=>$open_hours_since_end
161
});
162
163
$calendar->edit_holiday({
164
    title => "Single holiday",
165
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
166
    start_date=> $holiday_between,
167
    end_date=>$holiday_between
168
});
169
my $open_hours_between = $calendar->open_hours_between($open_hours_since_start, $open_hours_since_end);
170
is($open_hours_between, 7, "7 Hours open between $open_hours_since_start and $open_hours_since_end");
171
172
my $christmas = DateTime->new(
173
    year  => $today->year(),
174
    month => 12,
175
    day   => 25,
176
);
177
$calendar->edit_holiday({
178
    title => "Christmas",
179
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{REPEATABLE},
180
    start_date=>$christmas,
181
    end_date=>$christmas,
182
    override => 1, # necessary if unit tests are run between Christmas and the first of the year
183
});
184
is($calendar->is_opened($christmas), 0, "Branch closed on Christmas : $christmas");
185
186
my $newyear = DateTime->new(
187
    year  => $today->year() +1,
188
    month => 1,
189
    day   => 1,
190
);
191
192
$calendar->edit_holiday({
193
    title => "New Year",
194
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{REPEATABLE},
195
    start_date=>$newyear,
196
    end_date=>$newyear
197
});
198
is($calendar->is_opened($newyear), 0, "Branch closed on New Year : $newyear");
199
200
#Hours between :
201
my $date_due = DateTime->today->add(days => 1);
202
my $date_returned = DateTime->today->add(hours => 8);
203
my $hours_between = $calendar->hours_between($date_due, $date_returned);
204
205
is($hours_between->in_units('hours'), 16, "Date due $date_due, returned $date_returned, 16 hours in advance");
206
207
$date_due = DateTime->today->add(days => 1);
208
$date_returned = DateTime->today->add(days => 1, hours => 16);
209
$hours_between = $calendar->hours_between($date_due, $date_returned);
210
211
is($hours_between->in_units('hours'), 16, "Date due $date_due, returned $date_returned, 16 hours late");
212
213
214
#delete holidays
215
is($calendar->is_opened($today), 0, "Today is closed");
216
$calendar->edit_holiday({
217
    title => '',
218
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
219
    start_date=>$unique_holiday,
220
    end_date=>$unique_holiday
221
});
222
is($calendar->is_opened($today), 1, "Today's holiday was removed");
223
224
$calendar->edit_holiday({
225
    title => '',
226
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
227
    start_date => $yesterday,
228
    end_date => $yesterday,
229
    override => 1
230
});
231
is($calendar->is_opened($yesterday), 1, "Yesterdays's holiday was removed with override");
232
233
my $new_open_hours = '08:00';
234
$calendar->edit_holiday({
235
    title => '',
236
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
237
    open_hour=>$new_open_hours,
238
    close_hour=>'',
239
    start_date=>$today,
240
    end_date=>$today
241
});
242
is($calendar->get_date_info($today, $branch1)->{open_hour}, '08:00:00', "Open hour changed to 08:00:00");
243
244
isnt($calendar->get_date_info($today, $branch1)->{close_hour}, '', "Close hour not removed");
245
246
my $delete_range_end = DateTime->today->add(days => 30);
247
$calendar->edit_holiday({
248
    title => '',
249
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
250
    start_date=>$today,
251
    end_date=>$delete_range_end
252
});
253
254
255
is($calendar->is_opened($today), 1, "Today's holiday was already removed");
256
is($calendar->is_opened(DateTime->today->add(days => 1)), 1, "Tomorrow's holiday was removed");
257
is($calendar->is_opened($delete_range_end), 1, "End of range holiday was removed");
258
259
#Check if other branch was affected
260
my @unique_holidays_branch2 = $calendar2->get_unique_holidays();
261
is(scalar @unique_holidays_branch2, 0, "Set of exception holidays at 0 for branch => $branch2");
262
my @repeatable_holidays_branch2 = $calendar2->get_repeatable_holidays();
263
is(scalar @repeatable_holidays_branch2, 0, "Set of repeatable holidays at 0 for branch => $branch2");
264
my @weekly_holidays_branch2 = $calendar2->get_week_days_holidays();
265
is(scalar @weekly_holidays_branch2, 0, "Set of weekly holidays at 0 for branch => $branch2");
266
267
268
#Tests for addDate()
269
270
my $one_day_dur = DateTime::Duration->new( days => 1 );
271
my $negative_one_day_dur = DateTime::Duration->new( days => - 1 );
272
my $two_day_dur = DateTime::Duration->new( days => 2 );
273
my $seven_day_dur = DateTime::Duration->new( days => 7 );
274
275
#Preference useDaysMode Calendar
276
$calendar->{days_mode} = 'Calendar';
277
$unique_holiday->add(days => 1);
278
my $tomorrow = DateTime->today->add(days => 1);
279
$calendar->edit_holiday({
280
    title => "Single holiday Today",
281
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
282
    start_date=>$tomorrow,
283
    end_date=>$tomorrow
284
});
285
286
is($calendar->addDuration( $today, $one_day_dur, 'days' )->ymd(),
287
    $today->add(days => 2)->ymd(),
288
    'Single day add (Calendar)' );
289
290
is($calendar->addDuration( $today, $two_day_dur, 'days' )->ymd(),
291
    $today->add(days => 2)->ymd(),
292
    'Two days add, skips holiday (Calendar)' );
293
294
cmp_ok($calendar->addDuration( $today, $seven_day_dur, 'days' )->ymd(), 'eq',
295
    $today->add(days => 7)->ymd(),
296
    'Add 7 days (Calendar)' );
297
#Closed Sunday
298
$calendar->edit_holiday({
299
    title => "Weekly",
300
    weekday=>1,
301
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
302
    start_date=>$today,
303
    end_date=>$today
304
});
305
is( $calendar->addDuration( $sunday, $one_day_dur, 'days' )->day_of_week, 1,
306
    'addDate skips closed Sunday (Calendar)' );
307
#to remove the closed sundays
308
$today = DateTime->today;
309
$calendar->edit_holiday({
310
    title => '',
311
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
312
    start_date=>$today,
313
    end_date=>$delete_range_end
314
});
315
316
is( $calendar->addDuration($today, $negative_one_day_dur , 'days')->ymd(),
317
    $today->add(days => - 1)->ymd(),
318
    'Negative call to addDate (Calendar)' );
319
320
#Preference useDaysMode DateDue
321
$calendar->{days_mode} = 'Datedue';
322
#clean everything
323
$today = DateTime->today;
324
$calendar->edit_holiday({
325
    title => '',
326
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
327
    start_date=>$today,
328
    end_date=>$delete_range_end
329
});
330
$calendar->edit_holiday({
331
    title => "Single holiday Today",
332
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
333
    start_date=>$tomorrow,
334
    end_date=>$tomorrow
335
});
336
337
is($calendar->addDuration( $today, $one_day_dur, 'days' )->ymd(),
338
    $today->add(days => 2)->ymd(),
339
    'Single day add' );
340
341
is($calendar->addDuration( $today, $two_day_dur, 'days' )->ymd(),
342
    $today->add(days => 2)->ymd(),
343
    'Two days add, skips holiday (Datedue)' );
344
345
cmp_ok($calendar->addDuration( $today, $seven_day_dur, 'days' )->ymd(), 'eq',
346
    $today->add(days => 7)->ymd(),
347
    'Add 7 days (Datedue)' );
348
#Closed Sunday
349
$calendar->edit_holiday({
350
    title => "Weekly",
351
    weekday=>1,
352
    holiday_type=> $Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
353
    start_date=>$today,
354
    end_date=>$today
355
});
356
is( $calendar->addDuration( $sunday, $one_day_dur, 'days' )->day_of_week, 1,
357
    'addDate skips closed Sunday (Datedue)' );
358
#to remove the closed sundays
359
$today = DateTime->today;
360
$calendar->edit_holiday({
361
    title => '',
362
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
363
    start_date=>$today,
364
    end_date=>$delete_range_end
365
});
366
367
is( $calendar->addDuration($today, $negative_one_day_dur , 'days')->ymd(),
368
    $today->add(days => - 1)->ymd(),
369
    'Negative call to addDate (Datedue)' );
370
371
#Preference useDaysMode Days
372
$calendar->{days_mode} = 'Days';
373
#clean everything
374
$today = DateTime->today;
375
$calendar->edit_holiday({
376
    title => '',
377
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{NONE},
378
    start_date=>$today,
379
    end_date=>$delete_range_end
380
});
381
$calendar->edit_holiday({
382
    title => "Single holiday Today",
383
    holiday_type=>$Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
384
    start_date=>$tomorrow,
385
    end_date=>$tomorrow
386
});
387
is($calendar->addDuration( $today, $one_day_dur, 'days' )->ymd(),
388
    $today->add(days => 1)->ymd(),
389
    'Single day add' );
390
391
is($calendar->addDuration( $today, $two_day_dur, 'days' )->ymd(),
392
    $today->add(days => 2)->ymd(),
393
    'Two days add, skips holiday (Days)' );
394
395
cmp_ok($calendar->addDuration( $today, $seven_day_dur, 'days' )->ymd(), 'eq',
396
    $today->add(days => 7)->ymd(),
397
    'Add 7 days (Days)' );
398
#Closed Sunday
399
$calendar->edit_holiday({
400
    title => "Weekly",
401
    weekday => 1,
402
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
403
    start_date => $today,
404
    end_date => $today
405
});
406
is( $calendar->addDuration( $sunday, $one_day_dur, 'days' )->day_of_week, 1,
407
    'addDate skips closed Sunday (Days)' );
408
409
is( $calendar->addDuration($today, $negative_one_day_dur , 'days')->ymd(),
410
    $today->add(days => - 1)->ymd(),
411
    'Negative call to addDate (Days)' );
412
413
#Days_forward
414
415
#clean the range
416
$today = DateTime->today;
417
$calendar->edit_holiday({
418
    title => '',
419
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
420
    start_date => $today,
421
    end_date => DateTime->today->add(days => 20)
422
});
423
my $forwarded_dt = $calendar->days_forward($today, 10);
424
425
my $expected = $today->clone;
426
$expected->add(days => 10);
427
is($forwarded_dt->ymd, $expected->ymd, 'With no holiday on the perioddays_forward should add 10 days');
428
429
#Added a holiday
430
$unique_holiday = DateTime->today->add(days => 15);
431
$calendar->edit_holiday({
432
    title => "Single holiday Today",
433
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
434
    start_date => $unique_holiday,
435
    end_date => $unique_holiday
436
});
437
$forwarded_dt = $calendar->days_forward($today, 20);
438
439
$expected->add(days => 11);
440
is($forwarded_dt->ymd, $expected->ymd, 'With holiday on the perioddays_forward should add 20 days + 1 day for holiday');
441
442
$forwarded_dt = $calendar->days_forward($today, 0);
443
is($forwarded_dt->ymd, $today->ymd, '0 day should return start dt');
444
445
$forwarded_dt = $calendar->days_forward($today, -2);
446
is($forwarded_dt->ymd, $today->ymd, 'negative day should return start dt');
447
448
#copying a branch to an other
449
is($calendar2->is_opened($tomorrow), 1, "$branch2 opened tomorrow");
450
#Added a goliday tomorrow for branch1
451
$calendar->edit_holiday({
452
    title => "Single holiday Today",
453
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
454
    start_date => $tomorrow,
455
    end_date => $tomorrow
456
});
457
#Copy dates from branch1 to branch2
458
$calendar->copy_to_branch($branch2);
459
#Check if branch2 is also closed tomorrow after copying from branch1
460
is($calendar2->is_opened($tomorrow), 0, "$branch2 close tomorrow after copying from $branch1");
461
462
$schema->storage->txn_rollback;
463
464
1;
(-)a/t/db_dependent/Fines.t (+6 lines)
Lines 10-15 use Koha::DateUtils qw( dt_from_string ); Link Here
10
use Test::NoWarnings;
10
use Test::NoWarnings;
11
use Test::More tests => 6;
11
use Test::More tests => 6;
12
12
13
use t::lib::TestBuilder;
14
13
my $schema = Koha::Database->new->schema;
15
my $schema = Koha::Database->new->schema;
14
$schema->storage->txn_begin;
16
$schema->storage->txn_begin;
15
my $dbh = C4::Context->dbh;
17
my $dbh = C4::Context->dbh;
Lines 32-37 my $issuingrule = Koha::CirculationRules->set_rules( Link Here
32
    }
34
    }
33
);
35
);
34
36
37
my $builder = t::lib::TestBuilder->new();
38
$builder->fill_discrete_calendar({ branchcode => '' });
39
$builder->fill_discrete_calendar({ branchcode => '', start_date => '2000-01-01' });
40
35
ok( $issuingrule, 'Issuing rule created' );
41
ok( $issuingrule, 'Issuing rule created' );
36
42
37
my $period_start = dt_from_string('2000-01-01');
43
my $period_start = dt_from_string('2000-01-01');
(-)a/t/db_dependent/Hold.t (-4 / +18 lines)
Lines 22-28 use C4::Context; Link Here
22
use C4::Biblio qw( AddBiblio );
22
use C4::Biblio qw( AddBiblio );
23
use Koha::Database;
23
use Koha::Database;
24
use Koha::Libraries;
24
use Koha::Libraries;
25
use C4::Calendar qw( new insert_single_holiday );
25
use Koha::DiscreteCalendar;
26
use Koha::Patrons;
26
use Koha::Patrons;
27
use Koha::Holds;
27
use Koha::Holds;
28
use Koha::Item;
28
use Koha::Item;
Lines 78-86 my $hold = Koha::Hold->new( Link Here
78
);
78
);
79
$hold->store();
79
$hold->store();
80
80
81
my $b1_cal = C4::Calendar->new( branchcode => $branches[1]->{branchcode} );
81
$builder->fill_discrete_calendar({
82
$b1_cal->insert_single_holiday( day => 2, month => 1, year => 2017, title => "Morty Day", description => "Rick" )
82
    branchcode => $branches[1]->{branchcode},
83
    ;    #Add a holiday
83
    start_date => '2017-01-01',
84
    days => dt_from_string->delta_days( dt_from_string( '2017-01-01' ) )->in_units( 'days'),
85
});
86
my $b1_cal = Koha::DiscreteCalendar->new({ branchcode => $branches[1]->{branchcode} });
87
88
my $holiday = dt_from_string('2017-01-02', 'iso');
89
$b1_cal->edit_holiday({
90
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
91
    override     => 1,
92
    start_date   => $holiday,
93
    end_date     => $holiday,
94
    title        => "Morty Day",
95
    description  => "Rick"
96
});     #Add a holiday
97
84
my $today = dt_from_string;
98
my $today = dt_from_string;
85
is(
99
is(
86
    $hold->age(), $today->delta_days( dt_from_string('2017-01-01') )->in_units('days'),
100
    $hold->age(), $today->delta_days( dt_from_string('2017-01-01') )->in_units('days'),
(-)a/t/db_dependent/Holds.t (-1 lines)
Lines 13-19 use Test::Exception; Link Here
13
use MARC::Record;
13
use MARC::Record;
14
14
15
use C4::Biblio;
15
use C4::Biblio;
16
use C4::Calendar;
17
use C4::Items;
16
use C4::Items;
18
use C4::Reserves
17
use C4::Reserves
19
    qw( AddReserve CalculatePriority ModReserve AutoUnsuspendReserves SuspendAll ModReserveMinusPriority AlterPriority CanItemBeReserved CheckReserves MoveReserve );
18
    qw( AddReserve CalculatePriority ModReserve AutoUnsuspendReserves SuspendAll ModReserveMinusPriority AlterPriority CanItemBeReserved CheckReserves MoveReserve );
(-)a/t/db_dependent/Holds/WaitingReserves.t (-28 / +16 lines)
Lines 17-24 my $schema = Koha::Database->new->schema; Link Here
17
$schema->storage->txn_begin;
17
$schema->storage->txn_begin;
18
18
19
my $dbh = C4::Context->dbh;
19
my $dbh = C4::Context->dbh;
20
$dbh->do(q{DELETE FROM special_holidays});
20
$dbh->do(q{DELETE FROM discrete_calendar});
21
$dbh->do(q{DELETE FROM repeatable_holidays});
22
$dbh->do("DELETE FROM reserves");
21
$dbh->do("DELETE FROM reserves");
23
22
24
my $builder = t::lib::TestBuilder->new();
23
my $builder = t::lib::TestBuilder->new();
Lines 41-46 $builder->build( Link Here
41
    }
40
    }
42
);
41
);
43
42
43
$builder->fill_discrete_calendar({ branchcode => 'LIB1' });
44
my $calendar = Koha::DiscreteCalendar->new({ branchcode => 'LIB1' });
45
44
$builder->build(
46
$builder->build(
45
    {
47
    {
46
        source => 'Branch',
48
        source => 'Branch',
Lines 170-205 my $reserve3 = $builder->build( Link Here
170
my $special_holiday1_dt = $today->clone;
172
my $special_holiday1_dt = $today->clone;
171
$special_holiday1_dt->add( days => 2 );
173
$special_holiday1_dt->add( days => 2 );
172
174
173
my $holiday = $builder->build(
175
$calendar->edit_holiday({
174
    {
176
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
175
        source => 'SpecialHoliday',
177
    start_date   => $special_holiday1_dt,
176
        value  => {
178
    end_date     => $special_holiday1_dt,
177
            branchcode  => 'LIB1',
179
    title        => 'My special holiday',
178
            day         => $special_holiday1_dt->day,
180
});
179
            month       => $special_holiday1_dt->month,
180
            year        => $special_holiday1_dt->year,
181
            title       => 'My special holiday',
182
            isexception => 0
183
        },
184
    }
185
);
186
181
187
my $special_holiday2_dt = $today->clone;
182
my $special_holiday2_dt = $today->clone;
188
$special_holiday2_dt->add( days => 4 );
183
$special_holiday2_dt->add( days => 4 );
189
184
190
my $holiday2 = $builder->build(
185
$calendar->edit_holiday({
191
    {
186
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
192
        source => 'SpecialHoliday',
187
    start_date   => $special_holiday2_dt,
193
        value  => {
188
    end_date     => $special_holiday2_dt,
194
            branchcode  => 'LIB1',
189
    title        => 'My special holiday 2',
195
            day         => $special_holiday2_dt->day,
190
});
196
            month       => $special_holiday2_dt->month,
197
            year        => $special_holiday2_dt->year,
198
            title       => 'My special holiday 2',
199
            isexception => 0
200
        },
201
    }
202
);
203
191
204
Koha::Caches->get_instance->flush_all;
192
Koha::Caches->get_instance->flush_all;
205
193
(-)a/t/db_dependent/HoldsQueue.t (-9 / +10 lines)
Lines 12-18 use Test::NoWarnings; Link Here
12
use Test::More tests => 65;
12
use Test::More tests => 65;
13
use Data::Dumper;
13
use Data::Dumper;
14
14
15
use C4::Calendar qw( new insert_single_holiday );
15
use Koha::DiscreteCalendar;
16
use C4::Context;
16
use C4::Context;
17
use C4::Members;
17
use C4::Members;
18
use C4::Circulation qw( AddIssue AddReturn );
18
use C4::Circulation qw( AddIssue AddReturn );
Lines 392-409 is( Link Here
392
# have 1 row in the holds queue
392
# have 1 row in the holds queue
393
t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 1 );
393
t::lib::Mocks::mock_preference( 'HoldsQueueSkipClosed', 1 );
394
my $today = dt_from_string();
394
my $today = dt_from_string();
395
C4::Calendar->new( branchcode => $branchcodes[0] )->insert_single_holiday(
395
my $calendar = Koha::DiscreteCalendar->new({ branchcode => $branchcodes[0] });
396
    day         => $today->day(),
396
$calendar->edit_holiday({
397
    month       => $today->month(),
397
    holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
398
    year        => $today->year(),
398
    start_date   => $today,
399
    title       => "$today",
399
    end_date     => $today,
400
    description => "$today",
400
    title        => "$today",
401
);
401
    description  => "$today",
402
});
402
403
403
# If the test below is removed, aother tests using the holiday will fail. For some reason if we call is_holiday now
404
# If the test below is removed, aother tests using the holiday will fail. For some reason if we call is_holiday now
404
# the holiday will get set in cache correctly, but not if we let C4::HoldsQueue call is_holiday instead.
405
# the holiday will get set in cache correctly, but not if we let C4::HoldsQueue call is_holiday instead.
405
is(
406
is(
406
    Koha::Calendar->new( branchcode => $branchcodes[0] )->is_holiday($today), 1,
407
    $calendar->is_holiday($today), 1,
407
    'Is today a holiday for pickup branch'
408
    'Is today a holiday for pickup branch'
408
);
409
);
409
C4::HoldsQueue::CreateQueue();
410
C4::HoldsQueue::CreateQueue();
(-)a/t/db_dependent/Holidays.t (-354 lines)
Lines 1-354 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::NoWarnings;
21
use Test::More tests => 15;
22
use Test::Exception;
23
24
use DateTime;
25
use DateTime::TimeZone;
26
27
use t::lib::TestBuilder;
28
use C4::Context;
29
use Koha::Database;
30
use Koha::DateUtils qw( dt_from_string );
31
32
BEGIN {
33
    use_ok('Koha::Calendar');
34
    use_ok(
35
        'C4::Calendar',
36
        qw( insert_exception_holiday insert_week_day_holiday insert_day_month_holiday insert_single_holiday copy_to_branch get_exception_holidays isHoliday )
37
    );
38
}
39
40
my $schema  = Koha::Database->new->schema;
41
my $dbh     = C4::Context->dbh;
42
my $builder = t::lib::TestBuilder->new;
43
44
subtest 'is_holiday timezone tests' => sub {
45
46
    plan tests => 1;
47
48
    $schema->storage->txn_begin;
49
50
    $dbh->do("DELETE FROM special_holidays");
51
52
    # Clear cache
53
    Koha::Caches->get_instance->flush_all;
54
55
    # Artificially set timezone
56
    my $timezone = 'America/Santiago';
57
    $ENV{TZ} = $timezone;
58
    use POSIX qw(tzset);
59
    tzset;
60
61
    my $branch   = $builder->build( { source => 'Branch' } )->{branchcode};
62
    my $calendar = Koha::Calendar->new( branchcode => $branch );
63
64
    C4::Calendar->new( branchcode => $branch )->insert_exception_holiday(
65
        day         => 6,
66
        month       => 9,
67
        year        => 2015,
68
        title       => 'Invalid date',
69
        description => 'Invalid date description',
70
    );
71
72
    my $exception_holiday = DateTime->new( day => 6, month => 9, year => 2015 );
73
    my $now_dt            = DateTime->now;
74
75
    my $diff;
76
    eval { $diff = $calendar->days_between( $now_dt, $exception_holiday ) };
77
    unlike(
78
        $@,
79
        qr/Invalid local time for date in time zone: America\/Santiago/,
80
        'Avoid invalid datetime due to DST'
81
    );
82
83
    $schema->storage->txn_rollback;
84
};
85
86
$schema->storage->txn_begin;
87
88
# Create two fresh branches for the tests
89
my $branch_1 = $builder->build( { source => 'Branch' } )->{branchcode};
90
my $branch_2 = $builder->build( { source => 'Branch' } )->{branchcode};
91
92
C4::Calendar->new( branchcode => $branch_1 )->insert_week_day_holiday(
93
    weekday     => 0,
94
    title       => '',
95
    description => 'Sundays',
96
);
97
98
my $holiday2add = dt_from_string("2015-01-01");
99
C4::Calendar->new( branchcode => $branch_1 )->insert_day_month_holiday(
100
    day         => $holiday2add->day(),
101
    month       => $holiday2add->month(),
102
    year        => $holiday2add->year(),
103
    title       => '',
104
    description => "New Year's Day",
105
);
106
$holiday2add = dt_from_string("2014-12-25");
107
C4::Calendar->new( branchcode => $branch_1 )->insert_day_month_holiday(
108
    day         => $holiday2add->day(),
109
    month       => $holiday2add->month(),
110
    year        => $holiday2add->year(),
111
    title       => '',
112
    description => 'Christmas',
113
);
114
115
my $koha_calendar = Koha::Calendar->new( branchcode => $branch_1 );
116
my $c4_calendar   = C4::Calendar->new( branchcode => $branch_1 );
117
118
isa_ok( $koha_calendar, 'Koha::Calendar', 'Koha::Calendar class returned' );
119
isa_ok( $c4_calendar,   'C4::Calendar',   'C4::Calendar class returned' );
120
121
my $sunday = DateTime->new(
122
    year  => 2011,
123
    month => 6,
124
    day   => 26,
125
);
126
my $monday = DateTime->new(
127
    year  => 2011,
128
    month => 6,
129
    day   => 27,
130
);
131
my $christmas = DateTime->new(
132
    year  => 2032,
133
    month => 12,
134
    day   => 25,
135
);
136
my $newyear = DateTime->new(
137
    year  => 2035,
138
    month => 1,
139
    day   => 1,
140
);
141
142
is( $koha_calendar->is_holiday($sunday),    1, 'Sunday is a closed day' );
143
is( $koha_calendar->is_holiday($monday),    0, 'Monday is not a closed day' );
144
is( $koha_calendar->is_holiday($christmas), 1, 'Christmas is a closed day' );
145
is( $koha_calendar->is_holiday($newyear),   1, 'New Years day is a closed day' );
146
147
$dbh->do("DELETE FROM repeatable_holidays");
148
$dbh->do("DELETE FROM special_holidays");
149
150
my $custom_holiday = DateTime->new(
151
    year  => 2013,
152
    month => 11,
153
    day   => 12,
154
);
155
156
my $today = dt_from_string();
157
C4::Calendar->new( branchcode => $branch_2 )->insert_single_holiday(
158
    day         => $today->day(),
159
    month       => $today->month(),
160
    year        => $today->year(),
161
    title       => "$today",
162
    description => "$today",
163
);
164
165
is( Koha::Calendar->new( branchcode => $branch_2 )->is_holiday($today), 1, "Today is a holiday for $branch_2" );
166
is( Koha::Calendar->new( branchcode => $branch_1 )->is_holiday($today), 0, "Today is not a holiday for $branch_1" );
167
168
$schema->storage->txn_rollback;
169
170
subtest 'copy_to_branch' => sub {
171
172
    plan tests => 8;
173
174
    $schema->storage->txn_begin;
175
176
    my $branch1   = $builder->build( { source => 'Branch' } )->{branchcode};
177
    my $calendar1 = C4::Calendar->new( branchcode => $branch1 );
178
    my $sunday    = dt_from_string("2020-03-15");
179
    $calendar1->insert_week_day_holiday(
180
        weekday     => 0,
181
        title       => '',
182
        description => 'Sundays',
183
    );
184
185
    my $day_month = dt_from_string("2020-03-17");
186
    $calendar1->insert_day_month_holiday(
187
        day         => $day_month->day(),
188
        month       => $day_month->month(),
189
        year        => $day_month->year(),
190
        title       => '',
191
        description => "",
192
    );
193
194
    my $future_date = dt_from_string("9999-12-31");
195
    $calendar1->insert_single_holiday(
196
        day         => $future_date->day(),
197
        month       => $future_date->month(),
198
        year        => $future_date->year(),
199
        title       => "",
200
        description => "",
201
    );
202
203
    my $future_exception = dt_from_string("9999-12-30");
204
    $calendar1->insert_exception_holiday(
205
        day         => $future_exception->day(),
206
        month       => $future_exception->month(),
207
        year        => $future_exception->year(),
208
        title       => "",
209
        description => "",
210
    );
211
212
    my $past_date = dt_from_string("2019-11-20");
213
    $calendar1->insert_single_holiday(
214
        day         => $past_date->day(),
215
        month       => $past_date->month(),
216
        year        => $past_date->year(),
217
        title       => "",
218
        description => "",
219
    );
220
221
    my $past_exception = dt_from_string("2020-03-09");
222
    $calendar1->insert_exception_holiday(
223
        day         => $past_exception->day(),
224
        month       => $past_exception->month(),
225
        year        => $past_exception->year(),
226
        title       => "",
227
        description => "",
228
    );
229
230
    my $branch2 = $builder->build( { source => 'Branch' } )->{branchcode};
231
232
    C4::Calendar->new( branchcode => $branch1 )->copy_to_branch($branch2);
233
234
    my $calendar2  = C4::Calendar->new( branchcode => $branch2 );
235
    my $exceptions = $calendar2->get_exception_holidays;
236
237
    is( $calendar2->isHoliday( $sunday->day, $sunday->month, $sunday->year ), 1, "Weekday holiday copied to branch 2" );
238
    is(
239
        $calendar2->isHoliday( $day_month->day, $day_month->month, $day_month->year ), 1,
240
        "Day/month holiday copied to branch 2"
241
    );
242
    is(
243
        $calendar2->isHoliday( $future_date->day, $future_date->month, $future_date->year ), 1,
244
        "Single holiday copied to branch 2"
245
    );
246
    is( ( grep { $_->{date} eq "9999-12-30" } values %$exceptions ), 1, "Exception holiday copied to branch 2" );
247
    is(
248
        $calendar2->isHoliday( $past_date->day, $past_date->month, $past_date->year ), 0,
249
        "Don't copy past single holidays"
250
    );
251
    is( ( grep { $_->{date} eq "2020-03-09" } values %$exceptions ), 0, "Don't copy past exception holidays " );
252
253
    C4::Calendar->new( branchcode => $branch1 )->copy_to_branch($branch2);
254
255
    #Select all rows with same values from database
256
    my $dbh                     = C4::Context->dbh;
257
    my $get_repeatable_holidays = "SELECT a.* FROM repeatable_holidays a
258
        JOIN (SELECT branchcode, weekday, day, month, COUNT(*)
259
        FROM repeatable_holidays
260
        GROUP BY branchcode, weekday, day, month HAVING count(*) > 1) b
261
        ON a.branchcode = b.branchcode
262
        AND ( a.weekday = b.weekday OR (a.day = b.day AND a.month = b.month))
263
        ORDER BY a.branchcode;";
264
    my $sth = $dbh->prepare($get_repeatable_holidays);
265
    $sth->execute;
266
267
    my @repeatable_holidays;
268
    while ( my $row = $sth->fetchrow_hashref ) {
269
        push @repeatable_holidays, $row;
270
    }
271
272
    is( scalar(@repeatable_holidays), 0, "None of the repeatable holidays were doubled" );
273
274
    my $get_special_holidays = "SELECT a.* FROM special_holidays a
275
    JOIN (SELECT branchcode, day, month, year, isexception, COUNT(*)
276
    FROM special_holidays
277
    GROUP BY branchcode, day, month, year, isexception HAVING count(*) > 1) b
278
    ON a.branchcode = b.branchcode
279
    AND a.day = b.day AND a.month = b.month AND a.year = b.year AND a.isexception = b.isexception
280
    ORDER BY a.branchcode;";
281
    $sth = $dbh->prepare($get_special_holidays);
282
    $sth->execute;
283
284
    my @special_holidays;
285
    while ( my $row = $sth->fetchrow_hashref ) {
286
        push @special_holidays, $row;
287
    }
288
289
    is( scalar(@special_holidays), 0, "None of the special holidays were doubled" );
290
291
    $schema->storage->txn_rollback;
292
293
};
294
295
subtest 'with a library that is never open' => sub {
296
    plan tests => 2;
297
298
    $schema->storage->txn_begin;
299
300
    my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
301
    my $calendar   = C4::Calendar->new( branchcode => $branchcode );
302
    foreach my $weekday ( 0 .. 6 ) {
303
        $calendar->insert_week_day_holiday( weekday => $weekday, title => '', description => '' );
304
    }
305
306
    my $now = dt_from_string;
307
308
    subtest 'next_open_days should throw an exception' => sub {
309
        my $kcalendar = Koha::Calendar->new( branchcode => $branchcode, days_mode => 'Calendar' );
310
        throws_ok { $kcalendar->next_open_days( $now, 1 ) } 'Koha::Exceptions::Calendar::NoOpenDays';
311
    };
312
313
    subtest 'prev_open_days should throw an exception' => sub {
314
        my $kcalendar = Koha::Calendar->new( branchcode => $branchcode, days_mode => 'Calendar' );
315
        throws_ok { $kcalendar->prev_open_days( $now, 1 ) } 'Koha::Exceptions::Calendar::NoOpenDays';
316
    };
317
318
    $schema->storage->txn_rollback;
319
};
320
321
subtest 'with a library that is *almost* never open' => sub {
322
    plan tests => 2;
323
324
    $schema->storage->txn_begin;
325
326
    my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
327
    my $calendar   = C4::Calendar->new( branchcode => $branchcode );
328
    foreach my $weekday ( 0 .. 6 ) {
329
        $calendar->insert_week_day_holiday( weekday => $weekday, title => '', description => '' );
330
    }
331
332
    my $now                    = dt_from_string;
333
    my $open_day_in_the_future = $now->clone()->add( years => 1 );
334
    my $open_day_in_the_past   = $now->clone()->subtract( years => 1 );
335
    $calendar->insert_exception_holiday( date => $open_day_in_the_future->ymd, title => '', description => '' );
336
    $calendar->insert_exception_holiday( date => $open_day_in_the_past->ymd,   title => '', description => '' );
337
338
    subtest 'next_open_days should find the open day' => sub {
339
        my $kcalendar     = Koha::Calendar->new( branchcode => $branchcode, days_mode => 'Calendar' );
340
        my $next_open_day = $kcalendar->next_open_days( $now, 1 );
341
        is( $next_open_day->ymd, $open_day_in_the_future->ymd );
342
    };
343
344
    subtest 'prev_open_days should find the open day' => sub {
345
        my $kcalendar     = Koha::Calendar->new( branchcode => $branchcode, days_mode => 'Calendar' );
346
        my $prev_open_day = $kcalendar->prev_open_days( $now, 1 );
347
        is( $prev_open_day->ymd, $open_day_in_the_past->ymd );
348
    };
349
350
    $schema->storage->txn_rollback;
351
};
352
353
# Clear cache
354
Koha::Caches->get_instance->flush_all;
(-)a/t/db_dependent/Koha/Charges/Fees.t (-19 / +32 lines)
Lines 29-35 use t::lib::TestBuilder; Link Here
29
use t::lib::Dates;
29
use t::lib::Dates;
30
30
31
use Time::Fake;
31
use Time::Fake;
32
use C4::Calendar    qw( new insert_week_day_holiday delete_holiday );
32
use Koha::DiscreteCalendar;
33
use Koha::DateUtils qw(dt_from_string);
33
use Koha::DateUtils qw(dt_from_string);
34
34
35
BEGIN {
35
BEGIN {
Lines 363-389 subtest 'accumulate_rentalcharge tests' => sub { Link Here
363
    );
363
    );
364
    $itemtype->rentalcharge_daily_calendar(1)->store();
364
    $itemtype->rentalcharge_daily_calendar(1)->store();
365
365
366
    my $calendar = C4::Calendar->new( branchcode => $library->id );
366
    my $calendar = Koha::DiscreteCalendar->new({ branchcode => $library->id });
367
367
368
    # DateTime 1..7 (Mon..Sun), C4::Calender 0..6 (Sun..Sat)
368
    # DateTime 1..7 (Mon..Sun), Koha::DiscreteCalendar 1..7 (Sun..Sat)
369
    my $closed_day =
369
    my $closed_day =
370
          ( $dt_from->day_of_week == 6 ) ? 0
370
        ( $dt_from->day_of_week == 7 ) ? 1
371
        : ( $dt_from->day_of_week == 7 ) ? 1
371
      : $dt_from->day_of_week + 1;
372
        :                                  $dt_from->day_of_week + 1;
372
    $calendar->edit_holiday({
373
    $calendar->insert_week_day_holiday(
373
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
374
        weekday     => $closed_day,
374
        weekday      => $closed_day,
375
        title       => 'Test holiday',
375
        override     => 1,
376
        description => 'Test holiday'
376
        start_date   => $dt_from,
377
    );
377
        end_date     => $dt_from,
378
        title        => 'Test holiday',
379
        description  => 'Test holiday'
380
    });
378
    $charge = $fees->accumulate_rentalcharge();
381
    $charge = $fees->accumulate_rentalcharge();
379
    my $day_names = {
382
    my $day_names = {
380
        0 => 'Sunday',
383
        1 => 'Sunday',
381
        1 => 'Monday',
384
        2 => 'Monday',
382
        2 => 'Tuesday',
385
        3 => 'Tuesday',
383
        3 => 'Wednesday',
386
        4 => 'Wednesday',
384
        4 => 'Thursday',
387
        5 => 'Thursday',
385
        5 => 'Friday',
388
        6 => 'Friday',
386
        6 => 'Saturday'
389
        7 => 'Saturday'
387
    };
390
    };
388
    my $dayname = $day_names->{$closed_day};
391
    my $dayname = $day_names->{$closed_day};
389
    is(
392
    is(
Lines 437-443 subtest 'accumulate_rentalcharge tests' => sub { Link Here
437
    );
440
    );
438
441
439
    $itemtype->rentalcharge_hourly_calendar(1)->store();
442
    $itemtype->rentalcharge_hourly_calendar(1)->store();
440
    $calendar->delete_holiday( weekday => $closed_day );
443
    $calendar->edit_holiday({
444
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
445
        weekday      => $closed_day,
446
        override     => 1,
447
        today        => $dt_from,           # To override past date when deleting holiday type
448
        delete_type  => 1,
449
        start_date   => $dt_from,
450
        end_date     => $dt_from,
451
        title        => '',
452
        description  => '',
453
    });
441
    $charge = $fees->accumulate_rentalcharge();
454
    $charge = $fees->accumulate_rentalcharge();
442
    is(
455
    is(
443
        $charge, 24.00,
456
        $charge, 24.00,
(-)a/t/db_dependent/Koha/CurbsidePickups.t (-7 / +17 lines)
Lines 21-30 use Test::NoWarnings; Link Here
21
use Test::More tests => 5;
21
use Test::More tests => 5;
22
use Test::Exception;
22
use Test::Exception;
23
23
24
use C4::Calendar;
25
use Koha::CurbsidePickups;
24
use Koha::CurbsidePickups;
26
use Koha::CurbsidePickupPolicies;
25
use Koha::CurbsidePickupPolicies;
27
use Koha::Calendar;
26
use Koha::DiscreteCalendar;
28
use Koha::Database;
27
use Koha::Database;
29
use Koha::DateUtils qw( dt_from_string );
28
use Koha::DateUtils qw( dt_from_string );
30
29
Lines 152-170 subtest 'Create a pickup' => sub { Link Here
152
151
153
    # Day is a holiday
152
    # Day is a holiday
154
    Koha::Caches->get_instance->flush_all;
153
    Koha::Caches->get_instance->flush_all;
155
    C4::Calendar->new( branchcode => $library->branchcode )->insert_week_day_holiday(
154
    my $calendar = Koha::DiscreteCalendar->new({ branchcode => $library->branchcode });
156
        weekday     => 1,
155
    $calendar->edit_holiday({
156
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{WEEKLY},
157
        weekday      => 2,
158
        start_date   => $schedule_dt,
159
        end_date     => $schedule_dt,
157
        title       => '',
160
        title       => '',
158
        description => 'Mondays',
161
        description => 'Mondays',
159
    );
162
    });
160
    my $calendar = Koha::Calendar->new( branchcode => $library->branchcode );
161
    throws_ok {
163
    throws_ok {
162
        Koha::CurbsidePickup->new( { %$params, scheduled_pickup_datetime => $schedule_dt } )->store;
164
        Koha::CurbsidePickup->new( { %$params, scheduled_pickup_datetime => $schedule_dt } )->store;
163
    }
165
    }
164
    'Koha::Exceptions::CurbsidePickup::LibraryIsClosed',
166
    'Koha::Exceptions::CurbsidePickup::LibraryIsClosed',
165
        'Cannot create a pickup on a holiday';
167
        'Cannot create a pickup on a holiday';
166
168
167
    C4::Context->dbh->do(q{DELETE FROM repeatable_holidays});
169
    $calendar->edit_holiday({
170
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{NONE},
171
        weekday      => 2,
172
        delete_type  => 1,
173
        start_date   => $schedule_dt,
174
        end_date     => $schedule_dt,
175
        description  => '',
176
    });
177
168
    Koha::Caches->get_instance->flush_all;
178
    Koha::Caches->get_instance->flush_all;
169
};
179
};
170
180
(-)a/t/db_dependent/Koha/ItemTypes.t (-1 lines)
Lines 25-31 use Test::More tests => 16; Link Here
25
use t::lib::Mocks;
25
use t::lib::Mocks;
26
use t::lib::TestBuilder;
26
use t::lib::TestBuilder;
27
27
28
use C4::Calendar qw( new );
29
use Koha::Biblioitems;
28
use Koha::Biblioitems;
30
use Koha::Libraries;
29
use Koha::Libraries;
31
use Koha::Database;
30
use Koha::Database;
(-)a/t/db_dependent/Reserves/CancelExpiredReserves.t (-13 / +7 lines)
Lines 88-106 subtest 'CancelExpiredReserves tests incl. holidays' => sub { Link Here
88
    );
88
    );
89
89
90
    Koha::Caches->get_instance()->flush_all();
90
    Koha::Caches->get_instance()->flush_all();
91
    my $holiday = $builder->build(
91
    $builder->fill_discrete_calendar({ branchcode => 'LIB1 '});
92
        {
92
    my $calendar = Koha::DiscreteCalendar->new({ branchcode => 'LIB1' })->edit_holiday({
93
            source => 'SpecialHoliday',
93
        holiday_type => $Koha::DiscreteCalendar::HOLIDAYS->{EXCEPTION},
94
            value  => {
94
        start_date   => $today,
95
                branchcode  => 'LIB1',
95
        end_date     => $today,
96
                day         => $today->day,
96
        title        => 'My holiday',
97
                month       => $today->month,
97
    });
98
                year        => $today->year,
99
                title       => 'My holiday',
100
                isexception => 0
101
            },
102
        }
103
    );
104
98
105
    CancelExpiredReserves();
99
    CancelExpiredReserves();
106
    my $r3 = Koha::Holds->find( $reserve3->{reserve_id} );
100
    my $r3 = Koha::Holds->find( $reserve3->{reserve_id} );
(-)a/t/lib/TestBuilder.pm (-2 / +31 lines)
Lines 6-12 use Koha::Database qw( schema ); Link Here
6
use C4::Biblio      qw( AddBiblio );
6
use C4::Biblio      qw( AddBiblio );
7
use Koha::Biblios   qw( _type );
7
use Koha::Biblios   qw( _type );
8
use Koha::Items     qw( _type );
8
use Koha::Items     qw( _type );
9
use Koha::DateUtils qw( dt_from_string );
9
use Koha::DateUtils qw( dt_from_string output_pref );
10
10
11
use Bytes::Random::Secure;
11
use Bytes::Random::Secure;
12
use Carp         qw( carp );
12
use Carp         qw( carp );
Lines 152-157 sub build { Link Here
152
            if scalar @{ $fk->{keys} } == 1;
152
            if scalar @{ $fk->{keys} } == 1;
153
    }
153
    }
154
154
155
    if ($source eq 'Branch') {
156
        $self->fill_discrete_calendar({ branchcode => $col_values->{branchcode} });
157
    }
158
155
    # store this record and return hashref
159
    # store this record and return hashref
156
    return $self->_storeColumnValues(
160
    return $self->_storeColumnValues(
157
        {
161
        {
Lines 230-235 sub build_sample_ill_request { Link Here
230
    )->store->get_from_storage;
234
    )->store->get_from_storage;
231
}
235
}
232
236
237
sub fill_discrete_calendar {
238
    my ( $self, $args ) = @_;
239
240
    my $branchcode = $args->{branchcode} || '';
241
    my $start_date = ($args->{start_date}) ? dt_from_string($args->{start_date}) : DateTime->today();
242
    my $days = $args->{days} || 60;
243
244
    my $end_date = $start_date->clone();
245
    $start_date->add(days => 0 - $days);
246
    $end_date->add(days => $days);
247
248
    for (1; $start_date <= $end_date; $start_date->add(days => 1)) {
249
        my $data = {
250
            date       => output_pref( { dt => $start_date, dateformat => 'iso', dateonly => 1 }),
251
            branchcode => $branchcode,
252
            is_opened  => 1,
253
            open_hour  => "08:00:00",
254
            close_hour => "17:00:00",
255
        };
256
257
        $self->schema->resultset( "DiscreteCalendar" )->update_or_create( $data );
258
    }
259
260
    return
261
}
262
233
# ------------------------------------------------------------------------------
263
# ------------------------------------------------------------------------------
234
# Internal helper routines
264
# Internal helper routines
235
265
236
- 

Return to bug 17015