use Modern::Perl;
-use Carp;
+use Carp qw( croak );
use DateTime;
-use DateTime::Set;
use DateTime::Duration;
use C4::Context;
use Koha::Caches;
return;
}
-sub exception_holidays {
- my ( $self ) = @_;
+sub _holidays {
+ my ($self) = @_;
- my $cache = Koha::Caches->get_instance();
- my $cached = $cache->get_from_cache('exception_holidays');
- return $cached if $cached;
+ my $key = $self->{branchcode} . "_holidays";
+ my $cache = Koha::Caches->get_instance();
+ my $holidays = $cache->get_from_cache($key);
- my $dbh = C4::Context->dbh;
- my $branch = $self->{branchcode};
- my $exception_holidays_sth = $dbh->prepare(
-'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1'
- );
- $exception_holidays_sth->execute( $branch );
- my $dates = [];
- while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) {
- push @{$dates},
- DateTime->new(
- day => $day,
- month => $month,
- year => $year,
- time_zone => "floating",
- )->truncate( to => 'day' );
- }
- $self->{exception_holidays} =
- DateTime::Set->from_datetimes( dates => $dates );
- $cache->set_in_cache( 'exception_holidays', $self->{exception_holidays} );
- return $self->{exception_holidays};
-}
-
-sub single_holidays {
- my ( $self, $date ) = @_;
- my $branchcode = $self->{branchcode};
- my $cache = Koha::Caches->get_instance();
- my $single_holidays = $cache->get_from_cache('single_holidays');
-
- # $single_holidays looks like:
+ # $holidays looks like:
# {
- # CPL => [
- # [0] 20131122,
- # ...
- # ],
- # ...
+ # 20131122 => 1, # single_holiday
+ # 20131123 => 0, # exception_holiday
+ # ...
# }
- unless ($single_holidays) {
+ # Populate the cache if necessary
+ unless ($holidays) {
my $dbh = C4::Context->dbh;
- $single_holidays = {};
-
- # push holidays for each branch
- my $branches_sth =
- $dbh->prepare('SELECT distinct(branchcode) FROM special_holidays');
- $branches_sth->execute();
- while ( my $br = $branches_sth->fetchrow ) {
- my $single_holidays_sth = $dbh->prepare(
-'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0'
- );
- $single_holidays_sth->execute($br);
-
- my @ymd_arr;
- while ( my ( $day, $month, $year ) =
- $single_holidays_sth->fetchrow )
- {
- my $dt = DateTime->new(
- day => $day,
- month => $month,
- year => $year,
- time_zone => 'floating',
- )->truncate( to => 'day' );
- push @ymd_arr, $dt->ymd('');
- }
- $single_holidays->{$br} = \@ymd_arr;
- } # br
- $cache->set_in_cache( 'single_holidays', $single_holidays,
- { expiry => 76800 } ) #24 hrs ;
- }
- my $holidays = ( $single_holidays->{$branchcode} );
- for my $hols (@$holidays ) {
- return 1 if ( $date == $hols ) #match ymds;
+ $holidays = {};
+
+ # Add holidays for each branch
+ my $holidays_sth = $dbh->prepare(
+'SELECT day, month, year, MAX(isexception) FROM special_holidays WHERE branchcode = ? GROUP BY day, month, year'
+ );
+ $holidays_sth->execute($self->{branchcode});
+
+ while ( my ( $day, $month, $year, $exception ) =
+ $holidays_sth->fetchrow )
+ {
+ my $datestring =
+ sprintf( "%04d", $year )
+ . sprintf( "%02d", $month )
+ . sprintf( "%02d", $day );
+
+ $holidays->{$datestring} = $exception ? 0 : 1;
+ }
+ $cache->set_in_cache( $key, $holidays, { expiry => 76800 } );
}
- return 0;
+ return $holidays // {};
}
-sub addDate {
+sub addDuration {
my ( $self, $startdate, $add_duration, $unit ) = @_;
- Koha::Exceptions::MissingParameter->throw("Missing mandatory option for Koha:Calendar->addDate: days_mode")
+ Koha::Exceptions::MissingParameter->throw("Missing mandatory option for Koha:Calendar->addDuration: days_mode")
unless exists $self->{days_mode};
# Default to days duration (legacy support I guess)
unless exists $self->{days_mode};
my $dow = $base_date->day_of_week;
+ # Representation fix
+ # DateTime object dow (1-7) where Monday is 1
+ # Arrays are 0-based where 0 = Sunday, not 7.
+ if ( $dow == 7 ) {
+ $dow = 0;
+ }
+
return (
# We're using Dayweek useDaysMode option
$self->{days_mode} eq 'Dayweek' &&
# It's not a permanently closed day
- !$self->{weekly_closed_days}->[$dow] == 1
+ !$self->{weekly_closed_days}->[$dow]
) ? 7 : 1;
}
my $localdt = $dt->clone();
my $day = $localdt->day;
my $month = $localdt->month;
+ my $ymd = $localdt->ymd('');
#Change timezone to "floating" before doing any calculations or comparisons
$localdt->set_time_zone("floating");
$localdt->truncate( to => 'day' );
-
- if ( $self->exception_holidays->contains($localdt) ) {
- # exceptions are not holidays
- return 0;
- }
+ return $self->_holidays->{$ymd} if defined($self->_holidays->{$ymd});
my $dow = $localdt->day_of_week;
# Representation fix
return 1;
}
- my $ymd = $localdt->ymd('') ;
- if ($self->single_holidays( $ymd ) == 1 ) {
- return 1;
- }
-
# damn have to go to work after all
return 0;
}
# are we open
$open = $c->is_holiday($dt);
# when will item be due if loan period = $dur (a DateTime::Duration object)
- $duedate = $c->addDate($dt,$dur,'days');
+ $duedate = $c->addDuration($dt,$dur,'days');
=head1 DESCRIPTION
The option branchcode is required
-=head2 addDate
+=head2 addDuration
- my $dt = $calendar->addDate($date, $dur, $unit)
+ my $dt = $calendar->addDuration($date, $dur, $unit)
C<$date> is a DateTime object representing the starting date of the interval.
Currently unit is only used to invoke Staffs return Monday at 10 am rule this
parameter will be removed when issuingrules properly cope with that
-
-=head2 single_holidays
-
-my $rc = $self->single_holidays( $ymd );
-
-Passed a $date in Ymd (yyyymmdd) format - returns 1 if date is a single_holiday, or 0 if not.
-
-
=head2 is_holiday
$yesno = $calendar->is_holiday($dt);
days. It is intended for use to calculate the due date when useDaysMode
syspref is set to either 'Datedue', 'Calendar' or 'Dayweek'.
+=head2 days_forward
+
+$datetime = $calendar->days_forward($start_dt, $to_add)
+
+Passed a Datetime and number of days, returns another Datetime representing
+the next open day after adding the passed number of days. It is intended for
+use to calculate the due date when useDaysMode syspref is set to either
+'Datedue', 'Calendar' or 'Dayweek'.
+
=head2 set_daysmode
For testing only allows the calling script to change days mode