X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=Koha%2FCalendar.pm;h=a0b642b3cc8bfea5986772e23dea9e87b468c276;hb=de69ee9a91925497ae7598f9d406dca88de32a93;hp=90069b6a8957016bb482fd9ed4327bd1bb2ae0c0;hpb=ea1aa7a0d906d583375618e37be60e9f0d62d939;p=srvgit diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm index 90069b6a89..a0b642b3cc 100644 --- a/Koha/Calendar.pm +++ b/Koha/Calendar.pm @@ -7,8 +7,8 @@ use DateTime; use DateTime::Set; use DateTime::Duration; use C4::Context; +use Koha::Cache; use Carp; -use Readonly; sub new { my ( $classname, %options ) = @_; @@ -18,10 +18,6 @@ sub new { my $o = lc $o_name; $self->{$o} = $options{$o_name}; } - if ( exists $options{TEST_MODE} ) { - $self->_mockinit(); - return $self; - } if ( !defined $self->{branchcode} ) { croak 'No branchcode argument passed to Koha::Calendar->new'; } @@ -33,28 +29,52 @@ sub _init { my $self = shift; my $branch = $self->{branchcode}; my $dbh = C4::Context->dbh(); - my $repeat_sth = $dbh->prepare( -'SELECT * from repeatable_holidays WHERE branchcode = ? AND ISNULL(weekday) = ?' + my $weekly_closed_days_sth = $dbh->prepare( +'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL' ); - $repeat_sth->execute( $branch, 0 ); + $weekly_closed_days_sth->execute( $branch ); $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ]; - Readonly::Scalar my $sunday => 7; - while ( my $tuple = $repeat_sth->fetchrow_hashref ) { + while ( my $tuple = $weekly_closed_days_sth->fetchrow_hashref ) { $self->{weekly_closed_days}->[ $tuple->{weekday} ] = 1; } - $repeat_sth->execute( $branch, 1 ); + my $day_month_closed_days_sth = $dbh->prepare( +'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL' + ); + $day_month_closed_days_sth->execute( $branch ); $self->{day_month_closed_days} = {}; - while ( my $tuple = $repeat_sth->fetchrow_hashref ) { + while ( my $tuple = $day_month_closed_days_sth->fetchrow_hashref ) { $self->{day_month_closed_days}->{ $tuple->{month} }->{ $tuple->{day} } = 1; } - my $special = $dbh->prepare( -'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = ?' + $self->{days_mode} = C4::Context->preference('useDaysMode'); + $self->{test} = 0; + return; +} + + +# FIXME: use of package-level variables for caching the holiday +# lists breaks persistance engines. As of 2013-12-10, the RM +# is allowing this with the expectation that prior to release of +# 3.16, bug 8089 will be fixed and we can switch the caching over +# to Koha::Cache. + +our $exception_holidays; + +sub exception_holidays { + my ( $self ) = @_; + my $dbh = C4::Context->dbh; + my $branch = $self->{branchcode}; + if ( $exception_holidays ) { + $self->{exception_holidays} = $exception_holidays; + return $exception_holidays; + } + my $exception_holidays_sth = $dbh->prepare( +'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1' ); - $special->execute( $branch, 1 ); + $exception_holidays_sth->execute( $branch ); my $dates = []; - while ( my ( $day, $month, $year ) = $special->fetchrow ) { + while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) { push @{$dates}, DateTime->new( day => $day, @@ -65,22 +85,61 @@ sub _init { } $self->{exception_holidays} = DateTime::Set->from_datetimes( dates => $dates ); + $exception_holidays = $self->{exception_holidays}; + return $exception_holidays; +} - $special->execute( $branch, 0 ); - $dates = []; - while ( my ( $day, $month, $year ) = $special->fetchrow ) { - push @{$dates}, - DateTime->new( - day => $day, - month => $month, - year => $year, - time_zone => C4::Context->tz() - )->truncate( to => 'day' ); +sub single_holidays { + my ( $self, $date ) = @_; + my $branchcode = $self->{branchcode}; + my $cache = Koha::Cache->get_instance(); + my $single_holidays = $cache->get_from_cache('single_holidays'); + + # $single_holidays looks like: + # { + # CPL => [ + # [0] 20131122, + # ... + # ], + # ... + # } + + unless ($single_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($branchcode); + + my @ymd_arr; + while ( my ( $day, $month, $year ) = + $single_holidays_sth->fetchrow ) + { + my $dt = DateTime->new( + day => $day, + month => $month, + year => $year, + time_zone => C4::Context->tz() + )->truncate( to => 'day' ); + push @ymd_arr, $dt->ymd(''); + } + $single_holidays->{$br} = \@ymd_arr; + } # br + $cache->set_in_cache( 'single_holidays', $single_holidays, + 76800 ) #24 hrs ; } - $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates ); - $self->{days_mode} = C4::Context->preference('useDaysMode'); - $self->{test} = 0; - return; + my $holidays = ( $single_holidays->{$branchcode} ); + for my $hols (@$holidays ) { + return 1 if ( $date == $hols ) #match ymds; + } + return 0; } sub addDate { @@ -96,7 +155,7 @@ sub addDate { if ( $unit eq 'hours' ) { # Fixed for legacy support. Should be set as a branch parameter - Readonly::Scalar my $return_by_hour => 10; + my $return_by_hour = 10; $dt = $self->addHours($startdate, $add_duration, $return_by_hour); } else { @@ -136,6 +195,8 @@ sub addDays { my ( $self, $startdate, $days_duration ) = @_; my $base_date = $startdate->clone(); + $self->{days_mode} ||= q{}; + if ( $self->{days_mode} eq 'Calendar' ) { # use the calendar to skip all days the library is closed # when adding @@ -162,6 +223,7 @@ sub addDays { # Datedue, then use the calendar to push # the date to the next open day if holiday if ( $self->is_holiday($base_date) ) { + if ( $days_duration->is_negative() ) { $base_date = $self->prev_open_day($base_date); } else { @@ -176,20 +238,23 @@ sub addDays { sub is_holiday { my ( $self, $dt ) = @_; + my $localdt = $dt->clone(); my $day = $localdt->day; my $month = $localdt->month; $localdt->truncate( to => 'day' ); - if ( $self->{exception_holidays}->contains($localdt) ) { + + if ( $self->exception_holidays->contains($localdt) ) { # exceptions are not holidays return 0; } my $dow = $localdt->day_of_week; # Representation fix - # TODO: Shouldn't we shift the rest of the $dow also? + # DateTime object dow (1-7) where Monday is 1 + # Arrays are 0-based where 0 = Sunday, not 7. if ( $dow == 7 ) { $dow = 0; } @@ -202,7 +267,8 @@ sub is_holiday { return 1; } - if ( $self->{single_holidays}->contains($localdt) ) { + my $ymd = $localdt->ymd('') ; + if ($self->single_holidays( $ymd ) == 1 ) { return 1; } @@ -241,6 +307,13 @@ sub days_between { my $start_dt = shift; my $end_dt = shift; + if ( $start_dt->compare($end_dt) > 0 ) { + # swap dates + my $int_dt = $end_dt; + $end_dt = $start_dt; + $start_dt = $int_dt; + } + # start and end should not be closed days my $days = $start_dt->delta_days($end_dt)->delta_days; @@ -284,31 +357,6 @@ sub hours_between { } -sub _mockinit { - my $self = shift; - $self->{weekly_closed_days} = [ 1, 0, 0, 0, 0, 0, 0 ]; # Sunday only - $self->{day_month_closed_days} = { 6 => { 16 => 1, } }; - my $dates = []; - $self->{exception_holidays} = - DateTime::Set->from_datetimes( dates => $dates ); - my $special = DateTime->new( - year => 2011, - month => 6, - day => 1, - time_zone => 'Europe/London', - ); - push @{$dates}, $special; - $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates ); - - # if not defined, days_mode defaults to 'Calendar' - if ( !defined($self->{days_mode}) ) { - $self->{days_mode} = 'Calendar'; - } - - $self->{test} = 1; - return; -} - sub set_daysmode { my ( $self, $mode ) = @_; @@ -326,17 +374,6 @@ sub clear_weekly_closed_days { return; } -sub add_holiday { - my $self = shift; - my $new_dt = shift; - my @dt = $self->{single_holidays}->as_list; - push @dt, $new_dt; - $self->{single_holidays} = - DateTime::Set->from_datetimes( dates => \@dt ); - - return; -} - 1; __END__ @@ -413,6 +450,13 @@ 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);