From 436037fda4b86aa2ca94c6d2cf2da6f4526889c1 Mon Sep 17 00:00:00 2001 From: Jesse Weaver Date: Thu, 20 Jun 2013 16:54:32 -0600 Subject: [PATCH] Bug 8133 - hourly loans doesn't know when library closed This adds support for storing library hours in the calendar, and using those hours to compute hourly loan duetimes. A large amount of cleanup was also performed to expunge duplication of code between C4::Calendar and Koha::Calendar. Test plan: 1) Apply patch. 2) Update database. 3) Verify that the calendar administration interface still exists and works as expected. 4) Run t/Calendar.t and t/db_dependent/Calendar.t. --- C4/Calendar.pm | 738 ++++---------------- C4/Circulation.pm | 88 --- C4/Overdues.pm | 124 ---- Koha/Calendar.pm | 342 ++++----- .../data/mysql/de-DE/optional/sample_holidays.sql | 10 +- .../data/mysql/en/optional/sample_holidays.sql | 8 +- .../data/mysql/es-ES/optional/sample_holidays.sql | 8 +- .../data/mysql/it-IT/necessari/sample_holidays.sql | 10 +- installer/data/mysql/kohastructure.sql | 70 +- .../mysql/nb-NO/2-Valgfritt/sample_holidays.sql | 14 +- .../data/mysql/pl-PL/optional/sample_holidays.sql | 8 +- installer/data/mysql/ru-RU/optional/holidays.sql | 30 +- installer/data/mysql/uk-UA/optional/holidays.sql | 42 +- installer/data/mysql/updatedatabase.pl | 75 ++ .../intranet-tmpl/prog/en/includes/tools-menu.inc | 2 +- .../prog/en/modules/tools/calendar.tt | 597 ++++++++++++++++ .../prog/en/modules/tools/holidays.tt | 538 -------------- .../prog/en/modules/tools/tools-home.tt | 2 +- misc/cronjobs/staticfines.pl | 11 +- .../thirdparty/TalkingTech_itiva_outbound.pl | 31 +- t/Calendar.t | 143 +++- t/db_dependent/Calendar.t | 78 +++ t/db_dependent/lib/KohaTest/Calendar/New.pm | 186 ----- t/db_dependent/lib/KohaTest/Circulation.pm | 3 - t/db_dependent/lib/KohaTest/Overdues.pm | 3 - tools/calendar.pl | 255 +++++++ tools/copy-holidays.pl | 39 -- tools/exceptionHolidays.pl | 145 ---- tools/holidays.pl | 163 ----- tools/newHolidays.pl | 144 ---- 30 files changed, 1539 insertions(+), 2368 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 delete mode 100644 t/db_dependent/lib/KohaTest/Calendar/New.pm 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 diff --git a/C4/Calendar.pm b/C4/Calendar.pm index 1e687db..7131b56 100644 --- a/C4/Calendar.pm +++ b/C4/Calendar.pm @@ -15,712 +15,210 @@ 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; +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 +=head2 GetSingleEvents - $calendar = C4::Calendar->new(branchcode => $branchcode); + \@events = GetSingleEvents( $branchcode ) -Each library branch has its own Calendar. -C<$branchcode> specifies which Calendar you want. +Get the non-repeating events for the given library. =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 GetSingleEvents { + my ( $branchcode ) = @_; -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; + return C4::Context->dbh->selectall_arrayref( q{ + SELECT + event_date, open_hour, open_minute, close_hour, close_minute, title, description, + (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed + FROM calendar_events + WHERE branchcode = ? + }, { Slice => {} }, $branchcode ); } -=head2 get_week_days_holidays +=head2 GetWeeklyEvents - $week_days_holidays = $calendar->get_week_days_holidays(); + \@events = GetWeeklyEvents( $branchcode ) -Returns a hash reference to week days holidays. +Get the weekly-repeating events for the given library. =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 GetWeeklyEvents { + my ( $branchcode ) = @_; -sub get_day_month_holidays { - my $self = shift @_; - my $day_month_holidays = $self->{'day_month_holidays'}; - return $day_month_holidays; + return C4::Context->dbh->selectall_arrayref( q{ + SELECT + weekday, open_hour, open_minute, close_hour, close_minute, title, description, + (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed + FROM calendar_repeats + WHERE branchcode = ? AND weekday IS NOT NULL + }, { Slice => {} }, $branchcode ); } -=head2 get_exception_holidays +=head2 GetYearlyEvents - $exception_holidays = $calendar->exception_holidays(); + \@events = GetYearlyEvents( $branchcode ) -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. +Get the yearly-repeating events for the given library. =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(); +sub GetYearlyEvents { + my ( $branchcode ) = @_; -Returns a hash reference to single holidays. This kind of holidays are those which -happend just one time. - -=cut - -sub get_single_holidays { - my $self = shift @_; - my $single_holidays = $self->{'single_holidays'}; - return $single_holidays; + return C4::Context->dbh->selectall_arrayref( q{ + SELECT + month, day, open_hour, open_minute, close_hour, close_minute, title, description, + (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed + FROM calendar_repeats + WHERE branchcode = ? AND weekday IS NULL + }, { Slice => {} }, $branchcode ); } -=head2 insert_week_day_holiday - - insert_week_day_holiday(weekday => $weekday, - title => $title, - description => $description); - -Inserts a new week day for $self->{branchcode}. - -C<$day> Is the week day to make holiday. +=head2 ModSingleEvent -C<$title> Is the title to store for the holiday formed by $year/$month/$day. + ModSingleEvent( $branchcode, $date, \%info ) -C<$description> Is the description to store for the holiday formed by $year/$month/$day. +Creates or updates an event for a single date. $date should be an ISO-formatted +date string, and \%info should contain the following keys: open_hour, +open_minute, close_hour, close_minute, title and description. =cut -sub insert_week_day_holiday { - my $self = shift @_; - my %options = @_; +sub ModSingleEvent { + my ( $branchcode, $date, $info ) = @_; - 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; + C4::Context->dbh->do( q{ + INSERT INTO calendar_events(branchcode, event_date, open_hour, open_minute, close_hour, close_minute, title, description) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE open_hour = ?, open_minute = ?, close_hour = ?, close_minute = ?, title = ?, description = ? + }, {}, $branchcode, $date, ( map { $info->{$_} } qw(open_hour open_minute close_hour close_minute title description) ) x 2 ); } -=head2 insert_day_month_holiday - - insert_day_month_holiday(day => $day, - month => $month, - title => $title, - description => $description); - -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. +=head2 ModRepeatingEvent -C<$title> Is the title to store for the holiday formed by $year/$month/$day. + ModRepeatingEvent( $branchcode, $weekday, $month, $day, \%info ) -C<$description> Is the description to store for the holiday formed by $year/$month/$day. +Creates or updates a weekly- or yearly-repeating event. Either $weekday, +or $month and $day should be set, for a weekly or yearly event, respectively. =cut -sub insert_day_month_holiday { - my $self = shift @_; - my %options = @_; +sub ModRepeatingEvent { + my ( $branchcode, $weekday, $month, $day, $info ) = @_; - 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; + C4::Context->dbh->do( q{ + INSERT INTO calendar_repeats(branchcode, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE open_hour = ?, open_minute = ?, close_hour = ?, close_minute = ?, title = ?, description = ? + }, {}, $branchcode, $weekday, $month, $day, ( map { $info->{$_} } qw(open_hour open_minute close_hour close_minute title description) ) x 2 ); } -=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}. - -C<$day> Is the day month to make the date to insert. - -C<$month> Is month to make the date to insert. +=head2 DelSingleEvent -C<$year> Is year to make the date to insert. + DelSingleEvent( $branchcode, $date, \%info ) -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. +Deletes an event for a single date. $date should be an ISO-formatted date string. =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; -} - -=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. - -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. +sub DelSingleEvent { + my ( $branchcode, $date ) = @_; -C<$description> Is the description to store for the holiday formed by $year/$month/$day. - -=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}; - - 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; + C4::Context->dbh->do( q{ + DELETE FROM calendar_events + WHERE branchcode = ? AND event_date = ? + }, {}, $branchcode, $date ); } -=head2 ModWeekdayholiday - - ModWeekdayholiday(weekday =>$weekday, - title => $title, - description => $description) - -Modifies the title and description of a weekday for $self->{branchcode}. - -C<$weekday> Is the title to update for the holiday. - -C<$description> Is the description to update for the holiday. +sub _get_compare { + my ( $colname, $value ) = @_; -=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; + return ' AND ' . $colname . ' ' . ( defined( $value ) ? '=' : 'IS' ) . ' ?'; } -=head2 ModDaymonthholiday - - ModDaymonthholiday(day => $day, - month => $month, - title => $title, - description => $description); - -Modifies the title and description for a day/month holiday for $self->{branchcode}. +=head2 DelRepeatingEvent -C<$day> The day of the month for the update. + DelRepeatingEvent( $branchcode, $weekday, $month, $day ) -C<$month> The month to be used for the update. - -C<$title> The title to be updated for the holiday. - -C<$description> The description to be update for the holiday. +Deletes a weekly- or yearly-repeating event. Either $weekday, or $month and +$day should be set, for a weekly or yearly event, respectively. =cut -sub ModDaymonthholiday { - my $self = shift @_; - my %options = @_; +sub DelRepeatingEvent { + my ( $branchcode, $weekday, $month, $day ) = @_; - 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; + C4::Context->dbh->do( q{ + DELETE FROM calendar_repeats + WHERE branchcode = ? + } . _get_compare( 'weekday', $weekday ) . _get_compare( 'month', $month ) . _get_compare( 'day', $day ), {}, $branchcode, $weekday, $month, $day ); } -=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}. +=head2 CopyAllEvents -C<$day> Is the day of the month to make the update. + CopyAllEvents( $from_branchcode, $to_branchcode ) -C<$month> Is the month to make the update. - -C<$year> Is the year to make the update. - -C<$title> Is the title to update for the holiday formed by $year/$month/$day. - -C<$description> Is the description to update for the holiday formed by $year/$month/$day. +Copies all events from one branch to another. =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. +sub CopyAllEvents { + my ( $from_branchcode, $to_branchcode ) = @_; -C<$year> Is the year for the holiday. + C4::Context->dbh->do( q{ + INSERT IGNORE INTO calendar_events(branchcode, event_date, open_hour, open_minute, close_hour, close_minute, title, description) + SELECT ?, event_date, open_hour, open_minute, close_hour, close_minute, title, description + FROM calendar_events + WHERE branchcode = ? + }, {}, $to_branchcode, $from_branchcode ); -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. - -=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; + C4::Context->dbh->do( q{ + INSERT IGNORE INTO calendar_repeats(branchcode, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description) + SELECT ?, weekday, month, day, open_hour, open_minute, close_hour, close_minute, title, description + FROM calendar_repeats + WHERE branchcode = ? + }, {}, $to_branchcode, $from_branchcode ); } -=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. - -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 { - 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}"}); - } 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}"}); - } - } - } - 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 - - delete_holiday_range_repeatable(day => $day, - month => $month); - -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. - -=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 - - delete_exception_holiday_range(weekday => $weekday - day => $day, - month => $month, - year => $year); - -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}); -} - -=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 copy_to_branch - - $calendar->copy_to_branch($target_branch) - -=cut - -sub copy_to_branch { - my ($self, $target_branch) = @_; - - croak "No target_branch" unless $target_branch; - - 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; -} - -=head2 addDate - - my ($day, $month, $year) = $calendar->addDate($date, $offset) - -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. - -=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')); -} - -=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; diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 30cbe2f..ec3989a 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -3101,94 +3101,6 @@ sub CalcDateDue { } -=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; -$sth->finish; -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 ; -$sth->finish; -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 ; -$sth->finish; -return $countspecial; -} - - sub CheckValidBarcode{ my ($barcode) = @_; diff --git a/C4/Overdues.pm b/C4/Overdues.pm index 4fd0b84..f441cd7 100644 --- a/C4/Overdues.pm +++ b/C4/Overdues.pm @@ -306,130 +306,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); diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm index 6a12530..77db08a 100644 --- a/Koha/Calendar.pm +++ b/Koha/Calendar.pm @@ -18,10 +18,6 @@ sub new { my $o = lc $o_name; $self->{$o} = $options{$o_name}; } - if ( exists $options{TEST_MODE} ) { - $self->_mockinit(); - return $self; - } if ( !defined $self->{branchcode} ) { croak 'No branchcode argument passed to Koha::Calendar->new'; } @@ -33,57 +29,36 @@ sub _init { my $self = shift; my $branch = $self->{branchcode}; my $dbh = C4::Context->dbh(); - my $weekly_closed_days_sth = $dbh->prepare( -'SELECT weekday FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NOT NULL' - ); - $weekly_closed_days_sth->execute( $branch ); - $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ]; - Readonly::Scalar my $sunday => 7; - while ( my $tuple = $weekly_closed_days_sth->fetchrow_hashref ) { - $self->{weekly_closed_days}->[ $tuple->{weekday} ] = 1; - } - my $day_month_closed_days_sth = $dbh->prepare( -'SELECT day, month FROM repeatable_holidays WHERE branchcode = ? AND weekday IS NULL' - ); - $day_month_closed_days_sth->execute( $branch ); - $self->{day_month_closed_days} = {}; - while ( my $tuple = $day_month_closed_days_sth->fetchrow_hashref ) { - $self->{day_month_closed_days}->{ $tuple->{month} }->{ $tuple->{day} } = - 1; - } - my $exception_holidays_sth = $dbh->prepare( -'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 1' - ); - $exception_holidays_sth->execute( $branch ); - my $dates = []; - while ( my ( $day, $month, $year ) = $exception_holidays_sth->fetchrow ) { - push @{$dates}, - DateTime->new( - day => $day, - month => $month, - year => $year, - time_zone => C4::Context->tz() - )->truncate( to => 'day' ); + $self->{weekday_hours} = $dbh->selectall_hashref( q{ + SELECT + weekday, open_hour, open_minute, close_hour, close_minute, + (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed + FROM calendar_repeats + WHERE branchcode = ? AND weekday IS NOT NULL + }, 'weekday', { Slice => {} }, $branch ); + + my $day_month_hours = $dbh->selectall_arrayref( q{ + SELECT + month, day, open_hour, open_minute, close_hour, close_minute, + (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed + FROM calendar_repeats + WHERE branchcode = ? AND weekday IS NULL + }, { Slice => {} }, $branch ); + + # DBD::Mock doesn't support multi-key selectall_hashref, so we do it ourselves for now + foreach my $day_month ( @$day_month_hours ) { + $self->{day_month_hours}->{ $day_month->{month} }->{ $day_month->{day} } = $day_month; } - $self->{exception_holidays} = - DateTime::Set->from_datetimes( dates => $dates ); - - my $single_holidays_sth = $dbh->prepare( -'SELECT day, month, year FROM special_holidays WHERE branchcode = ? AND isexception = 0' - ); - $single_holidays_sth->execute( $branch ); - $dates = []; - while ( my ( $day, $month, $year ) = $single_holidays_sth->fetchrow ) { - push @{$dates}, - DateTime->new( - day => $day, - month => $month, - year => $year, - time_zone => C4::Context->tz() - )->truncate( to => 'day' ); - } - $self->{single_holidays} = DateTime::Set->from_datetimes( dates => $dates ); + + $self->{date_hours} = $dbh->selectall_hashref( q{ + SELECT + event_date, open_hour, open_minute, close_hour, close_minute, + (open_hour = 0 AND open_minute = 0 AND close_hour = 0 AND close_minute = 0) AS closed + FROM calendar_events + WHERE branchcode = ? + }, 'event_date', { Slice => {} }, $branch ); + $self->{days_mode} = C4::Context->preference('useDaysMode'); $self->{test} = 0; return; @@ -101,10 +76,7 @@ sub addDate { my $dt; if ( $unit eq 'hours' ) { - # Fixed for legacy support. Should be set as a branch parameter - Readonly::Scalar my $return_by_hour => 10; - - $dt = $self->addHours($startdate, $add_duration, $return_by_hour); + $dt = $self->addHours($startdate, $add_duration); } else { # days $dt = $self->addDays($startdate, $add_duration); @@ -114,25 +86,73 @@ sub addDate { } sub addHours { - my ( $self, $startdate, $hours_duration, $return_by_hour ) = @_; + my ( $self, $startdate, $hours_duration ) = @_; my $base_date = $startdate->clone(); - $base_date->add_duration($hours_duration); + if ( $self->{days_mode} eq 'Days' ) { + $base_date->add_duration( $hours_duration ); + return $base_date; + } + my $hours = $self->get_hours_full( $base_date ); + + if ( $hours_duration->is_negative() ) { + if ( $base_date <= $hours->{open_time} ) { + # Library is already closed + $base_date = $self->prev_open_day( $base_date ); + $hours = $self->get_hours_full( $base_date ); + $base_date = $hours->{close_time}->clone; + + if ( $self->{days_mode} eq 'Calendar' ) { + return $base_date; + } + } - # If we are using the calendar behave for now as if Datedue - # was the chosen option (current intended behaviour) + while ( $hours_duration->is_negative ) { + my $day_len = $hours->{open_time} - $base_date; - if ( $self->{days_mode} ne 'Days' && - $self->is_holiday($base_date) ) { + if ( DateTime::Duration->compare( $day_len, $hours_duration, $base_date ) > 0 ) { + if ( $self->{days_mode} eq 'Calendar' ) { + return $hours->{open_time}; + } - if ( $hours_duration->is_negative() ) { - $base_date = $self->prev_open_day($base_date); - } else { - $base_date = $self->next_open_day($base_date); + $hours_duration->subtract( $day_len ); + $base_date = $self->prev_open_day( $base_date ); + $hours = $self->get_hours_full( $base_date ); + $base_date = $hours->{close_time}->clone; + } else { + $base_date->add_duration( $hours_duration ); + return $base_date; + } + } + } else { + if ( $base_date >= $hours->{close_time} ) { + # Library is already closed + $base_date = $self->next_open_day( $base_date ); + $hours = $self->get_hours_full( $base_date ); + $base_date = $hours->{open_time}->clone; + + if ( $self->{days_mode} eq 'Calendar' ) { + return $base_date; + } } - $base_date->set_hour($return_by_hour); + while ( $hours_duration->is_positive ) { + my $day_len = $hours->{close_time} - $base_date; + + if ( DateTime::Duration->compare( $day_len, $hours_duration, $base_date ) < 0 ) { + if ( $self->{days_mode} eq 'Calendar' ) { + return $hours->{close_time}; + } + $hours_duration->subtract( $day_len ); + $base_date = $self->next_open_day( $base_date ); + $hours = $self->get_hours_full( $base_date ); + $base_date = $hours->{open_time}->clone; + } else { + $base_date->add_duration( $hours_duration ); + return $base_date; + } + } } return $base_date; @@ -182,33 +202,25 @@ sub addDays { sub is_holiday { my ( $self, $dt ) = @_; - my $localdt = $dt->clone(); - my $day = $localdt->day; - my $month = $localdt->month; - - $localdt->truncate( to => 'day' ); + my $day = $dt->day; + my $month = $dt->month; - if ( $self->{exception_holidays}->contains($localdt) ) { - # exceptions are not holidays + if ( exists $self->{date_hours}->{ $dt->ymd } && !$self->{date_hours}->{ $dt->ymd }->{closed} ) { return 0; } - my $dow = $localdt->day_of_week; - # Representation fix - # TODO: Shouldn't we shift the rest of the $dow also? - if ( $dow == 7 ) { - $dow = 0; - } - - if ( $self->{weekly_closed_days}->[$dow] == 1 ) { + if ( ( $self->{day_month_hours}->{$month}->{$day} || {} )->{closed} ) { return 1; } - if ( exists $self->{day_month_closed_days}->{$month}->{$day} ) { + # We use 0 for Sunday, not 7 + my $dow = $dt->day_of_week % 7; + + if ( ( $self->{weekday_hours}->{ $dow } || {} )->{closed} ) { return 1; } - if ( $self->{single_holidays}->contains($localdt) ) { + if ( ( $self->{date_hours}->{ $dt->ymd } || {} )->{closed} ) { return 1; } @@ -216,6 +228,60 @@ sub is_holiday { return 0; } +sub get_hours { + my ( $self, $dt ) = @_; + my $day = $dt->day; + my $month = $dt->month; + + if ( exists $self->{date_hours}->{ $dt->ymd } ) { + return $self->{date_hours}->{ $dt->ymd }; + } + + if ( exists $self->{day_month_hours}->{$month}->{$day} ) { + return $self->{day_month_hours}->{$month}->{$day}; + } + + # We use 0 for Sunday, not 7 + my $dow = $dt->day_of_week % 7; + + if ( exists $self->{weekday_hours}->{ $dow } ) { + return $self->{weekday_hours}->{ $dow }; + } + + # Assume open + return { + open_hour => 0, + open_minute => 0, + close_hour => 24, + close_minute => 0, + closed => 0 + }; +} + +sub get_hours_full { + my ( $self, $dt ) = @_; + + my $hours = { %{ $self->get_hours( $dt ) } }; + + $hours->{open_time} = $dt + ->clone->truncate( to => 'day' ) + ->set_hour( $hours->{open_hour} ) + ->set_minute( $hours->{open_minute} ); + + if ( $hours->{close_hour} == 24 ) { + $hours->{close_time} = $dt + ->clone->truncate( to => 'day' ) + ->add( days => 1 ); + } else { + $hours->{close_time} = $dt + ->clone->truncate( to => 'day' ) + ->set_hour( $hours->{close_hour} ) + ->set_minute( $hours->{close_minute} ); + } + + return $hours; +} + sub next_open_day { my ( $self, $dt ) = @_; my $base_date = $dt->clone(); @@ -273,81 +339,39 @@ sub hours_between { my ($self, $start_date, $end_date) = @_; my $start_dt = $start_date->clone(); my $end_dt = $end_date->clone(); - my $duration = $end_dt->delta_ms($start_dt); - $start_dt->truncate( to => 'day' ); - $end_dt->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; - for (my $dt = $start_dt->clone(); - $dt <= $end_dt; - $dt->add(days => 1) - ) { - if ($self->is_holiday($dt)) { - ++$skipped_days; - } - } - if ($skipped_days) { - $duration->subtract_duration(DateTime::Duration->new( hours => 24 * $skipped_days)); + + if ( $start_dt->compare($end_dt) > 0 ) { + # swap dates + my $int_dt = $end_dt; + $end_dt = $start_dt; + $start_dt = $int_dt; } - return $duration; + my $start_hours = $self->get_hours_full( $start_dt ); + my $end_hours = $self->get_hours_full( $end_dt ); -} + $start_dt = $start_hours->{open_time} if ( $start_dt < $start_hours->{open_time} ); + $end_dt = $end_hours->{close_time} if ( $end_dt > $end_hours->{close_time} ); -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'; - } + return $end_dt - $start_dt if ( $start_dt->ymd eq $end_dt->ymd ); - $self->{test} = 1; - return; -} + my $duration = DateTime::Duration->new; + + $duration->add_duration( $start_hours->{close_time} - $start_dt ) if ( $start_dt < $start_hours->{close_time} ); -sub set_daysmode { - my ( $self, $mode ) = @_; + for (my $date = $start_dt->clone->truncate( to => 'day' )->add( days => 1 ); + $date->ymd lt $end_dt->ymd; + $date->add(days => 1) + ) { + my $hours = $self->get_hours_full( $date ); - # if not testing this is a no op - if ( $self->{test} ) { - $self->{days_mode} = $mode; + $duration->add_duration( $hours->{close_time}->delta_ms( $hours->{open_time} ) ); } - return; -} - -sub clear_weekly_closed_days { - my $self = shift; - $self->{weekly_closed_days} = [ 0, 0, 0, 0, 0, 0, 0 ]; # Sunday only - return; -} + $duration->add_duration( $end_dt - $end_hours->{open_time} ) if ( $end_dt > $start_hours->{open_time} ); -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 $duration; - return; } 1; @@ -403,14 +427,12 @@ parameter will be removed when issuingrules properly cope with that =head2 addHours - my $dt = $calendar->addHours($date, $dur, $return_by_hour ) + my $dt = $calendar->addHours($date, $dur ) C<$date> is a DateTime object representing the starting date of the interval. C<$offset> is a DateTime::Duration to add to it -C<$return_by_hour> is an integer value representing the opening hour for the branch - =head2 addDays @@ -457,22 +479,6 @@ Passed a Datetime returns another Datetime representing the previous open day. I intended for use to calculate the due date when useDaysMode syspref is set to either 'Datedue' or 'Calendar'. -=head2 set_daysmode - -For testing only allows the calling script to change days mode - -=head2 clear_weekly_closed_days - -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 diff --git a/installer/data/mysql/de-DE/optional/sample_holidays.sql b/installer/data/mysql/de-DE/optional/sample_holidays.sql index 124fcad..7f18bf2 100644 --- a/installer/data/mysql/de-DE/optional/sample_holidays.sql +++ b/installer/data/mysql/de-DE/optional/sample_holidays.sql @@ -1,5 +1,5 @@ -INSERT INTO `repeatable_holidays` VALUES -(2,'MPL',0,NULL,NULL,'','Sonntag'), -(3,'MPL',NULL,1,1,'','Neujahr'), -(4,'MPL',NULL,25,12,'','1. Weihnachtsfeiertag'), -(5,'MPL',NULL,25,12,'','2. Weihnachtsfeiertag'); +INSERT INTO `calendar_repeats` VALUES +(2,'MPL',0,NULL,NULL,'','Sonntag',0,0,0,0), +(3,'MPL',NULL,1,1,'','Neujahr',0,0,0,0), +(4,'MPL',NULL,12,25,'','1. Weihnachtsfeiertag',0,0,0,0), +(5,'MPL',NULL,12,25,'','2. Weihnachtsfeiertag',0,0,0,0); diff --git a/installer/data/mysql/en/optional/sample_holidays.sql b/installer/data/mysql/en/optional/sample_holidays.sql index 33b6ff6..866c14f 100644 --- a/installer/data/mysql/en/optional/sample_holidays.sql +++ b/installer/data/mysql/en/optional/sample_holidays.sql @@ -1,4 +1,4 @@ -INSERT INTO `repeatable_holidays` VALUES -(2,'MPL',0,NULL,NULL,'','Sundays'), -(3,'MPL',NULL,1,1,'','New Year\'s Day'), -(4,'MPL',NULL,25,12,'','Christmas'); +INSERT INTO `calendar_repeats` VALUES +(2,'MPL',0,NULL,NULL,'','Sundays',0,0,0,0), +(3,'MPL',NULL,1,1,'','New Year\'s Day',0,0,0,0), +(4,'MPL',NULL,12,25,'','Christmas',0,0,0,0); diff --git a/installer/data/mysql/es-ES/optional/sample_holidays.sql b/installer/data/mysql/es-ES/optional/sample_holidays.sql index e323317..1cf78ec 100644 --- a/installer/data/mysql/es-ES/optional/sample_holidays.sql +++ b/installer/data/mysql/es-ES/optional/sample_holidays.sql @@ -1,4 +1,4 @@ -INSERT INTO `repeatable_holidays` VALUES -(2,'',0,NULL,NULL,'','Sundays'), -(3,'',NULL,1,1,'','New Year\'s Day'), -(4,'',NULL,25,12,'','Christmas'); +INSERT INTO `calendar_repeats` VALUES +(2,'',0,NULL,NULL,'','Sundays',0,0,0,0), +(3,'',NULL,1,1,'','New Year\'s Day',0,0,0,0), +(4,'',NULL,12,25,'','Christmas',0,0,0,0); diff --git a/installer/data/mysql/it-IT/necessari/sample_holidays.sql b/installer/data/mysql/it-IT/necessari/sample_holidays.sql index 67640a9..f1478de 100644 --- a/installer/data/mysql/it-IT/necessari/sample_holidays.sql +++ b/installer/data/mysql/it-IT/necessari/sample_holidays.sql @@ -1,8 +1,8 @@ SET FOREIGN_KEY_CHECKS=0; -INSERT INTO `repeatable_holidays` VALUES -(2,'',0,NULL,NULL,'','Domenica'), -(3,'',NULL,1,1,'','Nuovo anno'), -(4,'',NULL,25,12,'','Natale'); +INSERT INTO `calendar_repeats` VALUES +(2,'',0,NULL,NULL,'','Domenica',0,0,0,0), +(3,'',NULL,1,1,'','Nuovo anno',0,0,0,0), +(4,'',NULL,12,25,'','Natale',0,0,0,0); -SET FOREIGN_KEY_CHECKS=1; \ No newline at end of file +SET FOREIGN_KEY_CHECKS=1; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index d7eebdd..0721f7b 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -640,6 +640,43 @@ CREATE TABLE `default_circ_rules` ( PRIMARY KEY (`singleton`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `calendar_events` +-- +DROP TABLE IF EXISTS `calendar_events`; +CREATE TABLE `calendar_events` ( + `branchcode` varchar(10) NOT NULL DEFAULT '', + `event_date` date NOT NULL, + `title` varchar(50) NOT NULL DEFAULT '', + `description` text NOT NULL, + `open_hour` smallint(6) NOT NULL, + `open_minute` smallint(6) NOT NULL, + `close_hour` smallint(6) NOT NULL, + `close_minute` smallint(6) NOT NULL, + PRIMARY KEY (`branchcode`,`event_date`), + CONSTRAINT `calendar_events_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `calendar_repeats` +-- +DROP TABLE IF EXISTS `calendar_repeats`; +CREATE TABLE `calendar_repeats` ( + `branchcode` varchar(10) NOT NULL DEFAULT '', + `weekday` smallint(6) DEFAULT NULL, + `month` smallint(6) DEFAULT NULL, + `day` smallint(6) DEFAULT NULL, + `title` varchar(50) NOT NULL DEFAULT '', + `description` text NOT NULL, + `open_hour` smallint(6) NOT NULL, + `open_minute` smallint(6) NOT NULL, + `close_hour` smallint(6) NOT NULL, + `close_minute` smallint(6) NOT NULL, + UNIQUE KEY `branchcode` (`branchcode`,`weekday`), + UNIQUE KEY `branchcode_2` (`branchcode`,`month`,`day`), + CONSTRAINT `calendar_repeats_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Table structure for table `cities` -- @@ -1719,22 +1756,6 @@ CREATE TABLE `printers_profile` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- --- Table structure for table `repeatable_holidays` --- - -DROP TABLE IF EXISTS `repeatable_holidays`; -CREATE TABLE `repeatable_holidays` ( -- information for the days the library is closed - `id` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha - `branchcode` varchar(10) NOT NULL default '', -- foreign key from the branches table, defines which branch this closing is for - `weekday` smallint(6) default NULL, -- day of the week (0=Sunday, 1=Monday, etc) this closing is repeated on - `day` smallint(6) default NULL, -- day of the month this closing is on - `month` smallint(6) default NULL, -- month this closing is in - `title` varchar(50) NOT NULL default '', -- title of this closing - `description` text NOT NULL, -- description for this closing - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- -- Table structure for table `reports_dictionary` -- @@ -1917,23 +1938,6 @@ CREATE TABLE sessions ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- --- Table structure for table `special_holidays` --- - -DROP TABLE IF EXISTS `special_holidays`; -CREATE TABLE `special_holidays` ( -- non repeatable holidays/library closings - `id` int(11) NOT NULL auto_increment, -- unique identifier assigned by Koha - `branchcode` varchar(10) NOT NULL default '', -- foreign key from the branches table, defines which branch this closing is for - `day` smallint(6) NOT NULL default 0, -- day of the month this closing is on - `month` smallint(6) NOT NULL default 0, -- month this closing is in - `year` smallint(6) NOT NULL default 0, -- year this closing is in - `isexception` smallint(1) NOT NULL default 1, -- is this a holiday exception to a repeatable holiday (1 for yes, 0 for no) - `title` varchar(50) NOT NULL default '', -- title for this closing - `description` text NOT NULL, -- description of this closing - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- -- Table structure for table `statistics` -- diff --git a/installer/data/mysql/nb-NO/2-Valgfritt/sample_holidays.sql b/installer/data/mysql/nb-NO/2-Valgfritt/sample_holidays.sql index 7df9e67..d2b5ab7 100644 --- a/installer/data/mysql/nb-NO/2-Valgfritt/sample_holidays.sql +++ b/installer/data/mysql/nb-NO/2-Valgfritt/sample_holidays.sql @@ -19,10 +19,10 @@ -- with Koha; if not, write to the Free Software Foundation, Inc., -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -INSERT INTO `repeatable_holidays` VALUES -(2,'',0,NULL,NULL,'','Søndager'), -(3,'',NULL,1,1,'','1. nyttårsdag'), -(4,'',NULL,1,5,'','1. mai'), -(5,'',NULL,17,5,'','17. mai'), -(6,'',NULL,25,12,'','1. juledag'), -(7,'',NULL,26,12,'','2. juledag'); +INSERT INTO `calendar_repeats` VALUES +(2,'',0,NULL,NULL,'','Søndager',0,0,0,0), +(3,'',NULL,1,1,'','1. nyttårsdag',0,0,0,0), +(4,'',NULL,5,1,'','1. mai',0,0,0,0), +(5,'',NULL,5,17,'','17. mai',0,0,0,0), +(6,'',NULL,12,25,'','1. juledag',0,0,0,0), +(7,'',NULL,12,26,'','2. juledag',0,0,0,0); diff --git a/installer/data/mysql/pl-PL/optional/sample_holidays.sql b/installer/data/mysql/pl-PL/optional/sample_holidays.sql index bee37b5..6dfd59d 100644 --- a/installer/data/mysql/pl-PL/optional/sample_holidays.sql +++ b/installer/data/mysql/pl-PL/optional/sample_holidays.sql @@ -1,4 +1,4 @@ -INSERT INTO `repeatable_holidays` VALUES -(2,'',0,NULL,NULL,'','Niedziele'), -(3,'',NULL,1,1,'','Nowy Rok'), -(4,'',NULL,25,12,'','Boże Narodzenie'); +INSERT INTO `calendar_repeats` VALUES +(2,'',0,NULL,NULL,'','Niedziele',0,0,0,0), +(3,'',NULL,1,1,'','Nowy Rok',0,0,0,0), +(4,'',NULL,12,25,'','Boże Narodzenie',0,0,0,0); diff --git a/installer/data/mysql/ru-RU/optional/holidays.sql b/installer/data/mysql/ru-RU/optional/holidays.sql index 42f3311..7d8e00b 100644 --- a/installer/data/mysql/ru-RU/optional/holidays.sql +++ b/installer/data/mysql/ru-RU/optional/holidays.sql @@ -1,23 +1,23 @@ -TRUNCATE repeatable_holidays; +TRUNCATE calendar_repeats; -INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) -VALUES (2, '',0,NULL,NULL,'','Воскресенья'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) +VALUES ('',0,NULL,NULL,'','Воскресенья', 0, 0, 0, 0); -INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) -VALUES (3, '',NULL,1,1,'','Новый год'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) +VALUES ('',NULL,1,1,'','Новый год', 0, 0, 0, 0); -INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) -VALUES (4, '',NULL,7,1,'','Рождество'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) +VALUES ('',NULL,7,1,'','Рождество', 0, 0, 0, 0); -INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) -VALUES (5, '',NULL,8,3,'','Международный женский день'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) +VALUES ('',NULL,8,3,'','Международный женский день', 0, 0, 0, 0); -INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) -VALUES (6, '',NULL,1,5,'','День Труда'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) +VALUES ('',NULL,1,5,'','День Труда', 0, 0, 0, 0); -INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) -VALUES (7, '',NULL,2,5,'','День Труда'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) +VALUES ('',NULL,2,5,'','День Труда', 0, 0, 0, 0); -INSERT INTO `repeatable_holidays` (`id`, `branchcode`, `weekday`, `day`, `month`, `title`, `description`) -VALUES (8, '',NULL,9,5,'','День Победы'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) +VALUES ('',NULL,9,5,'','День Победы', 0, 0, 0, 0); diff --git a/installer/data/mysql/uk-UA/optional/holidays.sql b/installer/data/mysql/uk-UA/optional/holidays.sql index 55f45be..f6ce5bd 100644 --- a/installer/data/mysql/uk-UA/optional/holidays.sql +++ b/installer/data/mysql/uk-UA/optional/holidays.sql @@ -1,24 +1,24 @@ -TRUNCATE repeatable_holidays; +TRUNCATE calendar_repeats; -INSERT INTO `repeatable_holidays` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`) VALUES -('STL', 0, NULL, NULL,'', 'Неділі'), -('STL', NULL, 1, 1, '', 'Новий рік'), -('STL', NULL, 7, 1, '', 'Різдво'), -('STL', NULL, 8, 3, '', 'Міжнародний жіночий день'), -('STL', NULL, 1, 5, '', 'День Праці'), -('STL', NULL, 2, 5, '', 'День Праці'), -('STL', NULL, 9, 5, '', 'День Перемоги'), -('STL', NULL, 28, 6, '', 'День Конституції'), -('STL', NULL, 24, 8, '', 'День Незалежності'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) VALUES +('STL', 0, NULL, NULL,'', 'Неділі', 0, 0, 0, 0), +('STL', NULL, 1, 1, '', 'Новий рік', 0, 0, 0, 0), +('STL', NULL, 7, 1, '', 'Різдво', 0, 0, 0, 0), +('STL', NULL, 8, 3, '', 'Міжнародний жіночий день', 0, 0, 0, 0), +('STL', NULL, 1, 5, '', 'День Праці', 0, 0, 0, 0), +('STL', NULL, 2, 5, '', 'День Праці', 0, 0, 0, 0), +('STL', NULL, 9, 5, '', 'День Перемоги', 0, 0, 0, 0), +('STL', NULL, 28, 6, '', 'День Конституції', 0, 0, 0, 0), +('STL', NULL, 24, 8, '', 'День Незалежності', 0, 0, 0, 0); -INSERT INTO `repeatable_holidays` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`) VALUES -('LNSL', 0, NULL, NULL,'', 'Неділі'), -('LNSL', NULL, 1, 1, '', 'Новий рік'), -('LNSL', NULL, 7, 1, '', 'Різдво'), -('LNSL', NULL, 8, 3, '', 'Міжнародний жіночий день'), -('LNSL', NULL, 1, 5, '', 'День Праці'), -('LNSL', NULL, 2, 5, '', 'День Праці'), -('LNSL', NULL, 9, 5, '', 'День Перемоги'), -('LNSL', NULL, 28, 6, '', 'День Конституції'), -('LNSL', NULL, 24, 8, '', 'День Незалежності'); +INSERT INTO `calendar_repeats` (`branchcode`, `weekday`, `day`, `month`, `title`, `description`, open_hour, open_minute, close_hour, close_minute) VALUES +('LNSL', 0, NULL, NULL,'', 'Неділі', 0, 0, 0, 0), +('LNSL', NULL, 1, 1, '', 'Новий рік', 0, 0, 0, 0), +('LNSL', NULL, 7, 1, '', 'Різдво', 0, 0, 0, 0), +('LNSL', NULL, 8, 3, '', 'Міжнародний жіночий день', 0, 0, 0, 0), +('LNSL', NULL, 1, 5, '', 'День Праці', 0, 0, 0, 0), +('LNSL', NULL, 2, 5, '', 'День Праці', 0, 0, 0, 0), +('LNSL', NULL, 9, 5, '', 'День Перемоги', 0, 0, 0, 0), +('LNSL', NULL, 28, 6, '', 'День Конституції', 0, 0, 0, 0), +('LNSL', NULL, 24, 8, '', 'День Незалежності', 0, 0, 0, 0); diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 5963d24..91c8167 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/installer/data/mysql/updatedatabase.pl @@ -7010,6 +7010,81 @@ CREATE TABLE IF NOT EXISTS borrower_files ( SetVersion($DBversion); } +$DBversion = "3.13.00.XXX"; +if ( CheckVersion($DBversion) ) { + print "Upgrade to $DBversion done (Bug 8133: create tables, migrate data to calendar_*)\n"; + + $dbh->do( q{ + CREATE TABLE `calendar_events` ( + `branchcode` varchar(10) NOT NULL DEFAULT '', + `event_date` date NOT NULL, + `title` varchar(50) NOT NULL DEFAULT '', + `description` text NOT NULL, + `open_hour` smallint(6) NOT NULL, + `open_minute` smallint(6) NOT NULL, + `close_hour` smallint(6) NOT NULL, + `close_minute` smallint(6) NOT NULL, + PRIMARY KEY (`branchcode`,`event_date`), + CONSTRAINT `calendar_events_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + } ); + + $dbh->do( q{ + CREATE TABLE `calendar_repeats` ( + `branchcode` varchar(10) NOT NULL DEFAULT '', + `weekday` smallint(6) DEFAULT NULL, + `month` smallint(6) DEFAULT NULL, + `day` smallint(6) DEFAULT NULL, + `title` varchar(50) NOT NULL DEFAULT '', + `description` text NOT NULL, + `open_hour` smallint(6) NOT NULL, + `open_minute` smallint(6) NOT NULL, + `close_hour` smallint(6) NOT NULL, + `close_minute` smallint(6) NOT NULL, + UNIQUE KEY `branchcode` (`branchcode`,`weekday`), + UNIQUE KEY `branchcode_2` (`branchcode`,`month`,`day`), + CONSTRAINT `calendar_repeats_ibfk_1` FOREIGN KEY (`branchcode`) REFERENCES `branches` (`branchcode`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + } ); + + $dbh->do( q{ + INSERT INTO + calendar_events(branchcode, event_date, title, description, open_hour, open_minute, close_hour, close_minute) + SELECT + branchcode, CONCAT_WS('-', year, month, day), title, description, 0, 0, 0, 0 + FROM special_holidays + WHERE isexception = 0 + } ); + + $dbh->do( q{ + INSERT INTO + calendar_events(branchcode, event_date, title, description, open_hour, open_minute, close_hour, close_minute) + SELECT + branchcode, CONCAT_WS('-', year, month, day), title, description, 0, 0, 24, 0 + FROM special_holidays + WHERE isexception = 1 + } ); + + $dbh->do( q{ + INSERT INTO + calendar_repeats(branchcode, weekday, month, day, title, description, open_hour, open_minute, close_hour, close_minute) + SELECT + branchcode, weekday, month, day, title, description, 0, 0, 0, 0 + FROM repeatable_holidays + WHERE weekday IS NULL + } ); + + $dbh->do( q{ + DROP TABLE repeatable_holidays; + } ); + + $dbh->do( q{ + DROP TABLE special_holidays; + } ); + + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc index e4fd8c7..3811264 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc @@ -81,7 +81,7 @@
Additional tools