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

(-)a/C4/Circulation.pm (-13 / +23 lines)
Lines 3848-3867 sub CalcDateDue { Link Here
3848
    my $considerlibraryhours = C4::Context->preference('ConsiderLibraryHoursInCirculation');
3848
    my $considerlibraryhours = C4::Context->preference('ConsiderLibraryHoursInCirculation');
3849
3849
3850
    # starter vars so don't do calculations directly to $datedue
3850
    # starter vars so don't do calculations directly to $datedue
3851
    my $potential_datedue = $datedue->clone;
3851
    my $potential_datedue  = $datedue->clone;
3852
    my $library_close = $datedue->clone;
3852
    my $library_close      = $datedue->clone;
3853
    my $dayofweek = $datedue->day_of_week - 1;
3853
    my $dayofweek          = $datedue->day_of_week - 1;
3854
    my $tomorrow_dayofweek = $dayofweek + 1;
3854
    my $tomorrow_dayofweek = $dayofweek + 1;
3855
3855
    # If it's Sunday and tomorrow would be == 7, make tomorrow 0 (Days are stored as 0-6)
3856
    # If it's Sunday and tomorrow would be == 7, make tomorrow 0 (Days are stored as 0-6)
3856
    if ( $tomorrow_dayofweek > 6 ) { $tomorrow_dayofweek = 0; }
3857
    if ( $tomorrow_dayofweek > 6 ) { $tomorrow_dayofweek = 0; }
3857
    my $todayhours = Koha::Library::Hours->find({ library_id => $branch, day => $dayofweek });
3858
    my $todayhours    = Koha::Library::Hours->find( { library_id => $branch, day => $dayofweek } );
3858
    my @close = undef;
3859
    my @close         = undef;
3859
    my $tomorrowhours = Koha::Library::Hours->find({ library_id => $branch, day => $dayofweek+1 }); # get open hours of next day
3860
    my $tomorrowhours = Koha::Library::Hours->find( { library_id => $branch, day => $tomorrow_dayofweek } )
3861
        ;    # get open hours of next day
3860
    my @open = undef;
3862
    my @open = undef;
3861
    if ( $todayhours->close_time and $tomorrowhours->open_time ) {
3863
    if ( $considerlibraryhours ne 'ignore' and $todayhours->close_time and $tomorrowhours->open_time ) {
3862
        @close = split( ":", $todayhours->close_time );
3864
        @close             = split( ":", $todayhours->close_time );
3863
        $library_close = $library_close->set( hour => $close[0], minute => $close[1] );
3865
        $library_close     = $library_close->set( hour => $close[0], minute => $close[1] );
3864
        $potential_datedue = $potential_datedue->add( hours => $loanlength->{$length_key} ); # datedue without consideration for open hours
3866
        $potential_datedue = $potential_datedue->add( hours => $loanlength->{$length_key} )
3867
            ;    # datedue without consideration for open hours
3865
        @open = split( ":", $tomorrowhours->open_time );
3868
        @open = split( ":", $tomorrowhours->open_time );
3866
    }
3869
    }
3867
3870
Lines 3869-3888 sub CalcDateDue { Link Here
3869
    if ( $daysmode eq 'Days' )
3872
    if ( $daysmode eq 'Days' )
3870
    {    # ignoring calendar
3873
    {    # ignoring calendar
3871
        if ( $loanlength->{lengthunit} eq 'hours' ) {
3874
        if ( $loanlength->{lengthunit} eq 'hours' ) {
3872
            if ( $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3875
            if ( $considerlibraryhours ne 'ignore' and $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3873
                if ( $considerlibraryhours eq 'close' ) {
3876
                if ( $considerlibraryhours eq 'close' ) {
3877
3874
                    # datedue will be after the library closes on that day
3878
                    # datedue will be after the library closes on that day
3875
                    # shorten loan period to end when library closes
3879
                    # shorten loan period to end when library closes
3876
                    $datedue->set( hour => $close[0], minute => $close[1] );
3880
                    $datedue->set( hour => $close[0], minute => $close[1] );
3877
                } elsif ( $considerlibraryhours eq 'open' ) {
3881
                } elsif ( $considerlibraryhours eq 'open' ) {
3882
3878
                    # datedue will be after the library closes on that day
3883
                    # datedue will be after the library closes on that day
3879
                    # extend loan period to when library opens following day
3884
                    # extend loan period to when library opens following day
3880
                    $datedue->add( days => 1 )->set( hour => $open[0], minute => $open[1] );
3885
                    $datedue->add( days => 1 )->set( hour => $open[0], minute => $open[1] );
3881
                } else {
3886
                } else {
3887
3882
                    # ignore library open hours
3888
                    # ignore library open hours
3883
                    $datedue->add( hours => $loanlength->{$length_key} );
3889
                    $datedue->add( hours => $loanlength->{$length_key} );
3884
                }
3890
                }
3885
            } else {
3891
            } else {
3892
3886
                # due time doesn't conflict with library open hours, don't need to check
3893
                # due time doesn't conflict with library open hours, don't need to check
3887
                $datedue->add( hours => $loanlength->{$length_key} );
3894
                $datedue->add( hours => $loanlength->{$length_key} );
3888
            }
3895
            }
Lines 3893-3915 sub CalcDateDue { Link Here
3893
        }
3900
        }
3894
    } else {
3901
    } else {
3895
        my $dur;
3902
        my $dur;
3896
        my $sethours;
3897
        if ($loanlength->{lengthunit} eq 'hours') {
3903
        if ($loanlength->{lengthunit} eq 'hours') {
3898
            if ( $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3904
            if ( $considerlibraryhours ne 'ignore' and $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3899
                if ( $considerlibraryhours eq 'close' ) {
3905
                if ( $considerlibraryhours eq 'close' ) {
3906
3900
                    # datedue will be after the library closes on that day
3907
                    # datedue will be after the library closes on that day
3901
                    # shorten loan period to end when library closes by hardcoding due time
3908
                    # shorten loan period to end when library closes by hardcoding due time
3902
                    $datedue->set( hour => $close[0], minute => $close[1] );
3909
                    $datedue->set( hour => $close[0], minute => $close[1] );
3903
                } elsif ( $considerlibraryhours eq 'open' ) {
3910
                } elsif ( $considerlibraryhours eq 'open' ) {
3911
3904
                    # datedue will be after the library closes on that day
3912
                    # datedue will be after the library closes on that day
3905
                    # extend loan period to when library opens following day by hardcoding due time for next open day
3913
                    # extend loan period to when library opens following day by hardcoding due time for next open day
3906
                    $dur = DateTime::Duration->new( days => 1 );
3914
                    $dur = DateTime::Duration->new( days => 1 );
3907
                    $datedue->set( hour => $open[0], minute => $open[1] );
3915
                    $datedue->set( hour => $open[0], minute => $open[1] );
3908
                } else {
3916
                } else {
3917
3909
                    # ignore library open hours
3918
                    # ignore library open hours
3910
                    $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3919
                    $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3911
                }
3920
                }
3912
            } else {
3921
            } else {
3922
3913
                # due time doesn't conflict with library open hours, don't need to check
3923
                # due time doesn't conflict with library open hours, don't need to check
3914
                $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3924
                $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3915
            }
3925
            }
(-)a/admin/branches.pl (-11 / +18 lines)
Lines 50-60 my ( $template, $borrowernumber, $cookie ) = get_template_and_user( Link Here
50
);
50
);
51
51
52
if ( $op eq 'add_form' ) {
52
if ( $op eq 'add_form' ) {
53
    my @opening_hours = Koha::Library::Hours->search({ library_id => $branchcode }, { order_by => { -asc => 'day' } })->as_list;
53
    my @opening_hours =
54
        Koha::Library::Hours->search( { library_id => $branchcode }, { order_by => { -asc => 'day' } } )->as_list;
54
55
55
    $template->param(
56
    $template->param(
56
        library      => Koha::Libraries->find($branchcode),
57
        library       => Koha::Libraries->find($branchcode),
57
        smtp_servers => Koha::SMTP::Servers->search,
58
        smtp_servers  => Koha::SMTP::Servers->search,
58
        opening_hours => \@opening_hours
59
        opening_hours => \@opening_hours
59
    );
60
    );
60
} elsif ( $branchcode && $op eq 'view' ) {
61
} elsif ( $branchcode && $op eq 'view' ) {
Lines 118-128 if ( $op eq 'add_form' ) { Link Here
118
                        }
119
                        }
119
                    }
120
                    }
120
121
121
                    my @days = $input->multi_param("day");
122
                    my @days        = $input->multi_param("day");
122
                    my @open_times = $input->multi_param("open_time");
123
                    my @open_times  = $input->multi_param("open_time");
123
                    my @close_times = $input->multi_param("close_time");
124
                    my @close_times = $input->multi_param("close_time");
124
125
125
                    foreach my $day ( @days ) {
126
                    foreach my $day (@days) {
126
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
127
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
127
                            $open_times[$day] = undef;
128
                            $open_times[$day] = undef;
128
                        }
129
                        }
Lines 130-136 if ( $op eq 'add_form' ) { Link Here
130
                            $close_times[$day] = undef;
131
                            $close_times[$day] = undef;
131
                        }
132
                        }
132
133
133
                        my $openday = Koha::Library::Hours->find({ library_id => $branchcode, day => $day })->update({ open_time => $open_times[$day], close_time => $close_times[$day] });
134
                        my $openday = Koha::Library::Hours->find( { library_id => $branchcode, day => $day } )
135
                            ->update( { open_time => $open_times[$day], close_time => $close_times[$day] } );
134
                    }
136
                    }
135
137
136
                    push @messages, { type => 'message', code => 'success_on_update' };
138
                    push @messages, { type => 'message', code => 'success_on_update' };
Lines 171-181 if ( $op eq 'add_form' ) { Link Here
171
                        }
173
                        }
172
                    }
174
                    }
173
175
174
                    my @days = $input->multi_param("day");
176
                    my @days        = $input->multi_param("day");
175
                    my @open_times = $input->multi_param("open_time");
177
                    my @open_times  = $input->multi_param("open_time");
176
                    my @close_times = $input->multi_param("close_time");
178
                    my @close_times = $input->multi_param("close_time");
177
179
178
                    foreach my $day ( @days ) {
180
                    foreach my $day (@days) {
179
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
181
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
180
                            $open_times[$day] = undef;
182
                            $open_times[$day] = undef;
181
                        }
183
                        }
Lines 183-189 if ( $op eq 'add_form' ) { Link Here
183
                            $close_times[$day] = undef;
185
                            $close_times[$day] = undef;
184
                        }
186
                        }
185
187
186
                        my $openday = Koha::Library::Hour->new({ library_id => $branchcode, day => $day, open_time => $open_times[$day], close_time => $close_times[$day] })->store;
188
                        my $openday = Koha::Library::Hour->new(
189
                            {
190
                                library_id => $branchcode, day => $day, open_time => $open_times[$day],
191
                                close_time => $close_times[$day]
192
                            }
193
                        )->store;
187
                    }
194
                    }
188
195
189
                    push @messages, { type => 'message', code => 'success_on_insert' };
196
                    push @messages, { type => 'message', code => 'success_on_insert' };
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt (-6 / +6 lines)
Lines 300-320 Link Here
300
                            [% IF opening_hours # Existing library %]
300
                            [% IF opening_hours # Existing library %]
301
                                [% daycount = 0 %]
301
                                [% daycount = 0 %]
302
                                [% FOREACH hr IN opening_hours %]
302
                                [% FOREACH hr IN opening_hours %]
303
                                <tr id="hours_[% daycount %]">
303
                                <tr id="hours_[% daycount | html %]">
304
                                    <td>
304
                                    <td>
305
                                        [% PROCESS dayname day=daycount %]
305
                                        [% PROCESS dayname day=daycount %]
306
                                        <input type="hidden" value="[% daycount %]" name="day">
306
                                        <input type="hidden" value="[% daycount | html %]" name="day">
307
                                    </td>
307
                                    </td>
308
                                    <td>
308
                                    <td>
309
                                        [% IF hr.day == daycount && hr.open_time %]
309
                                        [% IF hr.day == daycount && hr.open_time %]
310
                                        <input type="time" value="[% hr.open_time %]" name="open_time">
310
                                        <input type="time" value="[% hr.open_time | html %]" name="open_time">
311
                                        [% ELSE %]
311
                                        [% ELSE %]
312
                                        <input type="time" value="" name="open_time">
312
                                        <input type="time" value="" name="open_time">
313
                                        [% END %]
313
                                        [% END %]
314
                                    </td>
314
                                    </td>
315
                                    <td>
315
                                    <td>
316
                                        [% IF hr.day == daycount && hr.close_time %]
316
                                        [% IF hr.day == daycount && hr.close_time %]
317
                                        <input type="time" value="[% hr.close_time %]" name="close_time">
317
                                        <input type="time" value="[% hr.close_time | html %]" name="close_time">
318
                                        [% ELSE %]
318
                                        [% ELSE %]
319
                                        <input type="time" value="" name="close_time">
319
                                        <input type="time" value="" name="close_time">
320
                                        [% END %]
320
                                        [% END %]
Lines 324-333 Link Here
324
                                [% END %]
324
                                [% END %]
325
                            [% ELSE # New library %]
325
                            [% ELSE # New library %]
326
                                [% FOREACH daycount IN [0..6] %]
326
                                [% FOREACH daycount IN [0..6] %]
327
                                <tr id="hours_[% day %]">
327
                                <tr id="hours_[% day | html %]">
328
                                    <td>
328
                                    <td>
329
                                        [% PROCESS dayname day=daycount %]
329
                                        [% PROCESS dayname day=daycount %]
330
                                        <input type="hidden" value="[% daycount %]" name="day">
330
                                        <input type="hidden" value="[% daycount | html %]" name="day">
331
                                    </td>
331
                                    </td>
332
                                    <td>
332
                                    <td>
333
                                        <input type="time" value="" name="open_time">
333
                                        <input type="time" value="" name="open_time">
(-)a/t/db_dependent/Circulation/CalcDateDue.t (-30 / +47 lines)
Lines 362-440 is( $date->ymd, $renewed_date->ymd, 'Renewal period of "" should trigger fallove Link Here
362
my $library1 = $builder->build( { source => 'Branch' } );
362
my $library1 = $builder->build( { source => 'Branch' } );
363
Koha::CirculationRules->set_rules(
363
Koha::CirculationRules->set_rules(
364
    {
364
    {
365
        categorycode => $categorycode,
365
        categorycode => $borrower->categorycode,
366
        itemtype     => $itemtype,
366
        itemtype     => $itemtype,
367
        branchcode   => $library1->{branchcode},
367
        branchcode   => $library1->{branchcode},
368
        rules        => {
368
        rules        => {
369
            issuelength   => 3, # loan period is 3 hours
369
            issuelength => 3,         # loan period is 3 hours
370
            lengthunit    => 'hours',
370
            lengthunit  => 'hours',
371
            daysmode      => '',
371
            daysmode    => '',
372
        }
372
        }
373
    }
373
    }
374
);
374
);
375
375
376
my $open = DateTime->new( year => 2023, month => 5, day => 1, hour => 10 )->hms;
376
my $open  = DateTime->new( year => 2023, month => 5, day => 1, hour => 10 )->hms;
377
my $close = DateTime->new( year => 2023, month => 5, day => 1, hour => 16 )->hms;
377
my $close = DateTime->new( year => 2023, month => 5, day => 1, hour => 16 )->hms;
378
my $now = DateTime->new( year => 2023, month => 5, day => 1, hour => 14 );
378
my $now   = DateTime->new( year => 2023, month => 5, day => 1, hour => 14 );
379
380
foreach ( 0 .. 6 ) {
379
381
380
foreach (0..6) {
381
    # library opened 4 hours ago and closes in 2 hours.
382
    # library opened 4 hours ago and closes in 2 hours.
382
    Koha::Library::Hour->new({ day => $_, library_id => $library1->{branchcode}, open_time => $open, close_time => $close })->store;
383
    Koha::Library::Hour->new(
384
        { day => $_, library_id => $library1->{branchcode}, open_time => $open, close_time => $close } )->store;
383
}
385
}
384
386
385
# ignore calendar
387
# ignore calendar
386
t::lib::Mocks::mock_preference('useDaysMode', 'Days');
388
t::lib::Mocks::mock_preference( 'useDaysMode',                       'Days' );
387
t::lib::Mocks::mock_preference('ConsiderLibraryHoursInCirculation', 'close');
389
t::lib::Mocks::mock_preference( 'ConsiderLibraryHoursInCirculation', 'close' );
390
388
# shorten loan period
391
# shorten loan period
389
392
390
$date = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
393
$date = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
391
my $expected_duetime = $now->clone->add( hours => 2 );
394
my $expected_duetime = $now->clone->add( hours => 2 );
392
is( $date, $expected_duetime, "Loan period was shortened because ConsiderLibraryHoursInCirculation is set to close time" );
395
is(
396
    $date, $expected_duetime,
397
    "Loan period was shortened because ConsiderLibraryHoursInCirculation is set to close time"
398
);
399
400
t::lib::Mocks::mock_preference( 'ConsiderLibraryHoursInCirculation', 'open' );
393
401
394
t::lib::Mocks::mock_preference('ConsiderLibraryHoursWhenIssuing', 'open');
395
# extend loan period
402
# extend loan period
396
403
397
$date = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
404
$date             = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
398
$expected_duetime = $now->clone->add( days => 1 )->subtract( hours => 4 );
405
$expected_duetime = $now->clone->add( days => 1 )->subtract( hours => 4 );
399
is( $date, $expected_duetime, "Loan period was extended because ConsiderLibraryHoursInCirculation is set to open time" );
406
is(
407
    $date, $expected_duetime,
408
    "Loan period was extended because ConsiderLibraryHoursInCirculation is set to open time"
409
);
400
410
401
my $holiday_tomorrow = $now->clone->add( days => 1 );
411
my $holiday_tomorrow = $now->clone->add( days => 1 );
402
412
403
# consider calendar
413
# consider calendar
404
my $library1_calendar = C4::Calendar->new( branchcode => $library1->{branchcode} );
414
my $library1_calendar = C4::Calendar->new( branchcode => $library1->{branchcode} );
405
$library1_calendar->insert_single_holiday(
415
$library1_calendar->insert_single_holiday(
406
    day             => $holiday_tomorrow->day,
416
    day         => $holiday_tomorrow->day,
407
    month           => $holiday_tomorrow->month,
417
    month       => $holiday_tomorrow->month,
408
    year            => $holiday_tomorrow->year,
418
    year        => $holiday_tomorrow->year,
409
    title           => 'testholiday',
419
    title       => 'testholiday',
410
    description     => 'testholiday'
420
    description => 'testholiday'
411
);
421
);
412
Koha::CirculationRules->set_rules(
422
Koha::CirculationRules->set_rules(
413
    {
423
    {
414
        categorycode => $categorycode,
424
        categorycode => $patron_category->categorycode,
415
        itemtype     => $itemtype,
425
        itemtype     => $itemtype,
416
        branchcode   => $library1->{branchcode},
426
        branchcode   => $library1->{branchcode},
417
        rules        => {
427
        rules        => {
418
            issuelength   => 18, # loan period must cross over into tomorrow
428
            issuelength => 18,        # loan period must cross over into tomorrow
419
            lengthunit    => 'hours',
429
            lengthunit  => 'hours',
420
        }
430
        }
421
    }
431
    }
422
);
432
);
423
433
424
t::lib::Mocks::mock_preference('useDaysMode', 'Calendar');
434
t::lib::Mocks::mock_preference( 'useDaysMode',                       'Calendar' );
425
t::lib::Mocks::mock_preference('ConsiderLibraryHoursInCirculation', 'close');
435
t::lib::Mocks::mock_preference( 'ConsiderLibraryHoursInCirculation', 'close' );
436
426
# shorten loan period
437
# shorten loan period
427
438
428
$date = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
439
$date             = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
429
$expected_duetime = $now->clone->add( days => 2, hours => 2 );
440
$expected_duetime = $now->clone->add( hours => 2 );
430
is( $date, $expected_duetime, "Loan period was shortened (but considers the holiday) because ConsiderLibraryHoursInCirculation is set to close time" );
441
is(
442
    $date, $expected_duetime,
443
    "Loan period was shortened (but considers the holiday) because ConsiderLibraryHoursInCirculation is set to close time"
444
);
431
445
432
t::lib::Mocks::mock_preference( 'ConsiderLibraryHoursInCirculation', 'open' );
446
t::lib::Mocks::mock_preference( 'ConsiderLibraryHoursInCirculation', 'open' );
447
433
# extend loan period
448
# extend loan period
434
449
435
$date = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
450
$date             = C4::Circulation::CalcDateDue( $now, $itemtype, $library1->{branchcode}, $borrower );
436
$expected_duetime = $now->clone->add( days => 2 )->subtract( hours => 4 );
451
$expected_duetime = $now->clone->add( days => 2 )->subtract( hours => 4 );
437
is( $date, $expected_duetime, "Loan period was extended (but considers the holiday) because ConsiderLibraryHoursInCirculation is set to open time" );
452
is(
453
    $date, $expected_duetime,
454
    "Loan period was extended (but considers the holiday) because ConsiderLibraryHoursInCirculation is set to open time"
455
);
438
456
439
$cache->clear_from_cache($key);
457
$cache->clear_from_cache($key);
440
$schema->storage->txn_rollback;
458
$schema->storage->txn_rollback;
441
- 

Return to bug 6796