@@ -, +, @@ 1) Install the new dependency, Template::Plugin::JavaScript. 2) prove t/db_dependent/Calendar.t t/db_dependent/Holidays.t to verify that the new C4::Calendar API works correctly. 3) prove t/Calendar.t 4) Add, remove and modify events of each type using the administrative interface. In this version, changing a repeating event to "Open" deletes it. 5) Check out items to verify that the calculation code is using the events you just created. 6) If possible, verify that the two affected cronjobs still function correctly. --- C4/Calendar.pm | 773 +++++---------------- C4/Circulation.pm | 87 --- C4/Installer/PerlDependencies.pm | 5 + C4/Overdues.pm | 124 ---- Koha/Calendar.pm | 26 +- .../intranet-tmpl/prog/en/includes/tools-menu.inc | 2 +- .../prog/en/modules/tools/calendar.tt | 594 ++++++++++++++++ .../prog/en/modules/tools/holidays.tt | 536 -------------- .../prog/en/modules/tools/tools-home.tt | 2 +- misc/cronjobs/staticfines.pl | 11 +- .../thirdparty/TalkingTech_itiva_outbound.pl | 31 +- t/Calendar.t | 6 +- t/db_dependent/Calendar.t | 86 +++ t/db_dependent/Holidays.t | 15 +- tools/calendar.pl | 268 +++++++ tools/copy-holidays.pl | 39 -- tools/exceptionHolidays.pl | 145 ---- tools/holidays.pl | 164 ----- tools/newHolidays.pl | 144 ---- 19 files changed, 1138 insertions(+), 1920 deletions(-) create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/calendar.tt delete mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/tools/holidays.tt create mode 100644 t/db_dependent/Calendar.t create mode 100755 tools/calendar.pl delete mode 100755 tools/copy-holidays.pl delete mode 100755 tools/exceptionHolidays.pl delete mode 100755 tools/holidays.pl delete mode 100755 tools/newHolidays.pl --- a/C4/Calendar.pm +++ a/C4/Calendar.pm @@ -15,712 +15,250 @@ package C4::Calendar; # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place, # Suite 330, Boston, MA 02111-1307 USA -use strict; -use warnings; +use Modern::Perl; use vars qw($VERSION @EXPORT); use Carp; -use Date::Calc qw( Date_to_Days Today); -use C4::Context; +use Koha::Database; + +our ( @ISA, @EXPORT ); + +BEGIN { + @ISA = qw( Exporter ); + @EXPORT = qw( + GetSingleEvents + GetWeeklyEvents + GetYearlyEvents + ModSingleEvent + ModRepeatingEvent + DelSingleEvent + DelRepeatingEvent + CopyAllEvents + ); +} use constant ISO_DATE_FORMAT => "%04d-%02d-%02d"; =head1 NAME -C4::Calendar::Calendar - Koha module dealing with holidays. +C4::Calendar - Koha module dealing with holidays. =head1 SYNOPSIS - use C4::Calendar::Calendar; + use C4::Calendar; =head1 DESCRIPTION -This package is used to deal with holidays. Through this package, you can set -all kind of holidays for the library. +This package is used to deal with hours and holidays; =head1 FUNCTIONS -=head2 new - - $calendar = C4::Calendar->new(branchcode => $branchcode); - -Each library branch has its own Calendar. -C<$branchcode> specifies which Calendar you want. - -=cut - -sub new { - my $classname = shift @_; - my %options = @_; - my $self = bless({}, $classname); - foreach my $optionName (keys %options) { - $self->{lc($optionName)} = $options{$optionName}; - } - defined($self->{branchcode}) or croak "No branchcode argument to new. Should be C4::Calendar->new(branchcode => \$branchcode)"; - $self->_init($self->{branchcode}); - return $self; -} - -sub _init { - my $self = shift @_; - my $branch = shift; - defined($branch) or die "No branchcode sent to _init"; # must test for defined here and above to allow "" - my $dbh = C4::Context->dbh(); - my $repeatable = $dbh->prepare( 'SELECT * - FROM repeatable_holidays - WHERE ( branchcode = ? ) - AND (ISNULL(weekday) = ?)' ); - $repeatable->execute($branch,0); - my %week_days_holidays; - while (my $row = $repeatable->fetchrow_hashref) { - my $key = $row->{weekday}; - $week_days_holidays{$key}{title} = $row->{title}; - $week_days_holidays{$key}{description} = $row->{description}; - } - $self->{'week_days_holidays'} = \%week_days_holidays; - - $repeatable->execute($branch,1); - my %day_month_holidays; - while (my $row = $repeatable->fetchrow_hashref) { - my $key = $row->{month} . "/" . $row->{day}; - $day_month_holidays{$key}{title} = $row->{title}; - $day_month_holidays{$key}{description} = $row->{description}; - $day_month_holidays{$key}{day} = sprintf("%02d", $row->{day}); - $day_month_holidays{$key}{month} = sprintf("%02d", $row->{month}); - } - $self->{'day_month_holidays'} = \%day_month_holidays; - - my $special = $dbh->prepare( 'SELECT day, month, year, title, description - FROM special_holidays - WHERE ( branchcode = ? ) - AND (isexception = ?)' ); - $special->execute($branch,1); - my %exception_holidays; - while (my ($day, $month, $year, $title, $description) = $special->fetchrow) { - $exception_holidays{"$year/$month/$day"}{title} = $title; - $exception_holidays{"$year/$month/$day"}{description} = $description; - $exception_holidays{"$year/$month/$day"}{date} = - sprintf(ISO_DATE_FORMAT, $year, $month, $day); - } - $self->{'exception_holidays'} = \%exception_holidays; - - $special->execute($branch,0); - my %single_holidays; - while (my ($day, $month, $year, $title, $description) = $special->fetchrow) { - $single_holidays{"$year/$month/$day"}{title} = $title; - $single_holidays{"$year/$month/$day"}{description} = $description; - $single_holidays{"$year/$month/$day"}{date} = - sprintf(ISO_DATE_FORMAT, $year, $month, $day); - } - $self->{'single_holidays'} = \%single_holidays; - return $self; -} - -=head2 get_week_days_holidays - - $week_days_holidays = $calendar->get_week_days_holidays(); - -Returns a hash reference to week days holidays. - -=cut - -sub get_week_days_holidays { - my $self = shift @_; - my $week_days_holidays = $self->{'week_days_holidays'}; - return $week_days_holidays; -} - -=head2 get_day_month_holidays - - $day_month_holidays = $calendar->get_day_month_holidays(); - -Returns a hash reference to day month holidays. - -=cut - -sub get_day_month_holidays { - my $self = shift @_; - my $day_month_holidays = $self->{'day_month_holidays'}; - return $day_month_holidays; -} - -=head2 get_exception_holidays - - $exception_holidays = $calendar->exception_holidays(); - -Returns a hash reference to exception holidays. This kind of days are those -which stands for a holiday, but you wanted to make an exception for this particular -date. - -=cut - -sub get_exception_holidays { - my $self = shift @_; - my $exception_holidays = $self->{'exception_holidays'}; - return $exception_holidays; -} - -=head2 get_single_holidays - - $single_holidays = $calendar->get_single_holidays(); - -Returns a hash reference to single holidays. This kind of holidays are those which -happend just one time. +=head2 GetSingleEvents -=cut - -sub get_single_holidays { - my $self = shift @_; - my $single_holidays = $self->{'single_holidays'}; - return $single_holidays; -} - -=head2 insert_week_day_holiday - - insert_week_day_holiday(weekday => $weekday, - title => $title, - description => $description); + \@events = GetSingleEvents( $branchcode ) -Inserts a new week day for $self->{branchcode}. - -C<$day> Is the week day to make holiday. - -C<$title> Is the title to store for the holiday formed by $year/$month/$day. - -C<$description> Is the description to store for the holiday formed by $year/$month/$day. +Get the non-repeating events for the given library. =cut -sub insert_week_day_holiday { - my $self = shift @_; - my %options = @_; - - my $weekday = $options{weekday}; - croak "Invalid weekday $weekday" unless $weekday =~ m/^[0-6]$/; - - my $dbh = C4::Context->dbh(); - my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ( '',?,?,NULL,NULL,?,? )"); - $insertHoliday->execute( $self->{branchcode}, $weekday, $options{title}, $options{description}); - $self->{'week_days_holidays'}->{$weekday}{title} = $options{title}; - $self->{'week_days_holidays'}->{$weekday}{description} = $options{description}; - return $self; +sub GetSingleEvents { + my ( $branchcode ) = @_; + + return C4::Context->dbh->selectall_arrayref( q{ + SELECT + CONCAT(LPAD(year, 4, '0'), '-', LPAD(month, 2, '0'), '-', LPAD(day, 2, '0')) as event_date, + 0 as open_hour, 0 as open_minute, IF(isexception, 24, 0) as close_hour, + 0 as close_minute, title, description, IF(isexception, 0, 1) as closed + FROM special_holidays + WHERE branchcode = ? + }, { Slice => {} }, $branchcode ); } -=head2 insert_day_month_holiday +=head2 GetWeeklyEvents - insert_day_month_holiday(day => $day, - month => $month, - title => $title, - description => $description); + \@events = GetWeeklyEvents( $branchcode ) -Inserts a new day month holiday for $self->{branchcode}. - -C<$day> Is the day month to make the date to insert. - -C<$month> Is month to make the date to insert. - -C<$title> Is the title to store for the holiday formed by $year/$month/$day. - -C<$description> Is the description to store for the holiday formed by $year/$month/$day. +Get the weekly-repeating events for the given library. =cut -sub insert_day_month_holiday { - my $self = shift @_; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ('', ?, NULL, ?, ?, ?,? )"); - $insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{title}, $options{description}); - $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title}; - $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description}; - return $self; -} - -=head2 insert_single_holiday - - insert_single_holiday(day => $day, - month => $month, - year => $year, - title => $title, - description => $description); - -Inserts a new single holiday for $self->{branchcode}. +sub GetWeeklyEvents { + my ( $branchcode ) = @_; -C<$day> Is the day month to make the date to insert. - -C<$month> Is month to make the date to insert. - -C<$year> Is year to make the date to insert. - -C<$title> Is the title to store for the holiday formed by $year/$month/$day. - -C<$description> Is the description to store for the holiday formed by $year/$month/$day. - -=cut - -sub insert_single_holiday { - my $self = shift @_; - my %options = @_; - - @options{qw(year month day)} = ( $options{date} =~ m/(\d+)-(\d+)-(\d+)/o ) - if $options{date} && !$options{day}; - - my $dbh = C4::Context->dbh(); - my $isexception = 0; - my $insertHoliday = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)"); - $insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description}); - $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title}; - $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description}; - return $self; + return C4::Context->dbh->selectall_arrayref( q{ + SELECT + weekday, 0 as open_hour, 0 as open_minute, 0 as close_hour, + 0 as close_minute, title, description, 1 as closed + FROM repeatable_holidays + WHERE branchcode = ? AND weekday IS NOT NULL + }, { Slice => {} }, $branchcode ); } -=head2 insert_exception_holiday - - insert_exception_holiday(day => $day, - month => $month, - year => $year, - title => $title, - description => $description); - -Inserts a new exception holiday for $self->{branchcode}. - -C<$day> Is the day month to make the date to insert. +=head2 GetYearlyEvents -C<$month> Is month to make the date to insert. + \@events = GetYearlyEvents( $branchcode ) -C<$year> Is year to make the date to insert. - -C<$title> Is the title to store for the holiday formed by $year/$month/$day. - -C<$description> Is the description to store for the holiday formed by $year/$month/$day. +Get the yearly-repeating events for the given library. =cut -sub insert_exception_holiday { - my $self = shift @_; - my %options = @_; - - @options{qw(year month day)} = ( $options{date} =~ m/(\d+)-(\d+)-(\d+)/o ) - if $options{date} && !$options{day}; +sub GetYearlyEvents { + my ( $branchcode ) = @_; - my $dbh = C4::Context->dbh(); - my $isexception = 1; - my $insertException = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)"); - $insertException->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description}); - $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title}; - $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description}; - return $self; + return C4::Context->dbh->selectall_arrayref( q{ + SELECT + month, day, 0 as open_hour, 0 as open_minute, 0 as close_hour, + 0 as close_minute, title, description, 1 as closed + FROM repeatable_holidays + WHERE branchcode = ? AND weekday IS NULL + }, { Slice => {} }, $branchcode ); } -=head2 ModWeekdayholiday - - ModWeekdayholiday(weekday =>$weekday, - title => $title, - description => $description) - -Modifies the title and description of a weekday for $self->{branchcode}. +=head2 ModSingleEvent -C<$weekday> Is the title to update for the holiday. + ModSingleEvent( $branchcode, \%info ) -C<$description> Is the description to update for the holiday. +Creates or updates an event for a single date. $info->{date} should be an +ISO-formatted date string, and \%info should also contain the following keys: +open_hour, open_minute, close_hour, close_minute, title and description. =cut -sub ModWeekdayholiday { - my $self = shift @_; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $updateHoliday = $dbh->prepare("UPDATE repeatable_holidays SET title = ?, description = ? WHERE branchcode = ? AND weekday = ?"); - $updateHoliday->execute( $options{title},$options{description},$self->{branchcode},$options{weekday}); - $self->{'week_days_holidays'}->{$options{weekday}}{title} = $options{title}; - $self->{'week_days_holidays'}->{$options{weekday}}{description} = $options{description}; - return $self; -} - -=head2 ModDaymonthholiday - - ModDaymonthholiday(day => $day, - month => $month, - title => $title, - description => $description); +sub ModSingleEvent { + my ( $branchcode, $info ) = @_; -Modifies the title and description for a day/month holiday for $self->{branchcode}. + my ( $year, $month, $day ) = ( $info->{date} =~ /(\d+)-(\d+)-(\d+)/ ); + return unless ( $year && $month && $day ); -C<$day> The day of the month for the update. + my $dbh = C4::Context->dbh; + my @args = ( ( map { $info->{$_} } qw(title description) ), $info->{close_hour} != 0, $branchcode, $year, $month, $day ); -C<$month> The month to be used for the update. + # The code below relies on $dbh->do returning 0 when the update affects no rows + my $affected = $dbh->do( q{ + UPDATE special_holidays + SET + title = ?, description = ?, isexception = ? + WHERE branchcode = ? AND year = ? AND month = ? AND day = ? + }, {}, @args ); -C<$title> The title to be updated for the holiday. - -C<$description> The description to be update for the holiday. - -=cut - -sub ModDaymonthholiday { - my $self = shift @_; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $updateHoliday = $dbh->prepare("UPDATE repeatable_holidays SET title = ?, description = ? WHERE month = ? AND day = ? AND branchcode = ?"); - $updateHoliday->execute( $options{title},$options{description},$options{month},$options{day},$self->{branchcode}); - $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title}; - $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description}; - return $self; + $dbh->do( q{ + INSERT + INTO special_holidays(title, description, isexception, branchcode, year, month, day) + VALUES (?, ?, ?, ?, ?, ?, ?) + }, {}, @args ) unless ( $affected > 0 ); } -=head2 ModSingleholiday - - ModSingleholiday(day => $day, - month => $month, - year => $year, - title => $title, - description => $description); - -Modifies the title and description for a single holiday for $self->{branchcode}. - -C<$day> Is the day of the month to make the update. - -C<$month> Is the month to make the update. - -C<$year> Is the year to make the update. +=head2 ModRepeatingEvent -C<$title> Is the title to update for the holiday formed by $year/$month/$day. + ModRepeatingEvent( $branchcode, \%info ) -C<$description> Is the description to update for the holiday formed by $year/$month/$day. +Creates or updates a weekly- or yearly-repeating event. Either $info->{weekday}, +or $info->{month} and $info->{day} should be set, for a weekly or yearly event, +respectively. =cut -sub ModSingleholiday { - my $self = shift @_; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $isexception = 0; - my $updateHoliday = $dbh->prepare("UPDATE special_holidays SET title = ?, description = ? WHERE day = ? AND month = ? AND year = ? AND branchcode = ? AND isexception = ?"); - $updateHoliday->execute($options{title},$options{description},$options{day},$options{month},$options{year},$self->{branchcode},$isexception); - $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title}; - $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description}; - return $self; -} - -=head2 ModExceptionholiday - - ModExceptionholiday(day => $day, - month => $month, - year => $year, - title => $title, - description => $description); - -Modifies the title and description for an exception holiday for $self->{branchcode}. - -C<$day> Is the day of the month for the holiday. - -C<$month> Is the month for the holiday. - -C<$year> Is the year for the holiday. - -C<$title> Is the title to be modified for the holiday formed by $year/$month/$day. - -C<$description> Is the description to be modified for the holiday formed by $year/$month/$day. +sub _get_compare { + my ( $colname, $value ) = @_; -=cut - -sub ModExceptionholiday { - my $self = shift @_; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $isexception = 1; - my $updateHoliday = $dbh->prepare("UPDATE special_holidays SET title = ?, description = ? WHERE day = ? AND month = ? AND year = ? AND branchcode = ? AND isexception = ?"); - $updateHoliday->execute($options{title},$options{description},$options{day},$options{month},$options{year},$self->{branchcode},$isexception); - $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title}; - $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description}; - return $self; + return ' AND ' . $colname . ' ' . ( defined( $value ) ? '=' : 'IS' ) . ' ?'; } -=head2 delete_holiday - - delete_holiday(weekday => $weekday - day => $day, - month => $month, - year => $year); - -Delete a holiday for $self->{branchcode}. - -C<$weekday> Is the week day to delete. +sub ModRepeatingEvent { + my ( $branchcode, $info ) = @_; -C<$day> Is the day month to make the date to delete. + my $dbh = C4::Context->dbh; + my $open = ( $info->{close_hour} != 0 ); -C<$month> Is month to make the date to delete. - -C<$year> Is year to make the date to delete. - -=cut - -sub delete_holiday { - my $self = shift @_; - my %options = @_; - - # Verify what kind of holiday that day is. For example, if it is - # a repeatable holiday, this should check if there are some exception - # for that holiday rule. Otherwise, if it is a regular holiday, it´s - # ok just deleting it. - - my $dbh = C4::Context->dbh(); - my $isSingleHoliday = $dbh->prepare("SELECT id FROM special_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?) AND (year = ?)"); - $isSingleHoliday->execute($self->{branchcode}, $options{day}, $options{month}, $options{year}); - if ($isSingleHoliday->rows) { - my $id = $isSingleHoliday->fetchrow; - $isSingleHoliday->finish; # Close the last query - - my $deleteHoliday = $dbh->prepare("DELETE FROM special_holidays WHERE id = ?"); - $deleteHoliday->execute($id); - delete($self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}); + if ($open) { + $dbh->do( q{ + DELETE FROM repeatable_holidays + WHERE branchcode = ? + } . _get_compare( 'weekday', $info->{weekday} ) . _get_compare( 'month', $info->{month} ) . _get_compare( 'day', $info->{day} ), {}, $branchcode, $info->{weekday}, $info->{month}, $info->{day} ); } else { - $isSingleHoliday->finish; # Close the last query - - my $isWeekdayHoliday = $dbh->prepare("SELECT id FROM repeatable_holidays WHERE branchcode = ? AND weekday = ?"); - $isWeekdayHoliday->execute($self->{branchcode}, $options{weekday}); - if ($isWeekdayHoliday->rows) { - my $id = $isWeekdayHoliday->fetchrow; - $isWeekdayHoliday->finish; # Close the last query - - my $updateExceptions = $dbh->prepare("UPDATE special_holidays SET isexception = 0 WHERE (WEEKDAY(CONCAT(special_holidays.year,'-',special_holidays.month,'-',special_holidays.day)) = ?) AND (branchcode = ?)"); - $updateExceptions->execute($options{weekday}, $self->{branchcode}); - $updateExceptions->finish; # Close the last query - - my $deleteHoliday = $dbh->prepare("DELETE FROM repeatable_holidays WHERE id = ?"); - $deleteHoliday->execute($id); - delete($self->{'week_days_holidays'}->{$options{weekday}}); - } else { - $isWeekdayHoliday->finish; # Close the last query - - my $isDayMonthHoliday = $dbh->prepare("SELECT id FROM repeatable_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?)"); - $isDayMonthHoliday->execute($self->{branchcode}, $options{day}, $options{month}); - if ($isDayMonthHoliday->rows) { - my $id = $isDayMonthHoliday->fetchrow; - $isDayMonthHoliday->finish; - my $updateExceptions = $dbh->prepare("UPDATE special_holidays SET isexception = 0 WHERE (special_holidays.branchcode = ?) AND (special_holidays.day = ?) and (special_holidays.month = ?)"); - $updateExceptions->execute($self->{branchcode}, $options{day}, $options{month}); - $updateExceptions->finish; # Close the last query - - my $deleteHoliday = $dbh->prepare("DELETE FROM repeatable_holidays WHERE (id = ?)"); - $deleteHoliday->execute($id); - delete($self->{'day_month_holidays'}->{"$options{month}/$options{day}"}); - } - } + my @args = ( ( map { $info->{$_} } qw(title description) ), $branchcode, $info->{weekday}, $info->{month}, $info->{day} ); + + # The code below relies on $dbh->do returning 0 when the update affects no rows + my $affected = $dbh->do( q{ + UPDATE repeatable_holidays + SET + title = ?, description = ? + WHERE branchcode = ? + } . _get_compare( 'weekday', $info->{weekday} ) . _get_compare( 'month', $info->{month} ) . _get_compare( 'day', $info->{day} ), {}, @args ); + + $dbh->do( q{ + INSERT + INTO repeatable_holidays(title, description, branchcode, weekday, month, day) + VALUES (?, ?, ?, ?, ?, ?) + }, {}, @args ) unless ( $affected > 0 ); } - return $self; -} -=head2 delete_holiday_range - - delete_holiday_range(day => $day, - month => $month, - year => $year); - -Delete a holiday range of dates for $self->{branchcode}. - -C<$day> Is the day month to make the date to delete. - -C<$month> Is month to make the date to delete. - -C<$year> Is year to make the date to delete. - -=cut - -sub delete_holiday_range { - my $self = shift; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $sth = $dbh->prepare("DELETE FROM special_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?) AND (year = ?)"); - $sth->execute($self->{branchcode}, $options{day}, $options{month}, $options{year}); } -=head2 delete_holiday_range_repeatable +=head2 DelSingleEvent - delete_holiday_range_repeatable(day => $day, - month => $month); + DelSingleEvent( $branchcode, \%info ) -Delete a holiday for $self->{branchcode}. - -C<$day> Is the day month to make the date to delete. - -C<$month> Is month to make the date to delete. +Deletes an event for a single date. $info->{date} should be an ISO-formatted date string. =cut -sub delete_holiday_range_repeatable { - my $self = shift; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $sth = $dbh->prepare("DELETE FROM repeatable_holidays WHERE (branchcode = ?) AND (day = ?) AND (month = ?)"); - $sth->execute($self->{branchcode}, $options{day}, $options{month}); -} - -=head2 delete_exception_holiday_range +sub DelSingleEvent { + my ( $branchcode, $info ) = @_; - delete_exception_holiday_range(weekday => $weekday - day => $day, - month => $month, - year => $year); + my ( $year, $month, $day ) = ( $info->{date} =~ /(\d+)-(\d+)-(\d+)/ ); + return unless ( $year && $month && $day ); -Delete a holiday for $self->{branchcode}. - -C<$day> Is the day month to make the date to delete. - -C<$month> Is month to make the date to delete. - -C<$year> Is year to make the date to delete. - -=cut - -sub delete_exception_holiday_range { - my $self = shift; - my %options = @_; - - my $dbh = C4::Context->dbh(); - my $sth = $dbh->prepare("DELETE FROM special_holidays WHERE (branchcode = ?) AND (isexception = 1) AND (day = ?) AND (month = ?) AND (year = ?)"); - $sth->execute($self->{branchcode}, $options{day}, $options{month}, $options{year}); + C4::Context->dbh->do( q{ + DELETE FROM special_holidays + WHERE branchcode = ? AND year = ? AND month = ? AND day = ? + }, {}, $branchcode, $year, $month, $day ); } -=head2 isHoliday - - $isHoliday = isHoliday($day, $month $year); - -C<$day> Is the day to check whether if is a holiday or not. - -C<$month> Is the month to check whether if is a holiday or not. - -C<$year> Is the year to check whether if is a holiday or not. - -=cut - -sub isHoliday { - my ($self, $day, $month, $year) = @_; - # FIXME - date strings are stored in non-padded metric format. should change to iso. - # FIXME - should change arguments to accept C4::Dates object - $month=$month+0; - $year=$year+0; - $day=$day+0; - my $weekday = &Date::Calc::Day_of_Week($year, $month, $day) % 7; - my $weekDays = $self->get_week_days_holidays(); - my $dayMonths = $self->get_day_month_holidays(); - my $exceptions = $self->get_exception_holidays(); - my $singles = $self->get_single_holidays(); - if (defined($exceptions->{"$year/$month/$day"})) { - return 0; - } else { - if ((exists($weekDays->{$weekday})) || - (exists($dayMonths->{"$month/$day"})) || - (exists($singles->{"$year/$month/$day"}))) { - return 1; - } else { - return 0; - } - } +=head2 DelRepeatingEvent -} + DelRepeatingEvent( $branchcode, \%info ) -=head2 copy_to_branch - - $calendar->copy_to_branch($target_branch) +Deletes a weekly- or yearly-repeating event. Either $info->{weekday}, or +$info->{month} and $info->{day} should be set, for a weekly or yearly event, +respectively. =cut -sub copy_to_branch { - my ($self, $target_branch) = @_; - - croak "No target_branch" unless $target_branch; +sub DelRepeatingEvent { + my ( $branchcode, $info ) = @_; - my $target_calendar = C4::Calendar->new(branchcode => $target_branch); - - my ($y, $m, $d) = Today(); - my $today = sprintf ISO_DATE_FORMAT, $y,$m,$d; - - my $wdh = $self->get_week_days_holidays; - $target_calendar->insert_week_day_holiday( weekday => $_, %{ $wdh->{$_} } ) - foreach keys %$wdh; - $target_calendar->insert_day_month_holiday(%$_) - foreach values %{ $self->get_day_month_holidays }; - $target_calendar->insert_exception_holiday(%$_) - foreach grep { $_->{date} gt $today } values %{ $self->get_exception_holidays }; - $target_calendar->insert_single_holiday(%$_) - foreach grep { $_->{date} gt $today } values %{ $self->get_single_holidays }; - - return 1; + C4::Context->dbh->do( q{ + DELETE FROM repeatable_holidays + WHERE branchcode = ? + } . _get_compare( 'weekday', $info->{weekday} ) . _get_compare( 'month', $info->{month} ) . _get_compare( 'day', $info->{day} ), {}, $branchcode, $info->{weekday}, $info->{month}, $info->{day} ); } -=head2 addDate +=head2 CopyAllEvents - my ($day, $month, $year) = $calendar->addDate($date, $offset) + CopyAllEvents( $from_branchcode, $to_branchcode ) -C<$date> is a C4::Dates object representing the starting date of the interval. - -C<$offset> Is the number of days that this function has to count from $date. +Copies all events from one branch to another. =cut -sub addDate { - my ($self, $startdate, $offset) = @_; - my ($year,$month,$day) = split("-",$startdate->output('iso')); - my $daystep = 1; - if ($offset < 0) { # In case $offset is negative - # $offset = $offset*(-1); - $daystep = -1; - } - my $daysMode = C4::Context->preference('useDaysMode'); - if ($daysMode eq 'Datedue') { - ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset ); - while ($self->isHoliday($day, $month, $year)) { - ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep); - } - } elsif($daysMode eq 'Calendar') { - while ($offset != 0) { - ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep); - if (!($self->isHoliday($day, $month, $year))) { - $offset = $offset - $daystep; - } - } - } else { ## ($daysMode eq 'Days') - ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset ); - } - return(C4::Dates->new( sprintf(ISO_DATE_FORMAT,$year,$month,$day),'iso')); +sub CopyAllEvents { + my ( $from_branchcode, $to_branchcode ) = @_; + + C4::Context->dbh->do( q{ + INSERT IGNORE INTO special_holidays(branchcode, year, month, day, isexception, title, description) + SELECT ?, year, month, day, isexception, title, description + FROM special_holidays + WHERE branchcode = ? + }, {}, $to_branchcode, $from_branchcode ); + + C4::Context->dbh->do( q{ + INSERT IGNORE INTO repeatable_holidays(branchcode, weekday, month, day, title, description) + SELECT ?, weekday, month, day, title, description + FROM repeatable_holidays + WHERE branchcode = ? + }, {}, $to_branchcode, $from_branchcode ); } -=head2 daysBetween - - my $daysBetween = $calendar->daysBetween($startdate, $enddate) - -C<$startdate> and C<$enddate> are C4::Dates objects that define the interval. - -Returns the number of non-holiday days in the interval. -useDaysMode syspref has no effect here. -=cut - -sub daysBetween { - my $self = shift or return; - my $startdate = shift or return; - my $enddate = shift or return; - my ($yearFrom,$monthFrom,$dayFrom) = split("-",$startdate->output('iso')); - my ($yearTo, $monthTo, $dayTo ) = split("-", $enddate->output('iso')); - if (Date_to_Days($yearFrom,$monthFrom,$dayFrom) > Date_to_Days($yearTo,$monthTo,$dayTo)) { - return 0; - # we don't go backwards ( FIXME - handle this error better ) - } - my $count = 0; - while (1) { - ($yearFrom != $yearTo or $monthFrom != $monthTo or $dayFrom != $dayTo) or last; # if they all match, it's the last day - unless ($self->isHoliday($dayFrom, $monthFrom, $yearFrom)) { - $count++; - } - ($yearFrom, $monthFrom, $dayFrom) = &Date::Calc::Add_Delta_Days($yearFrom, $monthFrom, $dayFrom, 1); - } - return($count); -} 1; @@ -729,5 +267,6 @@ __END__ =head1 AUTHOR Koha Physics Library UNLP +Jesse Weaver =cut --- a/C4/Circulation.pm +++ a/C4/Circulation.pm @@ -3314,93 +3314,6 @@ sub CalcDateDue { return $datedue; } - -=head2 CheckRepeatableHolidays - - $countrepeatable = CheckRepeatableHoliday($itemnumber,$week_day,$branchcode); - -This function checks if the date due is a repeatable holiday - -C<$date_due> = returndate calculate with no day check -C<$itemnumber> = itemnumber -C<$branchcode> = localisation of issue - -=cut - -sub CheckRepeatableHolidays{ -my($itemnumber,$week_day,$branchcode)=@_; -my $dbh = C4::Context->dbh; -my $query = qq|SELECT count(*) - FROM repeatable_holidays - WHERE branchcode=? - AND weekday=?|; -my $sth = $dbh->prepare($query); -$sth->execute($branchcode,$week_day); -my $result=$sth->fetchrow; -return $result; -} - - -=head2 CheckSpecialHolidays - - $countspecial = CheckSpecialHolidays($years,$month,$day,$itemnumber,$branchcode); - -This function check if the date is a special holiday - -C<$years> = the years of datedue -C<$month> = the month of datedue -C<$day> = the day of datedue -C<$itemnumber> = itemnumber -C<$branchcode> = localisation of issue - -=cut - -sub CheckSpecialHolidays{ -my ($years,$month,$day,$itemnumber,$branchcode) = @_; -my $dbh = C4::Context->dbh; -my $query=qq|SELECT count(*) - FROM `special_holidays` - WHERE year=? - AND month=? - AND day=? - AND branchcode=? - |; -my $sth = $dbh->prepare($query); -$sth->execute($years,$month,$day,$branchcode); -my $countspecial=$sth->fetchrow ; -return $countspecial; -} - -=head2 CheckRepeatableSpecialHolidays - - $countspecial = CheckRepeatableSpecialHolidays($month,$day,$itemnumber,$branchcode); - -This function check if the date is a repeatble special holidays - -C<$month> = the month of datedue -C<$day> = the day of datedue -C<$itemnumber> = itemnumber -C<$branchcode> = localisation of issue - -=cut - -sub CheckRepeatableSpecialHolidays{ -my ($month,$day,$itemnumber,$branchcode) = @_; -my $dbh = C4::Context->dbh; -my $query=qq|SELECT count(*) - FROM `repeatable_holidays` - WHERE month=? - AND day=? - AND branchcode=? - |; -my $sth = $dbh->prepare($query); -$sth->execute($month,$day,$branchcode); -my $countspecial=$sth->fetchrow ; -return $countspecial; -} - - - sub CheckValidBarcode{ my ($barcode) = @_; my $dbh = C4::Context->dbh; --- a/C4/Installer/PerlDependencies.pm +++ a/C4/Installer/PerlDependencies.pm @@ -737,6 +737,11 @@ our $PERL_DEPS = { 'required' => '0', 'min_ver' => '5.836', }, + 'Template::Plugin::JavaScript' => { + 'usage' => 'Core', + 'required' => '1', + 'min_ver' => '0.02', + }, }; 1; --- a/C4/Overdues.pm +++ a/C4/Overdues.pm @@ -309,130 +309,6 @@ sub _get_chargeable_units { } -=head2 GetSpecialHolidays - - &GetSpecialHolidays($date_dues,$itemnumber); - -return number of special days between date of the day and date due - -C<$date_dues> is the envisaged date of book return. - -C<$itemnumber> is the book's item number. - -=cut - -sub GetSpecialHolidays { - my ( $date_dues, $itemnumber ) = @_; - - # calcul the today date - my $today = join "-", &Today(); - - # return the holdingbranch - my $iteminfo = GetIssuesIteminfo($itemnumber); - - # use sql request to find all date between date_due and today - my $dbh = C4::Context->dbh; - my $query = - qq|SELECT DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') as date -FROM `special_holidays` -WHERE DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') >= ? -AND DATE_FORMAT(concat(year,'-',month,'-',day),'%Y-%m-%d') <= ? -AND branchcode=? -|; - my @result = GetWdayFromItemnumber($itemnumber); - my @result_date; - my $wday; - my $dateinsec; - my $sth = $dbh->prepare($query); - $sth->execute( $date_dues, $today, $iteminfo->{'branchcode'} ) - ; # FIXME: just use NOW() in SQL instead of passing in $today - - while ( my $special_date = $sth->fetchrow_hashref ) { - push( @result_date, $special_date ); - } - - my $specialdaycount = scalar(@result_date); - - for ( my $i = 0 ; $i < scalar(@result_date) ; $i++ ) { - $dateinsec = UnixDate( $result_date[$i]->{'date'}, "%o" ); - ( undef, undef, undef, undef, undef, undef, $wday, undef, undef ) = - localtime($dateinsec); - for ( my $j = 0 ; $j < scalar(@result) ; $j++ ) { - if ( $wday == ( $result[$j]->{'weekday'} ) ) { - $specialdaycount--; - } - } - } - - return $specialdaycount; -} - -=head2 GetRepeatableHolidays - - &GetRepeatableHolidays($date_dues, $itemnumber, $difference,); - -return number of day closed between date of the day and date due - -C<$date_dues> is the envisaged date of book return. - -C<$itemnumber> is item number. - -C<$difference> numbers of between day date of the day and date due - -=cut - -sub GetRepeatableHolidays { - my ( $date_dues, $itemnumber, $difference ) = @_; - my $dateinsec = UnixDate( $date_dues, "%o" ); - my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = - localtime($dateinsec); - my @result = GetWdayFromItemnumber($itemnumber); - my @dayclosedcount; - my $j; - - for ( my $i = 0 ; $i < scalar(@result) ; $i++ ) { - my $k = $wday; - - for ( $j = 0 ; $j < $difference ; $j++ ) { - if ( $result[$i]->{'weekday'} == $k ) { - push( @dayclosedcount, $k ); - } - $k++; - ( $k = 0 ) if ( $k eq 7 ); - } - } - return scalar(@dayclosedcount); -} - - -=head2 GetWayFromItemnumber - - &Getwdayfromitemnumber($itemnumber); - -return the different week day from repeatable_holidays table - -C<$itemnumber> is item number. - -=cut - -sub GetWdayFromItemnumber { - my ($itemnumber) = @_; - my $iteminfo = GetIssuesIteminfo($itemnumber); - my @result; - my $query = qq|SELECT weekday - FROM repeatable_holidays - WHERE branchcode=? -|; - my $sth = C4::Context->dbh->prepare($query); - - $sth->execute( $iteminfo->{'branchcode'} ); - while ( my $weekday = $sth->fetchrow_hashref ) { - push( @result, $weekday ); - } - return @result; -} - - =head2 GetIssuesIteminfo &GetIssuesIteminfo($itemnumber); --- a/Koha/Calendar.pm +++ a/Koha/Calendar.pm @@ -60,7 +60,7 @@ sub _init { # 3.16, bug 8089 will be fixed and we can switch the caching over # to Koha::Cache. our ( $exception_holidays, $single_holidays ); -sub exception_holidays { +sub _exception_holidays { my ( $self ) = @_; my $dbh = C4::Context->dbh; my $branch = $self->{branchcode}; @@ -88,7 +88,7 @@ sub exception_holidays { return $exception_holidays; } -sub single_holidays { +sub _single_holidays { my ( $self ) = @_; my $dbh = C4::Context->dbh; my $branch = $self->{branchcode}; @@ -213,7 +213,7 @@ sub is_holiday { $localdt->truncate( to => 'day' ); - if ( $self->exception_holidays->contains($localdt) ) { + if ( $self->_exception_holidays->contains($localdt) ) { # exceptions are not holidays return 0; } @@ -233,7 +233,7 @@ sub is_holiday { return 1; } - if ( $self->single_holidays->contains($localdt) ) { + if ( $self->_single_holidays->contains($localdt) ) { return 1; } @@ -339,18 +339,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 ); - $single_holidays = $self->{single_holidays}; - - return; -} - 1; __END__ @@ -468,12 +456,6 @@ In test mode changes the testing set of closed days to a new set with no closed days. TODO passing an array of closed days to this would allow testing of more configurations -=head2 add_holiday - -Passed a datetime object this will add it to the calendar's list of -closed days. This is for testing so that we can alter the Calenfar object's -list of specified dates - =head1 DIAGNOSTICS Will croak if not passed a branchcode in new --- a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc @@ -87,7 +87,7 @@
Additional tools