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

(-)a/C4/Circulation.pm (-13 / +23 lines)
Lines 3895-3914 sub CalcDateDue { Link Here
3895
    my $considerlibraryhours = C4::Context->preference('ConsiderLibraryHoursInCirculation');
3895
    my $considerlibraryhours = C4::Context->preference('ConsiderLibraryHoursInCirculation');
3896
3896
3897
    # starter vars so don't do calculations directly to $datedue
3897
    # starter vars so don't do calculations directly to $datedue
3898
    my $potential_datedue = $datedue->clone;
3898
    my $potential_datedue  = $datedue->clone;
3899
    my $library_close = $datedue->clone;
3899
    my $library_close      = $datedue->clone;
3900
    my $dayofweek = $datedue->day_of_week - 1;
3900
    my $dayofweek          = $datedue->day_of_week - 1;
3901
    my $tomorrow_dayofweek = $dayofweek + 1;
3901
    my $tomorrow_dayofweek = $dayofweek + 1;
3902
3902
    # If it's Sunday and tomorrow would be == 7, make tomorrow 0 (Days are stored as 0-6)
3903
    # If it's Sunday and tomorrow would be == 7, make tomorrow 0 (Days are stored as 0-6)
3903
    if ( $tomorrow_dayofweek > 6 ) { $tomorrow_dayofweek = 0; }
3904
    if ( $tomorrow_dayofweek > 6 ) { $tomorrow_dayofweek = 0; }
3904
    my $todayhours = Koha::Library::Hours->find({ library_id => $branch, day => $dayofweek });
3905
    my $todayhours    = Koha::Library::Hours->find( { library_id => $branch, day => $dayofweek } );
3905
    my @close = undef;
3906
    my @close         = undef;
3906
    my $tomorrowhours = Koha::Library::Hours->find({ library_id => $branch, day => $dayofweek+1 }); # get open hours of next day
3907
    my $tomorrowhours = Koha::Library::Hours->find( { library_id => $branch, day => $tomorrow_dayofweek } )
3908
        ;    # get open hours of next day
3907
    my @open = undef;
3909
    my @open = undef;
3908
    if ( $todayhours->close_time and $tomorrowhours->open_time ) {
3910
    if ( $considerlibraryhours ne 'ignore' and $todayhours->close_time and $tomorrowhours->open_time ) {
3909
        @close = split( ":", $todayhours->close_time );
3911
        @close             = split( ":", $todayhours->close_time );
3910
        $library_close = $library_close->set( hour => $close[0], minute => $close[1] );
3912
        $library_close     = $library_close->set( hour => $close[0], minute => $close[1] );
3911
        $potential_datedue = $potential_datedue->add( hours => $loanlength->{$length_key} ); # datedue without consideration for open hours
3913
        $potential_datedue = $potential_datedue->add( hours => $loanlength->{$length_key} )
3914
            ;    # datedue without consideration for open hours
3912
        @open = split( ":", $tomorrowhours->open_time );
3915
        @open = split( ":", $tomorrowhours->open_time );
3913
    }
3916
    }
3914
3917
Lines 3916-3935 sub CalcDateDue { Link Here
3916
    if ( $daysmode eq 'Days' )
3919
    if ( $daysmode eq 'Days' )
3917
    {    # ignoring calendar
3920
    {    # ignoring calendar
3918
        if ( $loanlength->{lengthunit} eq 'hours' ) {
3921
        if ( $loanlength->{lengthunit} eq 'hours' ) {
3919
            if ( $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3922
            if ( $considerlibraryhours ne 'ignore' and $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3920
                if ( $considerlibraryhours eq 'close' ) {
3923
                if ( $considerlibraryhours eq 'close' ) {
3924
3921
                    # datedue will be after the library closes on that day
3925
                    # datedue will be after the library closes on that day
3922
                    # shorten loan period to end when library closes
3926
                    # shorten loan period to end when library closes
3923
                    $datedue->set( hour => $close[0], minute => $close[1] );
3927
                    $datedue->set( hour => $close[0], minute => $close[1] );
3924
                } elsif ( $considerlibraryhours eq 'open' ) {
3928
                } elsif ( $considerlibraryhours eq 'open' ) {
3929
3925
                    # datedue will be after the library closes on that day
3930
                    # datedue will be after the library closes on that day
3926
                    # extend loan period to when library opens following day
3931
                    # extend loan period to when library opens following day
3927
                    $datedue->add( days => 1 )->set( hour => $open[0], minute => $open[1] );
3932
                    $datedue->add( days => 1 )->set( hour => $open[0], minute => $open[1] );
3928
                } else {
3933
                } else {
3934
3929
                    # ignore library open hours
3935
                    # ignore library open hours
3930
                    $datedue->add( hours => $loanlength->{$length_key} );
3936
                    $datedue->add( hours => $loanlength->{$length_key} );
3931
                }
3937
                }
3932
            } else {
3938
            } else {
3939
3933
                # due time doesn't conflict with library open hours, don't need to check
3940
                # due time doesn't conflict with library open hours, don't need to check
3934
                $datedue->add( hours => $loanlength->{$length_key} );
3941
                $datedue->add( hours => $loanlength->{$length_key} );
3935
            }
3942
            }
Lines 3940-3962 sub CalcDateDue { Link Here
3940
        }
3947
        }
3941
    } else {
3948
    } else {
3942
        my $dur;
3949
        my $dur;
3943
        my $sethours;
3944
        if ($loanlength->{lengthunit} eq 'hours') {
3950
        if ($loanlength->{lengthunit} eq 'hours') {
3945
            if ( $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3951
            if ( $considerlibraryhours ne 'ignore' and $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3946
                if ( $considerlibraryhours eq 'close' ) {
3952
                if ( $considerlibraryhours eq 'close' ) {
3953
3947
                    # datedue will be after the library closes on that day
3954
                    # datedue will be after the library closes on that day
3948
                    # shorten loan period to end when library closes by hardcoding due time
3955
                    # shorten loan period to end when library closes by hardcoding due time
3949
                    $datedue->set( hour => $close[0], minute => $close[1] );
3956
                    $datedue->set( hour => $close[0], minute => $close[1] );
3950
                } elsif ( $considerlibraryhours eq 'open' ) {
3957
                } elsif ( $considerlibraryhours eq 'open' ) {
3958
3951
                    # datedue will be after the library closes on that day
3959
                    # datedue will be after the library closes on that day
3952
                    # extend loan period to when library opens following day by hardcoding due time for next open day
3960
                    # extend loan period to when library opens following day by hardcoding due time for next open day
3953
                    $dur = DateTime::Duration->new( days => 1 );
3961
                    $dur = DateTime::Duration->new( days => 1 );
3954
                    $datedue->set( hour => $open[0], minute => $open[1] );
3962
                    $datedue->set( hour => $open[0], minute => $open[1] );
3955
                } else {
3963
                } else {
3964
3956
                    # ignore library open hours
3965
                    # ignore library open hours
3957
                    $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3966
                    $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3958
                }
3967
                }
3959
            } else {
3968
            } else {
3969
3960
                # due time doesn't conflict with library open hours, don't need to check
3970
                # due time doesn't conflict with library open hours, don't need to check
3961
                $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3971
                $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3962
            }
3972
            }
(-)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 120-130 if ( $op eq 'add_form' ) { Link Here
120
                        }
121
                        }
121
                    }
122
                    }
122
123
123
                    my @days = $input->multi_param("day");
124
                    my @days        = $input->multi_param("day");
124
                    my @open_times = $input->multi_param("open_time");
125
                    my @open_times  = $input->multi_param("open_time");
125
                    my @close_times = $input->multi_param("close_time");
126
                    my @close_times = $input->multi_param("close_time");
126
127
127
                    foreach my $day ( @days ) {
128
                    foreach my $day (@days) {
128
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
129
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
129
                            $open_times[$day] = undef;
130
                            $open_times[$day] = undef;
130
                        }
131
                        }
Lines 132-138 if ( $op eq 'add_form' ) { Link Here
132
                            $close_times[$day] = undef;
133
                            $close_times[$day] = undef;
133
                        }
134
                        }
134
135
135
                        my $openday = Koha::Library::Hours->find({ library_id => $branchcode, day => $day })->update({ open_time => $open_times[$day], close_time => $close_times[$day] });
136
                        my $openday = Koha::Library::Hours->find( { library_id => $branchcode, day => $day } )
137
                            ->update( { open_time => $open_times[$day], close_time => $close_times[$day] } );
136
                    }
138
                    }
137
139
138
                    push @messages, { type => 'message', code => 'success_on_update' };
140
                    push @messages, { type => 'message', code => 'success_on_update' };
Lines 173-183 if ( $op eq 'add_form' ) { Link Here
173
                        }
175
                        }
174
                    }
176
                    }
175
177
176
                    my @days = $input->multi_param("day");
178
                    my @days        = $input->multi_param("day");
177
                    my @open_times = $input->multi_param("open_time");
179
                    my @open_times  = $input->multi_param("open_time");
178
                    my @close_times = $input->multi_param("close_time");
180
                    my @close_times = $input->multi_param("close_time");
179
181
180
                    foreach my $day ( @days ) {
182
                    foreach my $day (@days) {
181
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
183
                        if ( $open_times[$day] !~ /([0-9]{2}:[0-9]{2})/ ) {
182
                            $open_times[$day] = undef;
184
                            $open_times[$day] = undef;
183
                        }
185
                        }
Lines 185-191 if ( $op eq 'add_form' ) { Link Here
185
                            $close_times[$day] = undef;
187
                            $close_times[$day] = undef;
186
                        }
188
                        }
187
189
188
                        my $openday = Koha::Library::Hour->new({ library_id => $branchcode, day => $day, open_time => $open_times[$day], close_time => $close_times[$day] })->store;
190
                        my $openday = Koha::Library::Hour->new(
191
                            {
192
                                library_id => $branchcode, day => $day, open_time => $open_times[$day],
193
                                close_time => $close_times[$day]
194
                            }
195
                        )->store;
189
                    }
196
                    }
190
197
191
                    push @messages, { type => 'message', code => 'success_on_insert' };
198
                    push @messages, { type => 'message', code => 'success_on_insert' };
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/branches.tt (-6 / +6 lines)
Lines 303-323 Link Here
303
                            [% IF opening_hours # Existing library %]
303
                            [% IF opening_hours # Existing library %]
304
                                [% daycount = 0 %]
304
                                [% daycount = 0 %]
305
                                [% FOREACH hr IN opening_hours %]
305
                                [% FOREACH hr IN opening_hours %]
306
                                <tr id="hours_[% daycount %]">
306
                                <tr id="hours_[% daycount | html %]">
307
                                    <td>
307
                                    <td>
308
                                        [% PROCESS dayname day=daycount %]
308
                                        [% PROCESS dayname day=daycount %]
309
                                        <input type="hidden" value="[% daycount %]" name="day">
309
                                        <input type="hidden" value="[% daycount | html %]" name="day">
310
                                    </td>
310
                                    </td>
311
                                    <td>
311
                                    <td>
312
                                        [% IF hr.day == daycount && hr.open_time %]
312
                                        [% IF hr.day == daycount && hr.open_time %]
313
                                        <input type="time" value="[% hr.open_time %]" name="open_time">
313
                                        <input type="time" value="[% hr.open_time | html %]" name="open_time">
314
                                        [% ELSE %]
314
                                        [% ELSE %]
315
                                        <input type="time" value="" name="open_time">
315
                                        <input type="time" value="" name="open_time">
316
                                        [% END %]
316
                                        [% END %]
317
                                    </td>
317
                                    </td>
318
                                    <td>
318
                                    <td>
319
                                        [% IF hr.day == daycount && hr.close_time %]
319
                                        [% IF hr.day == daycount && hr.close_time %]
320
                                        <input type="time" value="[% hr.close_time %]" name="close_time">
320
                                        <input type="time" value="[% hr.close_time | html %]" name="close_time">
321
                                        [% ELSE %]
321
                                        [% ELSE %]
322
                                        <input type="time" value="" name="close_time">
322
                                        <input type="time" value="" name="close_time">
323
                                        [% END %]
323
                                        [% END %]
Lines 327-336 Link Here
327
                                [% END %]
327
                                [% END %]
328
                            [% ELSE # New library %]
328
                            [% ELSE # New library %]
329
                                [% FOREACH daycount IN [0..6] %]
329
                                [% FOREACH daycount IN [0..6] %]
330
                                <tr id="hours_[% day %]">
330
                                <tr id="hours_[% day | html %]">
331
                                    <td>
331
                                    <td>
332
                                        [% PROCESS dayname day=daycount %]
332
                                        [% PROCESS dayname day=daycount %]
333
                                        <input type="hidden" value="[% daycount %]" name="day">
333
                                        <input type="hidden" value="[% daycount | html %]" name="day">
334
                                    </td>
334
                                    </td>
335
                                    <td>
335
                                    <td>
336
                                        <input type="time" value="" name="open_time">
336
                                        <input type="time" value="" name="open_time">
(-)a/t/db_dependent/Circulation/CalcDateDue.t (-31 / +48 lines)
Lines 8-14 use DBI; Link Here
8
use DateTime;
8
use DateTime;
9
use t::lib::Mocks;
9
use t::lib::Mocks;
10
use t::lib::TestBuilder;
10
use t::lib::TestBuilder;
11
use C4::Calendar qw( new insert_single_holiday delete_holiday insert_week_day_holiday );
11
use C4::Calendar    qw( new insert_single_holiday delete_holiday insert_week_day_holiday );
12
use Koha::DateUtils qw( dt_from_string );
12
use Koha::DateUtils qw( dt_from_string );
13
use Koha::Library::Hours;
13
use Koha::Library::Hours;
14
use Koha::CirculationRules;
14
use Koha::CirculationRules;
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