From e3969d6af74a8eb333a768f7bde5ee0f297413cc Mon Sep 17 00:00:00 2001 From: Mehdi Hamidi Date: Thu, 30 Mar 2017 09:06:48 -0400 Subject: [PATCH] Bug 17015 - DiscreteCalendar UI, Back-End and necessary scripts --- Koha/DiscreteCalendar.pm | 990 +++++++++++++++++++++ Koha/Schema/Result/DiscreteCalendar.pm | 111 +++ .../bug_17015_part1_create_discrete_calendar.sql | 14 + .../bug_17015_part2_fill_discrete_calendar.perl | 168 ++++ .../prog/en/modules/tools/discrete_calendar.tt | 663 ++++++++++++++ misc/cronjobs/add_days_discrete_calendar.pl | 125 +++ tools/discrete_calendar.pl | 152 ++++ 7 files changed, 2223 insertions(+) create mode 100644 Koha/DiscreteCalendar.pm create mode 100644 Koha/Schema/Result/DiscreteCalendar.pm create mode 100644 installer/data/mysql/atomicupdate/bug_17015_part1_create_discrete_calendar.sql create mode 100755 installer/data/mysql/atomicupdate/bug_17015_part2_fill_discrete_calendar.perl create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/discrete_calendar.tt create mode 100755 misc/cronjobs/add_days_discrete_calendar.pl create mode 100755 tools/discrete_calendar.pl diff --git a/Koha/DiscreteCalendar.pm b/Koha/DiscreteCalendar.pm new file mode 100644 index 0000000..39fe5f9 --- /dev/null +++ b/Koha/DiscreteCalendar.pm @@ -0,0 +1,990 @@ +package Koha::DiscreteCalendar; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +#####Sets holiday periods for each branch. Datedues will be extended if branch is closed -TG +use strict; +use warnings; + +use CGI qw ( -utf8 ); +use Carp; +use DateTime; +use DateTime::Format::Strptime; + +use C4::Context; +use C4::Output; +use Koha::Database; +use Koha::DateUtils; + +sub new { + my ( $classname, %options ) = @_; + my $self = {}; + bless $self, $classname; + for my $o_name ( keys %options ) { + my $o = lc $o_name; + $self->{$o} = $options{$o_name}; + } + if ( !defined $self->{branchcode} ) { + croak 'No branchcode argument passed to Koha::DiscreteCalendar->new'; + } + $self->_init(); + + return $self; +} + +sub _init { + my $self = shift; + $self->{days_mode} = C4::Context->preference('useDaysMode'); + #If the branchcode doesn't exist we use the default calendar. + my $schema = Koha::Database->new->schema; + my $branchcode = $self->{branchcode}; + my $dtf = $schema->storage->datetime_parser; + my $today = $dtf->format_datetime(DateTime->today); + my $rs = $schema->resultset('DiscreteCalendar')->single( + { + branchcode => $branchcode, + date => $today + } + ); + #use default if no calendar is found + if (!$rs){ + $self->{branchcode} = 'DFLT'; + $self->{no_branch_selected} = 1; + } + +} + +sub getDatesInfo { + my $self = shift; + my $branchcode = $self->{branchcode}; + my @datesInfos =(); + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode + }, + { + select => [ 'date', { DATE => 'date' } ], + as => [qw/ date date /], + columns =>[ qw/ holidaytype openhour closehour note/] + }, + ); + + while (my $date = $rs->next()){ + my $outputdate = dt_from_string( $date->date(), 'iso'); + $outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); + push @datesInfos, { + date => $date->date(), + outputdate => $outputdate, + holidaytype => $date->holidaytype() , + openhour => $date->openhour(), + closehour => $date->closehour(), + note => $date->note() + }; + } + + return @datesInfos; +} +#This methode will copy everything from a given branch found to the new branch +sub add_new_branch { + my ($self, $copyBranch, $newBranch) = @_; + $copyBranch = 'DFLT' unless $copyBranch; + my $schema = Koha::Database->new->schema; + + my $branch_rs = $schema->resultset('DiscreteCalendar')->search({ + branchcode => $copyBranch + }); + + while(my $row = $branch_rs->next()){ + $schema->resultset('DiscreteCalendar')->create({ + date => $row->date(), + branchcode => $newBranch, + isopened => $row->isopened(), + holidaytype => $row->holidaytype(), + openhour => $row->openhour(), + closehour => $row->closehour(), + }); + } + +} +#DiscreteCalendar data transfer object (DTO) +sub get_date_info { + my ($self, $date) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + #String dates for Database usage + my $date_string = $dtf->format_datetime($date); + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + select => [ 'date', { DATE => 'date' } ], + as => [qw/ date date /], + where => \['DATE(?) = date', $date_string ], + columns =>[ qw/ branchcode holidaytype openhour closehour note/] + }, + ); + my $dateDTO; + while (my $date = $rs->next()){ + $dateDTO = { + date => $date->date(), + branchcode => $date->branchcode(), + holidaytype => $date->holidaytype() , + openhour => $date->openhour(), + closehour => $date->closehour(), + note => $date->note() + }; + } + + return $dateDTO; +} + + +sub getMaxDate { + my $self = shift; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode + }, + { + select => [{ MAX => 'date' } ], + as => [qw/ max /], + } + ); + + return $rs->next()->get_column('max'); +} + +sub getMinDate { + my $self = shift; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode + }, + { + select => [{ MIN => 'date' } ], + as => [qw/ min /], + } + ); + + return $rs->next()->get_column('min'); +} + + +sub get_unique_holidays { + my $self = shift; + my $branchcode = $self->{branchcode}; + my @single_holidays; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + holidaytype => 'E' + }, + { + select => [{ DATE => 'date' }, 'note' ], + as => [qw/ date note/], + } + ); + while (my $date = $rs->next()){ + my $outputdate = dt_from_string($date->date(), 'iso'); + $outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); + push @single_holidays, { + date => $date->date(), + outputdate => $outputdate, + note => $date->note() + } + } + + return @single_holidays; +} + +sub get_float_holidays { + my $self = shift; + my $branchcode = $self->{branchcode}; + my @float_holidays; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + holidaytype => 'F' + }, + { + select => [{ DATE => 'date' }, 'note' ], + as => [qw/ date note/], + } + ); + while (my $date = $rs->next()){ + my $outputdate = dt_from_string($date->date(), 'iso'); + $outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); + push @float_holidays, { + date => $date->date(), + outputdate => $outputdate, + note => $date->note() + } + } + + return @float_holidays; +} + +sub get_need_valdation_holidays { + my $self = shift; + my $branchcode = $self->{branchcode}; + my @need_validation_holidays; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + holidaytype => 'N' + }, + { + select => [{ DATE => 'date' }, 'note' ], + as => [qw/ date note/], + } + ); + while (my $date = $rs->next()){ + my $outputdate = dt_from_string($date->date(), 'iso'); + $outputdate = output_pref( { dt => $outputdate, dateonly => 1 } ); + push @need_validation_holidays, { + date => $date->date(), + outputdate => $outputdate, + note => $date->note() + } + } + + return @need_validation_holidays; +} + +sub get_repeatable_holidays { + my $self = shift; + my $branchcode = $self->{branchcode}; + my @repeatable_holidays; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + holidaytype => 'R', + + }, + { + select => \[ 'distinct DAY(date), MONTH(date), note'], + as => [qw/ day month note/], + } + ); + + while (my $date = $rs->next()){ + push @repeatable_holidays, { + day=> $date->get_column('day'), + month => $date->get_column('month'), + note => $date->note() + }; + } + + return @repeatable_holidays; +} + +sub get_week_days_holidays { + my $self = shift; + my $branchcode = $self->{branchcode}; + my @week_days; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + holidaytype => 'W', + branchcode => $branchcode, + }, + { + select => [{ DAYOFWEEK => 'date'}, 'note'], + as => [qw/ weekday note /], + distinct => 1, + } + ); + + while (my $date = $rs->next()){ + push @week_days, { + weekday => ($date->get_column('weekday') -1), + note => $date->note() + }; + } + + return @week_days; +} +=head1 edit_holiday + +Modifies a date or a range of dates + +C<$title> Is the title to be modified for the holiday formed by $year/$month/$day. + +C<$weekday> Is the day of week for the holiday + +C<$holidaytype> Is the type of the holiday : + E : Exception holiday, single day. + F : Floating holiday, different day each year. + N : Needs validation, copied float holiday from the past + R : Repeatable holiday, repeated on same date. + W : Weekly holiday, same day of the week. + +C<$openHour> Is the opening hour. +C<$closeHour> Is the closing hour. +C<$startDate> Is the start of the range of dates. +C<$endDate> Is the end of the range of dates. +=back +=cut + +sub edit_holiday { + my ($self, $title, $weekday, $holidaytype, $openHour, $closeHour, $startDate, $endDate, $deleteType, $today) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + #String dates for Database usage + my $startDate_String = $dtf->format_datetime($startDate); + my $endDate_String = $dtf->format_datetime($endDate); + $today = DateTime->today unless $today; + $today = $dtf->format_datetime($today); + + my %updateValues = ( + isopened => 0, + note => $title, + holidaytype => $holidaytype, + ); + $updateValues{openhour} = $openHour if $openHour ne ''; + $updateValues{closehour} = $closeHour if $closeHour ne ''; + + if($holidaytype eq 'W') { + #Insert/Update weekly holidays + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \[ 'DAYOFWEEK(date) = ? and date >= ?', $weekday, $today], + } + ); + + while (my $date = $rs->next()){ + $date->update(\%updateValues); + } + }elsif ($holidaytype eq 'E' || $holidaytype eq 'F' || $holidaytype eq 'N') { + #Insert/Update Exception Float and Needs Validation holidays + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \['date between DATE(?) and DATE(?) and date >= ?',$startDate_String, $endDate_String, $today] + } + ); + while (my $date = $rs->next()){ + $date->update(\%updateValues); + } + + }elsif ($holidaytype eq 'R') { + #Insert/Update repeatable holidays + my $parser = DateTime::Format::Strptime->new( + pattern => '%m-%d', + on_error => 'croak', + ); + #Format the dates to have only month-day ex: 01-04 for January 4th + $startDate = $parser->format_datetime($startDate); + $endDate = $parser->format_datetime($endDate); + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \["(DATE_FORMAT(date,'\%m-\%d') BETWEEN ? AND ? ) AND date >= ?", $startDate, $endDate, $today], + } + ); + while (my $date = $rs->next()){ + $date->update(\%updateValues); + } + + }else { + #Delete/Update date(s) + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \['date between DATE(?) and DATE(?) and date >= ?',$startDate_String, $endDate_String, $today], + } + ); + #If none, the date(s) will be normal days, else, + if($holidaytype eq 'none'){ + $updateValues{holidaytype} =''; + $updateValues{isopened} =1; + }else{ + delete $updateValues{holidaytype}; + } + while (my $date = $rs->next()){ + if($deleteType){ + if($date->holidaytype() eq 'W' && $startDate_String eq $endDate_String){ + $self->remove_weekly_holidays($weekday, \%updateValues, $today); + }elsif($date->holidaytype() eq 'R'){ + $self->remove_repeatable_holidays($startDate, $endDate, \%updateValues, $today); + } + }else{ + $date->update(\%updateValues); + } + } + } +} + +sub remove_weekly_holidays { + my ($self, $weekday, $updateValues, $today) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 0, + holidaytype => 'W' + }, + { + where => \["DAYOFWEEK(date) = ? and date >= ?", $weekday,$today], + } + ); + + while (my $date = $rs->next()){ + $date->update($updateValues); + } +} + +sub remove_repeatable_holidays { + my ($self, $startDate, $endDate, $updateValues, $today) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $parser = DateTime::Format::Strptime->new( + pattern => '%m-%d', + on_error => 'croak', + ); + #Format the dates to have only month-day ex: 01-04 for January 4th + $startDate = $parser->format_datetime($startDate); + $endDate = $parser->format_datetime($endDate); + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 0, + holidaytype => 'R', + }, + { + where => \["(DATE_FORMAT(date,'\%m-\%d') BETWEEN ? AND ? ) AND date >= ?", $startDate, $endDate, $today], + } + ); + + while (my $date = $rs->next()){ + $date->update($updateValues); + } +} + +sub copyToBranch { + my ($self,$newBranch) =@_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + + my $copyFrom = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode + }, + { + columns => [ qw/ date isopened note holidaytype openhour closehour /] + } + ); + while (my $copyDate = $copyFrom->next()){ + my $copyTo = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $newBranch, + date => $copyDate->date(), + }, + { + columns => [ qw/ date branchcode isopened note holidaytype openhour closehour /] + } + ); + #if the date does not exist in the copyTO branch, than skip it. + if($copyTo->count ==0){ + next; + } + $copyTo->next()->update({ + isopened => $copyDate->isopened(), + holidaytype => $copyDate->holidaytype(), + note => $copyDate->note(), + openhour => $copyDate->openhour(), + closehour => $copyDate->closehour() + }); + } +} + +sub isOpened { + my($self, $date) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + $date= $dtf->format_datetime($date); + #if the date is not found + my $isOpened = -1; + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \['date = DATE(?)', $date] + } + ); + $isOpened = $rs->next()->isopened() if $rs->count() != 0; + + return $isOpened; +} + +sub is_holiday { + my($self, $date) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + $date= $dtf->format_datetime($date); + #if the date is not found + my $isHoliday = -1; + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \['date = DATE(?)', $date] + } + ); + + if($rs->count() != 0){ + $isHoliday = 0 if $rs->first()->isopened(); + $isHoliday = 1 if !$rs->first()->isopened(); + } + + return $isHoliday; +} + +sub copyHoliday { + my ($self, $from_startDate, $from_endDate, $to_startDate, $to_endDate, $daysnumber) = @_; + my $branchcode = $self->{branchcode}; + my $copyFromType = $from_startDate && $from_endDate eq '' ? 'oneDay': 'range'; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + + if ($copyFromType eq 'oneDay'){ + my $where; + $to_startDate = $dtf->format_datetime($to_startDate); + if ($to_startDate && $to_endDate) { + $to_endDate = $dtf->format_datetime($to_endDate); + $where = \["date between ? and ?", $to_startDate, $to_endDate]; + } else { + $where = \['date = ?', $to_startDate]; + } + + $from_startDate = $dtf->format_datetime($from_startDate); + my $fromDate = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + date => $from_startDate + } + ); + my $toDates = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => $where + } + ); + + my $copyDate = $fromDate->next(); + while (my $date = $toDates->next()){ + $date->update({ + isopened => $copyDate->isopened(), + holidaytype => $copyDate->holidaytype(), + note => $copyDate->note(), + openhour => $copyDate->openhour(), + closehour => $copyDate->closehour() + }) + } + + }else{ + my $endDate = dt_from_string($from_endDate); + $to_startDate = $dtf->format_datetime($to_startDate); + $to_endDate = $dtf->format_datetime($to_endDate); + if($daysnumber ==7){ + for (my $tempDate = $from_startDate->clone(); $tempDate <= $endDate;$tempDate->add(days => 1)){ + my $formatedDate = $dtf->format_datetime($tempDate); + my $fromDate = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + date => $formatedDate, + }, + { + select => [{ DAYOFWEEK => 'date' }], + as => [qw/ weekday /], + columns =>[ qw/ holidaytype note openhour closehour note/] + } + ); + my $copyDate = $fromDate->next(); + my $weekday = $copyDate->get_column('weekday'); + + my $toDate = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + + }, + { + where => \['date between ? and ? and DAYOFWEEK(date) = ?',$to_startDate, $to_endDate, $weekday] + } + ); + my $copyToDate = $toDate->next(); + $copyToDate->update({ + isopened => $copyDate->isopened(), + holidaytype => $copyDate->holidaytype(), + note => $copyDate->note(), + openhour => $copyDate->openhour(), + closehour => $copyDate->closehour() + }); + + } + }else{ + my $to_startDate = dt_from_string($to_startDate); + my $to_endDate = dt_from_string($to_endDate); + for (my $tempDate = $from_startDate->clone(); $tempDate <= $endDate;$tempDate->add(days => 1)){ + my $from_formatedDate = $dtf->format_datetime($tempDate); + my $fromDate = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + date => $from_formatedDate, + }, + { + order_by => { -asc => 'date' } + } + ); + my $to_formatedDate = $dtf->format_datetime($to_startDate); + my $toDate = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + date => $to_formatedDate + }, + { + order_by => { -asc => 'date' } + } + ); + my $copyDate = $fromDate->next(); + $toDate->next()->update({ + isopened => $copyDate->isopened(), + holidaytype => $copyDate->holidaytype(), + note => $copyDate->note(), + openhour => $copyDate->openhour(), + closehour => $copyDate->closehour() + }); + $to_startDate->add(days =>1); + } + } + + + } +} + +sub days_between { + my ($self, $start_date, $end_date, ) = @_; + my $branchcode = $self->{branchcode}; + + if ( $start_date->compare($end_date) > 0 ) { + # swap dates + my $int_dt = $end_date; + $end_date = $start_date; + $start_date = $int_dt; + } + + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + $start_date = $dtf->format_datetime($start_date); + $end_date = $dtf->format_datetime($end_date); + + my $days_between = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 1, + }, + { + where => \['date >= date(?) and date < date(?)',$start_date, $end_date] + } + ); + + return DateTime::Duration->new( days => $days_between->count()); +} + +sub next_open_day { + my ( $self, $date ) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + $date = $dtf->format_datetime($date); + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 1, + }, + { + where => \['date > date(?)', $date], + order_by => { -asc => 'date' }, + rows => 1 + } + ); + return dt_from_string( $rs->next()->date(), 'iso'); +} + +sub prev_open_day { + my ( $self, $date ) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + $date = $dtf->format_datetime($date); + + my $rs = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 1, + }, + { + where => \['date < date(?)', $date], + order_by => { -desc => 'date' }, + rows => 1 + } + ); + return dt_from_string( $rs->next()->date(), 'iso'); +} + +sub days_forward { + my $self = shift; + my $start_dt = shift; + my $num_days = shift; + + return $start_dt unless $num_days > 0; + + my $base_dt = $start_dt->clone(); + + while ($num_days--) { + $base_dt = $self->next_open_day($base_dt); + } + + return $base_dt; +} + +sub hours_between { + my ($self, $start_dt, $end_dt) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + my $start_date = $start_dt->clone(); + my $end_date = $end_dt->clone(); + my $duration = $end_date->delta_ms($start_date); + $start_date->truncate( to => 'day' ); + $end_date->truncate( to => 'day' ); + + # NB this is a kludge in that it assumes all days are 24 hours + # However for hourly loans the logic should be expanded to + # take into account open/close times then it would be a duration + # of library open hours + my $skipped_days = 0; + $start_date = $dtf->format_datetime($start_date); + $end_date = $dtf->format_datetime($end_date); + my $hours_between = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 0 + }, + { + where => \[ 'date between ? and ?', $start_date, $end_date], + } + ); + + if ($skipped_days = $hours_between->count()) { + $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days)); + } + + return $duration; +} + +sub open_hours_between { + my ($self, $start_date, $end_date) = @_; + my $branchcode = $self->{branchcode}; + my $schema = Koha::Database->new->schema; + my $dtf = $schema->storage->datetime_parser; + $start_date = $dtf->format_datetime($start_date); + $end_date = $dtf->format_datetime($end_date); + + my $working_hours_between = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 1, + }, + { + select => \['sum(time_to_sec(timediff(closehour, openhour)) / 3600)'], + as => [qw /hours_between/], + where => \['date BETWEEN DATE(?) AND DATE(?)', $start_date, $end_date] + } + ); + + my $loan_day = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \['date = DATE(?)', $start_date], + } + ); + + my $return_day = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + }, + { + where => \['date = DATE(?)', $end_date], + } + ); + + #Capture the time portion of the date + $start_date =~ /\s(.*)/; + my $loan_date_time = $1; + $end_date =~ /\s(.*)/; + my $return_date_time = $1; + + my $not_used_hours = $schema->resultset('DiscreteCalendar')->search( + { + branchcode => $branchcode, + isopened => 1, + }, + { + select => \[ '(time_to_sec(timediff(?, ?)) + time_to_sec(timediff(?, ?)) ) / 3600', $return_day->next()->closehour(), $return_date_time, $loan_date_time, $loan_day->next()->openhour()], + as => [qw /not_used_hours/], + } + ); + + return ($working_hours_between->next()->get_column('hours_between') - $not_used_hours->next()->get_column('not_used_hours')); +} +sub addDate { + my ( $self, $startdate, $add_duration, $unit ) = @_; + + # Default to days duration (legacy support I guess) + if ( ref $add_duration ne 'DateTime::Duration' ) { + $add_duration = DateTime::Duration->new( days => $add_duration ); + } + + $unit ||= 'days'; # default days ? + my $dt; + + if ( $unit eq 'hours' ) { + # Fixed for legacy support. Should be set as a branch parameter + my $return_by_hour = 10; + + $dt = $self->addHours($startdate, $add_duration, $return_by_hour); + } else { + # days + $dt = $self->addDays($startdate, $add_duration); + } + + return $dt; +} + +sub addHours { + my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_; + my $base_date = $startdate->clone(); + + $base_date->add_duration($hours_duration); + + # If we are using the calendar behave for now as if Datedue + # was the chosen option (current intended behaviour) + + if ( $self->{days_mode} ne 'Days' && + $self->is_holiday($base_date) ) { + + if ( $hours_duration->is_negative() ) { + $base_date = $self->prev_open_day($base_date); + } else { + $base_date = $self->next_open_day($base_date); + } + + $base_date->set_hour($return_by_hour); + + } + + return $base_date; +} + +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 + my $days = abs $days_duration->in_units('days'); + + if ( $days_duration->is_negative() ) { + while ($days) { + $base_date = $self->prev_open_day($base_date); + --$days; + } + } else { + while ($days) { + $base_date = $self->next_open_day($base_date); + --$days; + } + } + + } else { # Days or Datedue + # use straight days, then use calendar to push + # the date to the next open day if Datedue + $base_date->add_duration($days_duration); + + if ( $self->{days_mode} eq 'Datedue' ) { + # Datedue, then use the calendar to push + # the date to the next open day if holiday + if (!$self->isOpened($base_date) ) { + + if ( $days_duration->is_negative() ) { + $base_date = $self->prev_open_day($base_date); + } else { + $base_date = $self->next_open_day($base_date); + } + } + } + } + + return $base_date; +} + +1; diff --git a/Koha/Schema/Result/DiscreteCalendar.pm b/Koha/Schema/Result/DiscreteCalendar.pm new file mode 100644 index 0000000..8b85e67 --- /dev/null +++ b/Koha/Schema/Result/DiscreteCalendar.pm @@ -0,0 +1,111 @@ +use utf8; +package Koha::Schema::Result::DiscreteCalendar; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::DiscreteCalendar + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("discrete_calendar"); + +=head1 ACCESSORS + +=head2 date + + data_type: 'datetime' + datetime_undef_if_invalid: 1 + is_nullable: 0 + +=head2 branchcode + + data_type: 'varchar' + is_nullable: 0 + size: 10 + +=head2 isopened + + data_type: 'tinyint' + default_value: 1 + is_nullable: 1 + +=head2 holidaytype + + data_type: 'varchar' + default_value: (empty string) + is_nullable: 1 + size: 1 + +=head2 note + + data_type: 'varchar' + default_value: (empty string) + is_nullable: 1 + size: 30 + +=head2 openhour + + data_type: 'time' + is_nullable: 0 + +=head2 closehour + + data_type: 'time' + is_nullable: 0 + +=cut + +__PACKAGE__->add_columns( + "date", + { + data_type => "datetime", + datetime_undef_if_invalid => 1, + is_nullable => 0, + }, + "branchcode", + { data_type => "varchar", is_nullable => 0, size => 10 }, + "isopened", + { data_type => "tinyint", default_value => 1, is_nullable => 1 }, + "holidaytype", + { data_type => "varchar", default_value => "", is_nullable => 1, size => 1 }, + "note", + { data_type => "varchar", default_value => "", is_nullable => 1, size => 30 }, + "openhour", + { data_type => "time", is_nullable => 0 }, + "closehour", + { data_type => "time", is_nullable => 0 }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("branchcode", "date"); + + +# Created by DBIx::Class::Schema::Loader v0.07045 @ 2017-04-19 10:07:41 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:wtctW8ZzCkyCZFZmmavFEw + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/installer/data/mysql/atomicupdate/bug_17015_part1_create_discrete_calendar.sql b/installer/data/mysql/atomicupdate/bug_17015_part1_create_discrete_calendar.sql new file mode 100644 index 0000000..28399e1 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_17015_part1_create_discrete_calendar.sql @@ -0,0 +1,14 @@ +-- Bugzilla 17015 +-- New koha calendar +-- Create discrete_calendar table to keep track of library day's information + +CREATE TABLE `discrete_calendar` ( + `date` datetime NOT NULL, + `branchcode` varchar(10) NOT NULL, + `isopened` tinyint(1) DEFAULT 1, + `holidaytype` varchar(1) DEFAULT '', + `note` varchar(30) DEFAULT '', + `openhour` time NOT NULL, + `closehour` time NOT NULL, + PRIMARY KEY (`branchcode`,`date`) +); diff --git a/installer/data/mysql/atomicupdate/bug_17015_part2_fill_discrete_calendar.perl b/installer/data/mysql/atomicupdate/bug_17015_part2_fill_discrete_calendar.perl new file mode 100755 index 0000000..fdfbe94 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_17015_part2_fill_discrete_calendar.perl @@ -0,0 +1,168 @@ +#!/usr/bin/perl + +# +# Script that fills the discrete_calendar table with dates, using the other date-related tables +# +use strict; +use warnings; +use DateTime; +use DateTime::Format::Strptime; +use Getopt::Long; +use C4::Context; + +# Options +my $help = 0; +my $daysInFuture = 365; +GetOptions ( + 'days|?|d=i' => \$daysInFuture, + 'help|?|h' => \$help); +my $usage = << 'ENDUSAGE'; + +Script that manages the discrete_calendar table. + +This script has the following parameters : + --days --d : how many days in the future will be created, by default it's 365 + -h --help: this message + --generate: fills discrete_calendar table with dates from the last two years and the next one + +ENDUSAGE + +if ($help) { + print $usage; + exit; +} +my $dbh = C4::Context->dbh; +$dbh->{AutoCommit} = 0; +$dbh->{RaiseError} = 1; + +my $currentDate = DateTime->today; + +# two years ago +my $startDate = DateTime->new( +day => $currentDate->day(), +month => $currentDate->month(), +year => $currentDate->year()-2, +time_zone => C4::Context->tz() +)->truncate( to => 'day' ); + +# a year into the future +my $endDate = DateTime->new( +day => $currentDate->day(), +month => $currentDate->month(), +year => $currentDate->year(), +time_zone => C4::Context->tz() +)->truncate( to => 'day' ); +$endDate->add(days => $daysInFuture); + +#Added a default (standard) branch. +my $add_default_branch = 'INSERT IGNORE INTO branches (branchname, branchcode) VALUES(?,?)'; +my $add_Branch_Sth = $dbh->prepare($add_default_branch); +$add_Branch_Sth->execute('Default', 'DFLT'); +# finds branches; +my $selectBranchesSt = 'SELECT branchcode FROM branches'; +my $selectBranchesSth = $dbh->prepare($selectBranchesSt); +$selectBranchesSth->execute(); +my @branches = (); +while ( my $branchCode = $selectBranchesSth->fetchrow_array ) { + + push @branches,$branchCode; +} + +# finds what days are closed for each branch +my %repeatableHolidaysPerBranch = (); +my %specialHolidaysPerBranch = (); +my $selectWeeklySt; +my $selectWeeklySth; + +foreach my $branch (@branches){ + + $selectWeeklySt = 'SELECT weekday, title, day, month FROM repeatable_holidays WHERE branchcode = ?'; + $selectWeeklySth = $dbh->prepare($selectWeeklySt); + $selectWeeklySth->execute($branch); + + my @weeklyHolidays = (); + + while ( my ($weekDay, $title, $day, $month) = $selectWeeklySth->fetchrow_array ) { + push @weeklyHolidays,{weekday => $weekDay, title => $title, day => $day, month => $month}; + + } + + $repeatableHolidaysPerBranch{$branch} = \@weeklyHolidays; + + my $selectSpecialHolidayDateSt = 'SELECT day,month,year,title FROM special_holidays WHERE branchcode = ? AND isexception = 0'; + my $specialHolidayDatesSth = $dbh->prepare($selectSpecialHolidayDateSt); + $specialHolidayDatesSth -> execute($branch); + # Tranforms dates from specialHolidays table in DateTime for our new table + my @specialHolidayDates = (); + while ( my ($day, $month, $year, $title) = $specialHolidayDatesSth->fetchrow_array ) { + + my $specialHolidayDate = DateTime->new( + day => $day, + month => $month, + year => $year, + time_zone => C4::Context->tz() + )->truncate( to => 'day' ); + push @specialHolidayDates,{date=>$specialHolidayDate, title=> $title}; + } + + $specialHolidaysPerBranch{$branch} = \@specialHolidayDates; +} +# Fills table with dates and sets 'isopened' according to the branch's weekly restrictions (repeatable_holidays) +my $insertDateSt; +my $insertDateSth; + +# Loop that does everything in the world +for (my $tempDate = $startDate->clone(); $tempDate <= $endDate;$tempDate->add(days => 1)){ + foreach my $branch (@branches){ + my $dayOfWeek = $tempDate->day_of_week; + # Representation fix + # DateTime object dow (1-7) where Monday is 1 + # Arrays are 0-based where 0 = Sunday, not 7. + $dayOfWeek -=1 unless $dayOfWeek ==7; + $dayOfWeek =0 if $dayOfWeek ==7; + + my $openhour = "09:00:00"; + my $closehour = "17:00:00"; + + # Finds closed days + my $isOpened =1; + my $specialDescription = ""; + my $holidaytype =''; + $dayOfWeek = $tempDate->day_of_week; + foreach my $holidayWeekDay (@{$repeatableHolidaysPerBranch{$branch}}){ + if($holidayWeekDay->{weekday} && $dayOfWeek == $holidayWeekDay->{weekday}){ + $isOpened = 0; + $specialDescription = $holidayWeekDay->{title}; + $holidaytype = 'W'; + }elsif($holidayWeekDay->{day} && $holidayWeekDay->{month}){ + my $date = DateTime->new( + day => $holidayWeekDay->{day}, + month => $holidayWeekDay->{month}, + year => $tempDate->year(), + time_zone => C4::Context->tz() + )->truncate( to => 'day' ); + + if ($tempDate == $date) { + $isOpened = 0; + $specialDescription = $holidayWeekDay->{title}; + $holidaytype = 'R'; + } + } + } + + foreach my $specialDate (@{$specialHolidaysPerBranch{$branch}}){ + if($tempDate->datetime() eq $specialDate->{date}->datetime() ){ + $isOpened = 0; + $specialDescription = $specialDate->{title}; + $holidaytype = 'E'; + } + } + #final insert statement + + $insertDateSt = 'INSERT INTO discrete_calendar (date,branchcode,isopened,holidaytype,note,openhour,closehour) VALUES (?,?,?,?,?,?,?)'; + $insertDateSth = $dbh->prepare($insertDateSt); + $insertDateSth->execute($tempDate,$branch,$isOpened,$holidaytype,$specialDescription,$openhour,$closehour); + } +} +# If everything went well we commit to the database +$dbh->commit(); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/discrete_calendar.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/discrete_calendar.tt new file mode 100644 index 0000000..baa6d25 --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/discrete_calendar.tt @@ -0,0 +1,663 @@ +[% USE Branches %] +[% INCLUDE 'doc-head-open.inc' %] +Koha › Tools › [% Branches.GetName( branch ) %] calendar +[% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'calendar.inc' %] + + +[% INCLUDE 'datatables.inc' %] + + + + + +[% INCLUDE 'header.inc' %] +[% INCLUDE 'cat-search.inc' %] + + + +
+ +
+
+
+

[% Branches.GetName( branch ) %] calendar

+
+
+ +
+ + Copy calendar to + + + +
+

Calendar information

+
+ + [% UNLESS datesInfos %] +
+ Error! You have to run generate_discrete_calendar.pl in order to use Discrete Calendar. +
+ [% END %] + + [% IF no_branch_selected %] +
+ No library set! You are using the default calendar. +
+ [% END %] +
+
+
+

Edit date details

+ +
    +
  1. + Library: + + +
  2. +
  3. + From date: + , + + [% IF ( dateformat == "us" ) %]//[% ELSIF ( dateformat == "metric" ) %]//[% ELSIF ( dateformat == "dmydot" ) %]..[% ELSE %]//[% END %] + + + + + + +
  4. +
  5. + To date: + +
  6. +
  7. + +
  8. +
  9. + + +
  10. + +
  11. + +
  12. +
  13. + +
  14. +
  15. + + +
  16. +
  17. + + + + + + + + + + +
  18. +
+
+ + Cancel +
+
+
+
+ + + + + +
+
+
+

Hints

+
    +
  • Search in the calendar the day you want to set as holiday.
  • +
  • Click the date to add or edit a holiday.
  • +
  • Specify how the holiday should repeat.
  • +
  • Click Save to finish.
  • +
  • PS: +
      +
    • You can't edit passed dates
    • +
    • Weekly holidays change open/close hours for all the days affected unless inputs are empty
    • +
    +
  • +
+

Key

+

+ Working day + Unique holiday + Holiday repeating weekly + Holiday repeating yearly + Floating holiday + Need validation +

+
+
+ + [% IF ( NEED_VALIDATION_HOLIDAYS ) %] +

Need validation holidays

+ + + + + + + + + [% FOREACH need_validation_holiday IN NEED_VALIDATION_HOLIDAYS %] + + + + + [% END %] + +
DateTitle
[% need_validation_holiday.outputdate %][% need_validation_holiday.note %]
+ [% END %] + + [% IF ( WEEKLY_HOLIDAYS ) %] +

Weekly - Repeatable holidays

+ + + + + + + + + [% FOREACH WEEK_DAYS_LOO IN WEEKLY_HOLIDAYS %] + + + + + + [% END %] + +
Day of weekTitle
[% WEEK_DAYS_LOO.weekday %][% WEEK_DAYS_LOO.note %]
+[% END %] + +[% IF ( REPEATABLE_HOLIDAYS ) %] +

Yearly - Repeatable holidays

+ + + + [% IF ( dateformat == "metric" ) %] + + [% ELSE %] + + [% END %] + + + + + [% FOREACH DAY_MONTH_HOLIDAYS_LOO IN REPEATABLE_HOLIDAYS %] + + + + + [% END %] + +
Day/monthMonth/dayTitle
[%DAY_MONTH_HOLIDAYS_LOO.month%]/[% DAY_MONTH_HOLIDAYS_LOO.day %][% DAY_MONTH_HOLIDAYS_LOO.note %]
+[% END %] + +[% IF ( UNIQUE_HOLIDAYS ) %] +

Unique holidays

+ + + + + + + + + [% FOREACH HOLIDAYS_LOO IN UNIQUE_HOLIDAYS %] + + + + + [% END %] + +
DateTitle
[% HOLIDAYS_LOO.outputdate %][% HOLIDAYS_LOO.note %]
+[% END %] + +[% IF ( FLOAT_HOLIDAYS ) %] +

Floating holidays

+ + + + + + + + + [% FOREACH float_holiday IN FLOAT_HOLIDAYS %] + + + + + [% END %] + +
DateTitle
[% float_holiday.outputdate %][% float_holiday.note %]
+[% END %] +
+
+
+
+
+ +
+[% INCLUDE 'tools-menu.inc' %] +
+
+[% INCLUDE 'intranet-bottom.inc' %] diff --git a/misc/cronjobs/add_days_discrete_calendar.pl b/misc/cronjobs/add_days_discrete_calendar.pl new file mode 100755 index 0000000..9264b22 --- /dev/null +++ b/misc/cronjobs/add_days_discrete_calendar.pl @@ -0,0 +1,125 @@ +#!/usr/bin/perl + +# +# This script adds one day into discrete_calendar table based on the same day from the week before +# +use strict; +use warnings; +use DateTime; +use DateTime::Format::Strptime; +use Getopt::Long; +use C4::Context; + +# Options +my $help = 0; +my $daysInFuture = 1; +my $debug = 0; +GetOptions ( + 'help|?|h' => \$help, + 'n=i' => \$daysInFuture, + 'd|?|debug' => \$debug); + +my $usage = << 'ENDUSAGE'; + +This script adds days into discrete_calendar table based on the same day from the week before. + +Examples : + The latest date on discrete_calendar is : 28-07-2017 + The current date : 01-08-2016 + The dates that will be added are : 29-07-2017, 30-07-2017, 31-07-2017, 01-08-2017 +Open close exemples : + Date added is : 29-07-2017 + Opening/closing hours will be base on : 22-07-2017 (- 7 days) + Library open or closed will be based on : 29-07-2017 (- 1 year) +This script has the following parameters: + -h --help: this message + -n : number of days to add in the futre, default : 1 + -d --debug: displays all added days and errors if there is any + +ENDUSAGE + +my $dbh = C4::Context->dbh; +my $query = "SELECT distinct weekday(date), note FROM discrete_calendar where holidaytype='W'"; +my $stmt = $dbh->prepare($query); +$stmt->execute(); +my @week_days_discrete; +while (my ($weekday,$note) = $stmt->fetchrow_array){ + push @week_days_discrete, {weekday => $weekday, note => $note}; +} + +if ($help) { + print $usage; + exit; +} + +#getting the all the branches +my $selectBranchesSt = 'SELECT branchcode FROM discrete_calendar GROUP BY branchcode'; +my $selectBranchesSth = $dbh->prepare($selectBranchesSt); +$selectBranchesSth->execute(); +my @branches = (); +while ( my $branchCode = $selectBranchesSth->fetchrow_array ) { + + push @branches,$branchCode; +} + +#get the latest date in the table +$query = "SELECT MAX(date) FROM discrete_calendar"; +$stmt = $dbh->prepare($query); +$stmt->execute(); +my $latestedDate = $stmt->fetchrow_array; +my $parser = DateTime::Format::Strptime->new( + pattern => '%Y-%m-%d %H:%M:%S', + on_error => 'croak', +); +$latestedDate = $parser->parse_datetime($latestedDate); + +my $newDay = $latestedDate->clone(); +$latestedDate->add(days => $daysInFuture); + +for ($newDay->add(days => 1);$newDay <= $latestedDate;$newDay->add(days => 1)){ + my $lastWeekDay = $newDay->clone(); + $lastWeekDay->add(days=> -8); + my $dayOfWeek = $lastWeekDay->day_of_week; + # Representation fix + # DateTime object dow (1-7) where Monday is 1 + # Arrays are 0-based where 0 = Sunday, not 7. + $dayOfWeek -= 1 unless $dayOfWeek == 7; + $dayOfWeek = 0 if $dayOfWeek == 7; + + #checking if it was open on the same day from last year + my $yearAgo = $newDay->clone(); + $yearAgo = $yearAgo->add(years => -1); + my $last_year = 'SELECT isopened, holidaytype, note FROM discrete_calendar WHERE date=? AND branchcode=?'; + my $day_last_week = "SELECT openhour, closehour FROM discrete_calendar WHERE DAYOFWEEk(date)=DAYOFWEEK(?) and date < ? order by date desc limit 1"; + my $add_Day = 'INSERT INTO discrete_calendar (date,branchcode,isopened,openhour,closehour) VALUES (?,?,?,?,?)'; + my $note =''; + #insert into discrete_calendar for each branch + foreach my $branchCode(@branches){ + $stmt = $dbh->prepare($last_year); + $stmt->execute($yearAgo,$branchCode); + my ($isOpened, $holidaytype, $note) = $stmt->fetchrow_array; + #weekly and unique holidays are not replicated in the future + if ($holidaytype && $holidaytype ne "R"){ + $isOpened = 1; + if ($holidaytype eq "W" || $holidaytype eq "E"){ + $holidaytype=''; + $note=''; + }elsif ($holidaytype eq "F"){ + $holidaytype = 'N'; + } + } + $holidaytype = '' if $isOpened; + $stmt = $dbh->prepare($day_last_week); + $stmt->execute($newDay, $newDay); + my ($openhour,$closehour ) = $stmt->fetchrow_array; + my $add_Day = 'INSERT INTO discrete_calendar (date,branchcode,isopened,holidaytype, note,openhour,closehour) VALUES (?,?,?,?,?,?,?)'; + $stmt = $dbh->prepare($add_Day); + $stmt->execute($newDay,$branchCode,$isOpened,$holidaytype,$note, $openhour,$closehour); + + if($debug && !$@){ + warn "Added day $newDay to $branchCode is opened : $isOpened, holidaytype : $holidaytype, note: $note, openhour : $openhour, closehour : $closehour \n"; + }elsif($@){ + warn "Failed to add day $newDay to $branchCode : $_\n"; + } + } +} diff --git a/tools/discrete_calendar.pl b/tools/discrete_calendar.pl new file mode 100755 index 0000000..8397b3a --- /dev/null +++ b/tools/discrete_calendar.pl @@ -0,0 +1,152 @@ +#!/usr/bin/perl + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +#####Sets holiday periods for each branch. Datedues will be extended if branch is closed -TG +use strict; +use warnings; + +use CGI qw ( -utf8 ); + +use C4::Auth; +use C4::Output; + +use Koha::DateUtils; +use Koha::DiscreteCalendar; + +my $input = new CGI; + +# Get the template to use +my ($template, $loggedinuser, $cookie) + = get_template_and_user({template_name => "tools/discrete_calendar.tt", + type => "intranet", + query => $input, + authnotrequired => 0, + flagsrequired => {tools => 'edit_calendar'}, + debug => 1, + }); + +my $branch = $input->param('branch') || C4::Context->userenv->{'branch'}; +my $calendar = Koha::DiscreteCalendar->new(branchcode => $branch); +#alert the user that he is using the default calendar because he does not have a library set +my $no_branch_selected = $calendar->{no_branch_selected}; + +my $weekday = $input->param('Weekday'); + +my $holidaytype = $input->param('holidayType'); +my $allbranches = $input->param('allBranches'); + +my $title = $input->param('Title'); + +my $action = $input->param('action') || ''; + +# calendardate - date passed in url for human readability (syspref) +# if the url has an invalid date default to 'now.' +my $calendarinput_dt = eval { dt_from_string( scalar $input->param('calendardate')); } || dt_from_string; +my $calendardate = output_pref( { dt => $calendarinput_dt, dateonly => 1 } ); + +if($action eq 'copyBranch'){ + $calendar->copyToBranch(scalar $input->param('newBranch')); +} elsif($action eq 'copyDates'){ + my $from_startDate = $input->param('from_copyFrom') ||''; + my $from_endDate = $input->param('toDate') || ''; + my $to_startDate = $input->param('to_copyFrom') || ''; + my $to_endDate = $input->param('to_copyTo') || ''; + my $daysnumber= $input->param('daysnumber'); + + $from_startDate = dt_from_string(scalar $from_startDate) if$from_startDate ne ''; + $to_startDate = dt_from_string(scalar $to_startDate) if $to_startDate ne ''; + $to_startDate = dt_from_string(scalar $to_startDate) if $to_startDate ne ''; + $to_endDate = dt_from_string(scalar $to_endDate) if $to_endDate ne ''; + + $calendar->copyHoliday($from_startDate, $from_endDate, $to_startDate, $to_endDate, $daysnumber); +} elsif($action eq 'edit'){ + my $openHour = $input->param('openHour'); + my $closeHour = $input->param('closeHour'); + my $toDate = $input->param('toDate'); + my $deleteType = $input->param('deleteType') || 0; + #Get today from javascript for a precise local time + my $local_today = dt_from_string( $input->param('local_today'), 'iso'); + + my $startDate = dt_from_string(scalar $input->param('from_copyFrom')); + + if($toDate ne '' ) { + $toDate = dt_from_string(scalar $toDate); + } else{ + $toDate = $startDate->clone(); + } + #MYSQL DAYOFWEEK Returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). + #JavaScript getDay() Returns the day of the week (from 0 to 6) for the specified date. Sunday is 0, Monday is 1, and so on. + $weekday+=1; + $calendar->edit_holiday($title, $weekday, $holidaytype, $openHour, $closeHour, $startDate, $toDate, $deleteType, $local_today); + +} + +# keydate - date passed to calendar.js. calendar.js does not process dashes within a date. + +my $keydate = output_pref( { dt => $calendarinput_dt, dateonly => 1, dateformat => 'iso' } ); +$keydate =~ s/-/\//g; + +# Set all the branches. +my $onlymine = + ( C4::Context->preference('IndependentBranches') + && C4::Context->userenv + && !C4::Context->IsSuperLibrarian() + && C4::Context->userenv->{branch} ? 1 : 0 ); +if ( $onlymine ) { + $branch = C4::Context->userenv->{'branch'}; +} + +# Get all the holidays + +#discrete_calendar weekly holidays +my @week_days = $calendar->get_week_days_holidays(); + +#discrete_calendar repeatable holidays +my @repeatable_holidays = $calendar->get_repeatable_holidays(); + +#discrete_calendar unique holidays +my @unique_holidays =$calendar->get_unique_holidays(); +#discrete_calendar floating holidays +my @float_holidays =$calendar->get_float_holidays(); +#discrete_caledar need validation holidays +my @need_validation_holidays =$calendar->get_need_valdation_holidays(); + +#Calendar maximum date +my $minDate = $calendar->getMinDate($branch); + +#Calendar minimum date +my $maxDate = $calendar->getMaxDate($branch); + +my @datesInfos = $calendar->getDatesInfo($branch); + +$template->param( + UNIQUE_HOLIDAYS => \@unique_holidays, + FLOAT_HOLIDAYS => \@float_holidays, + NEED_VALIDATION_HOLIDAYS => \@need_validation_holidays, + REPEATABLE_HOLIDAYS => \@repeatable_holidays, + WEEKLY_HOLIDAYS => \@week_days, + calendardate => $calendardate, + keydate => $keydate, + branch => $branch, + minDate => $minDate, + maxDate => $maxDate, + datesInfos => \@datesInfos, + no_branch_selected => $no_branch_selected, +); + +# Shows the template with the real values replaced +output_html_with_http_headers $input, $cookie, $template->output; -- 1.9.1