Bug 14608: Add a page to configure shared statistics
[koha.git] / Koha / Calendar.pm
index 90069b6..f6cb58c 100644 (file)
@@ -7,8 +7,8 @@ use DateTime;
 use DateTime::Set;
 use DateTime::Duration;
 use C4::Context;
 use DateTime::Set;
 use DateTime::Duration;
 use C4::Context;
+use Koha::Caches;
 use Carp;
 use Carp;
-use Readonly;
 
 sub new {
     my ( $classname, %options ) = @_;
 
 sub new {
     my ( $classname, %options ) = @_;
@@ -18,10 +18,6 @@ sub new {
         my $o = lc $o_name;
         $self->{$o} = $options{$o_name};
     }
         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';
     }
     if ( !defined $self->{branchcode} ) {
         croak 'No branchcode argument passed to Koha::Calendar->new';
     }
@@ -33,54 +29,109 @@ sub _init {
     my $self       = shift;
     my $branch     = $self->{branchcode};
     my $dbh        = C4::Context->dbh();
     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 ];
     $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;
     }
         $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} = {};
     $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;
     }
 
         $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;
+}
+
+sub exception_holidays {
+    my ( $self ) = @_;
+
+    my $cache  = Koha::Caches->get_instance();
+    my $cached = $cache->get_from_cache('exception_holidays');
+    return $cached if $cached;
+
+    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'
     );
     );
-    $special->execute( $branch, 1 );
+    $exception_holidays_sth->execute( $branch );
     my $dates = [];
     my $dates = [];
-    while ( my ( $day, $month, $year ) = $special->fetchrow ) {
+    while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) {
         push @{$dates},
           DateTime->new(
             day       => $day,
             month     => $month,
             year      => $year,
         push @{$dates},
           DateTime->new(
             day       => $day,
             month     => $month,
             year      => $year,
-            time_zone => C4::Context->tz()
+            time_zone => "floating",
           )->truncate( to => 'day' );
     }
     $self->{exception_holidays} =
       DateTime::Set->from_datetimes( dates => $dates );
           )->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};
+}
 
 
-    $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::Caches->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($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 ;
     }
     }
-    $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 {
 }
 
 sub addDate {
@@ -96,7 +147,7 @@ sub addDate {
 
     if ( $unit eq 'hours' ) {
         # Fixed for legacy support. Should be set as a branch parameter
 
     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 {
 
         $dt = $self->addHours($startdate, $add_duration, $return_by_hour);
     } else {
@@ -136,6 +187,8 @@ sub addDays {
     my ( $self, $startdate, $days_duration ) = @_;
     my $base_date = $startdate->clone();
 
     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
     if ( $self->{days_mode} eq 'Calendar' ) {
         # use the calendar to skip all days the library is closed
         # when adding
@@ -162,6 +215,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) ) {
             # 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 {
                 if ( $days_duration->is_negative() ) {
                     $base_date = $self->prev_open_day($base_date);
                 } else {
@@ -176,20 +230,25 @@ sub addDays {
 
 sub is_holiday {
     my ( $self, $dt ) = @_;
 
 sub is_holiday {
     my ( $self, $dt ) = @_;
+
     my $localdt = $dt->clone();
     my $day   = $localdt->day;
     my $month = $localdt->month;
 
     my $localdt = $dt->clone();
     my $day   = $localdt->day;
     my $month = $localdt->month;
 
+    #Change timezone to "floating" before doing any calculations or comparisons
+    $localdt->set_time_zone("floating");
     $localdt->truncate( to => 'day' );
 
     $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
         # 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;
     }
     if ( $dow == 7 ) {
         $dow = 0;
     }
@@ -202,7 +261,8 @@ sub is_holiday {
         return 1;
     }
 
         return 1;
     }
 
-    if ( $self->{single_holidays}->contains($localdt) ) {
+    my $ymd   = $localdt->ymd('')  ;
+    if ($self->single_holidays(  $ymd  ) == 1 ) {
         return 1;
     }
 
         return 1;
     }
 
@@ -241,6 +301,13 @@ sub days_between {
     my $start_dt = shift;
     my $end_dt   = shift;
 
     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;
 
     # start and end should not be closed days
     my $days = $start_dt->delta_days($end_dt)->delta_days;
@@ -284,31 +351,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 ) = @_;
 
 sub set_daysmode {
     my ( $self, $mode ) = @_;
 
@@ -326,17 +368,6 @@ sub clear_weekly_closed_days {
     return;
 }
 
     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__
 
 1;
 __END__
 
@@ -344,10 +375,6 @@ __END__
 
 Koha::Calendar - Object containing a branches calendar
 
 
 Koha::Calendar - Object containing a branches calendar
 
-=head1 VERSION
-
-This documentation refers to Koha::Calendar version 0.0.1
-
 =head1 SYNOPSIS
 
   use Koha::Calendar
 =head1 SYNOPSIS
 
   use Koha::Calendar
@@ -413,6 +440,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
 
 
 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);
 =head2 is_holiday
 
 $yesno = $calendar->is_holiday($dt);