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

(-)a/C4/Circulation.pm (-13 / +23 lines)
Lines 3891-3910 sub CalcDateDue { Link Here
3891
    my $considerlibraryhours = C4::Context->preference('ConsiderLibraryHoursInCirculation');
3891
    my $considerlibraryhours = C4::Context->preference('ConsiderLibraryHoursInCirculation');
3892
3892
3893
    # starter vars so don't do calculations directly to $datedue
3893
    # starter vars so don't do calculations directly to $datedue
3894
    my $potential_datedue = $datedue->clone;
3894
    my $potential_datedue  = $datedue->clone;
3895
    my $library_close = $datedue->clone;
3895
    my $library_close      = $datedue->clone;
3896
    my $dayofweek = $datedue->day_of_week - 1;
3896
    my $dayofweek          = $datedue->day_of_week - 1;
3897
    my $tomorrow_dayofweek = $dayofweek + 1;
3897
    my $tomorrow_dayofweek = $dayofweek + 1;
3898
3898
    # If it's Sunday and tomorrow would be == 7, make tomorrow 0 (Days are stored as 0-6)
3899
    # If it's Sunday and tomorrow would be == 7, make tomorrow 0 (Days are stored as 0-6)
3899
    if ( $tomorrow_dayofweek > 6 ) { $tomorrow_dayofweek = 0; }
3900
    if ( $tomorrow_dayofweek > 6 ) { $tomorrow_dayofweek = 0; }
3900
    my $todayhours = Koha::Library::Hours->find({ library_id => $branch, day => $dayofweek });
3901
    my $todayhours    = Koha::Library::Hours->find( { library_id => $branch, day => $dayofweek } );
3901
    my @close = undef;
3902
    my @close         = undef;
3902
    my $tomorrowhours = Koha::Library::Hours->find({ library_id => $branch, day => $dayofweek+1 }); # get open hours of next day
3903
    my $tomorrowhours = Koha::Library::Hours->find( { library_id => $branch, day => $tomorrow_dayofweek } )
3904
        ;    # get open hours of next day
3903
    my @open = undef;
3905
    my @open = undef;
3904
    if ( $todayhours->close_time and $tomorrowhours->open_time ) {
3906
    if ( $considerlibraryhours ne 'ignore' and $todayhours->close_time and $tomorrowhours->open_time ) {
3905
        @close = split( ":", $todayhours->close_time );
3907
        @close             = split( ":", $todayhours->close_time );
3906
        $library_close = $library_close->set( hour => $close[0], minute => $close[1] );
3908
        $library_close     = $library_close->set( hour => $close[0], minute => $close[1] );
3907
        $potential_datedue = $potential_datedue->add( hours => $loanlength->{$length_key} ); # datedue without consideration for open hours
3909
        $potential_datedue = $potential_datedue->add( hours => $loanlength->{$length_key} )
3910
            ;    # datedue without consideration for open hours
3908
        @open = split( ":", $tomorrowhours->open_time );
3911
        @open = split( ":", $tomorrowhours->open_time );
3909
    }
3912
    }
3910
3913
Lines 3912-3931 sub CalcDateDue { Link Here
3912
    if ( $daysmode eq 'Days' )
3915
    if ( $daysmode eq 'Days' )
3913
    {    # ignoring calendar
3916
    {    # ignoring calendar
3914
        if ( $loanlength->{lengthunit} eq 'hours' ) {
3917
        if ( $loanlength->{lengthunit} eq 'hours' ) {
3915
            if ( $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3918
            if ( $considerlibraryhours ne 'ignore' and $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3916
                if ( $considerlibraryhours eq 'close' ) {
3919
                if ( $considerlibraryhours eq 'close' ) {
3920
3917
                    # datedue will be after the library closes on that day
3921
                    # datedue will be after the library closes on that day
3918
                    # shorten loan period to end when library closes
3922
                    # shorten loan period to end when library closes
3919
                    $datedue->set( hour => $close[0], minute => $close[1] );
3923
                    $datedue->set( hour => $close[0], minute => $close[1] );
3920
                } elsif ( $considerlibraryhours eq 'open' ) {
3924
                } elsif ( $considerlibraryhours eq 'open' ) {
3925
3921
                    # datedue will be after the library closes on that day
3926
                    # datedue will be after the library closes on that day
3922
                    # extend loan period to when library opens following day
3927
                    # extend loan period to when library opens following day
3923
                    $datedue->add( days => 1 )->set( hour => $open[0], minute => $open[1] );
3928
                    $datedue->add( days => 1 )->set( hour => $open[0], minute => $open[1] );
3924
                } else {
3929
                } else {
3930
3925
                    # ignore library open hours
3931
                    # ignore library open hours
3926
                    $datedue->add( hours => $loanlength->{$length_key} );
3932
                    $datedue->add( hours => $loanlength->{$length_key} );
3927
                }
3933
                }
3928
            } else {
3934
            } else {
3935
3929
                # due time doesn't conflict with library open hours, don't need to check
3936
                # due time doesn't conflict with library open hours, don't need to check
3930
                $datedue->add( hours => $loanlength->{$length_key} );
3937
                $datedue->add( hours => $loanlength->{$length_key} );
3931
            }
3938
            }
Lines 3936-3958 sub CalcDateDue { Link Here
3936
        }
3943
        }
3937
    } else {
3944
    } else {
3938
        my $dur;
3945
        my $dur;
3939
        my $sethours;
3940
        if ($loanlength->{lengthunit} eq 'hours') {
3946
        if ($loanlength->{lengthunit} eq 'hours') {
3941
            if ( $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3947
            if ( $considerlibraryhours ne 'ignore' and $potential_datedue > $library_close and $todayhours->close_time and $tomorrowhours->open_time ) {
3942
                if ( $considerlibraryhours eq 'close' ) {
3948
                if ( $considerlibraryhours eq 'close' ) {
3949
3943
                    # datedue will be after the library closes on that day
3950
                    # datedue will be after the library closes on that day
3944
                    # shorten loan period to end when library closes by hardcoding due time
3951
                    # shorten loan period to end when library closes by hardcoding due time
3945
                    $datedue->set( hour => $close[0], minute => $close[1] );
3952
                    $datedue->set( hour => $close[0], minute => $close[1] );
3946
                } elsif ( $considerlibraryhours eq 'open' ) {
3953
                } elsif ( $considerlibraryhours eq 'open' ) {
3954
3947
                    # datedue will be after the library closes on that day
3955
                    # datedue will be after the library closes on that day
3948
                    # extend loan period to when library opens following day by hardcoding due time for next open day
3956
                    # extend loan period to when library opens following day by hardcoding due time for next open day
3949
                    $dur = DateTime::Duration->new( days => 1 );
3957
                    $dur = DateTime::Duration->new( days => 1 );
3950
                    $datedue->set( hour => $open[0], minute => $open[1] );
3958
                    $datedue->set( hour => $open[0], minute => $open[1] );
3951
                } else {
3959
                } else {
3960
3952
                    # ignore library open hours
3961
                    # ignore library open hours
3953
                    $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3962
                    $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3954
                }
3963
                }
3955
            } else {
3964
            } else {
3965
3956
                # due time doesn't conflict with library open hours, don't need to check
3966
                # due time doesn't conflict with library open hours, don't need to check
3957
                $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3967
                $dur = DateTime::Duration->new( hours => $loanlength->{$length_key} );
3958
            }
3968
            }
(-)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 320-340 Link Here
320
                            [% IF opening_hours # Existing library %]
320
                            [% IF opening_hours # Existing library %]
321
                                [% daycount = 0 %]
321
                                [% daycount = 0 %]
322
                                [% FOREACH hr IN opening_hours %]
322
                                [% FOREACH hr IN opening_hours %]
323
                                <tr id="hours_[% daycount %]">
323
                                <tr id="hours_[% daycount | html %]">
324
                                    <td>
324
                                    <td>
325
                                        [% PROCESS dayname day=daycount %]
325
                                        [% PROCESS dayname day=daycount %]
326
                                        <input type="hidden" value="[% daycount %]" name="day">
326
                                        <input type="hidden" value="[% daycount | html %]" name="day">
327
                                    </td>
327
                                    </td>
328
                                    <td>
328
                                    <td>
329
                                        [% IF hr.day == daycount && hr.open_time %]
329
                                        [% IF hr.day == daycount && hr.open_time %]
330
                                        <input type="time" value="[% hr.open_time %]" name="open_time">
330
                                        <input type="time" value="[% hr.open_time | html %]" name="open_time">
331
                                        [% ELSE %]
331
                                        [% ELSE %]
332
                                        <input type="time" value="" name="open_time">
332
                                        <input type="time" value="" name="open_time">
333
                                        [% END %]
333
                                        [% END %]
334
                                    </td>
334
                                    </td>
335
                                    <td>
335
                                    <td>
336
                                        [% IF hr.day == daycount && hr.close_time %]
336
                                        [% IF hr.day == daycount && hr.close_time %]
337
                                        <input type="time" value="[% hr.close_time %]" name="close_time">
337
                                        <input type="time" value="[% hr.close_time | html %]" name="close_time">
338
                                        [% ELSE %]
338
                                        [% ELSE %]
339
                                        <input type="time" value="" name="close_time">
339
                                        <input type="time" value="" name="close_time">
340
                                        [% END %]
340
                                        [% END %]
Lines 344-353 Link Here
344
                                [% END %]
344
                                [% END %]
345
                            [% ELSE # New library %]
345
                            [% ELSE # New library %]
346
                                [% FOREACH daycount IN [0..6] %]
346
                                [% FOREACH daycount IN [0..6] %]
347
                                <tr id="hours_[% day %]">
347
                                <tr id="hours_[% day | html %]">
348
                                    <td>
348
                                    <td>
349
                                        [% PROCESS dayname day=daycount %]
349
                                        [% PROCESS dayname day=daycount %]
350
                                        <input type="hidden" value="[% daycount %]" name="day">
350
                                        <input type="hidden" value="[% daycount | html %]" name="day">
351
                                    </td>
351
                                    </td>
352
                                    <td>
352
                                    <td>
353
                                        <input type="time" value="" name="open_time">
353
                                        <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