3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free Software
7 # Foundation; either version 2 of the License, or (at your option) any later
10 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License along with
15 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
16 # Suite 330, Boston, MA 02111-1307 USA
19 use vars qw($VERSION @EXPORT);
22 use Date::Calc qw( Date_to_Days );
27 # set the version for version checking
31 &get_week_days_holidays
32 &get_day_month_holidays
33 &get_exception_holidays
35 &insert_week_day_holiday
36 &insert_day_month_holiday
37 &insert_single_holiday
38 &insert_exception_holiday
48 C4::Calendar::Calendar - Koha module dealing with holidays.
52 use C4::Calendar::Calendar;
56 This package is used to deal with holidays. Through this package, you can set all kind of holidays for the library.
64 $calendar = C4::Calendar->new(branchcode => $branchcode);
66 Each library branch has its own Calendar.
67 C<$branchcode> specifies which Calendar you want.
72 my $classname = shift @_;
74 my $self = bless({}, $classname);
75 foreach my $optionName (keys %options) {
76 $self->{lc($optionName)} = $options{$optionName};
78 defined($self->{branchcode}) or croak "No branchcode argument to new. Should be C4::Calendar->new(branchcode => \$branchcode)";
79 $self->_init($self->{branchcode});
86 defined($branch) or die "No branchcode sent to _init"; # must test for defined here and above to allow ""
87 my $dbh = C4::Context->dbh();
88 my $repeatable = $dbh->prepare( 'SELECT *
89 FROM repeatable_holidays
90 WHERE ( branchcode = ? )
91 AND (ISNULL(weekday) = ?)' );
92 $repeatable->execute($branch,0);
93 my %week_days_holidays;
94 while (my $row = $repeatable->fetchrow_hashref) {
95 my $key = $row->{weekday};
96 $week_days_holidays{$key}{title} = $row->{title};
97 $week_days_holidays{$key}{description} = $row->{description};
99 $self->{'week_days_holidays'} = \%week_days_holidays;
101 $repeatable->execute($branch,1);
102 my %day_month_holidays;
103 while (my $row = $repeatable->fetchrow_hashref) {
104 my $key = $row->{month} . "/" . $row->{day};
105 $day_month_holidays{$key}{title} = $row->{title};
106 $day_month_holidays{$key}{description} = $row->{description}
108 $self->{'day_month_holidays'} = \%day_month_holidays;
110 my $special = $dbh->prepare( 'SELECT day, month, year, title, description
111 FROM special_holidays
112 WHERE ( branchcode = ? )
113 AND (isexception = ?)' );
114 $special->execute($branch,1);
115 my %exception_holidays;
116 while (my ($day, $month, $year, $title, $description) = $special->fetchrow) {
117 $exception_holidays{"$year/$month/$day"}{title} = $title;
118 $exception_holidays{"$year/$month/$day"}{description} = $description;
120 $self->{'exception_holidays'} = \%exception_holidays;
122 $special->execute($branch,0);
124 while (my ($day, $month, $year, $title, $description) = $special->fetchrow) {
125 $single_holidays{"$year/$month/$day"}{title} = $title;
126 $single_holidays{"$year/$month/$day"}{description} = $description;
128 $self->{'single_holidays'} = \%single_holidays;
132 =item get_week_days_holidays
134 $week_days_holidays = $calendar->get_week_days_holidays();
136 Returns a hash reference to week days holidays.
140 sub get_week_days_holidays {
142 my $week_days_holidays = $self->{'week_days_holidays'};
143 return $week_days_holidays;
146 =item get_day_month_holidays
148 $day_month_holidays = $calendar->get_day_month_holidays();
150 Returns a hash reference to day month holidays.
154 sub get_day_month_holidays {
156 my $day_month_holidays = $self->{'day_month_holidays'};
157 return $day_month_holidays;
160 =item get_exception_holidays
162 $exception_holidays = $calendar->exception_holidays();
164 Returns a hash reference to exception holidays. This kind of days are those
165 which stands for a holiday, but you wanted to make an exception for this particular
170 sub get_exception_holidays {
172 my $exception_holidays = $self->{'exception_holidays'};
173 return $exception_holidays;
176 =item get_single_holidays
178 $single_holidays = $calendar->get_single_holidays();
180 Returns a hash reference to single holidays. This kind of holidays are those which
181 happend just one time.
185 sub get_single_holidays {
187 my $single_holidays = $self->{'single_holidays'};
188 return $single_holidays;
191 =item insert_week_day_holiday
193 insert_week_day_holiday(weekday => $weekday,
195 description => $description);
197 Inserts a new week day for $self->{branchcode}.
199 C<$day> Is the week day to make holiday.
201 C<$title> Is the title to store for the holiday formed by $year/$month/$day.
203 C<$description> Is the description to store for the holiday formed by $year/$month/$day.
207 sub insert_week_day_holiday {
211 my $dbh = C4::Context->dbh();
212 my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ( '',?,?,NULL,NULL,?,? )");
213 $insertHoliday->execute( $self->{branchcode}, $options{weekday},$options{title}, $options{description});
214 $insertHoliday->finish;
216 $self->{'week_days_holidays'}->{$options{weekday}}{title} = $options{title};
217 $self->{'week_days_holidays'}->{$options{weekday}}{description} = $options{description};
221 =item insert_day_month_holiday
223 insert_day_month_holiday(day => $day,
226 description => $description);
228 Inserts a new day month holiday for $self->{branchcode}.
230 C<$day> Is the day month to make the date to insert.
232 C<$month> Is month to make the date to insert.
234 C<$title> Is the title to store for the holiday formed by $year/$month/$day.
236 C<$description> Is the description to store for the holiday formed by $year/$month/$day.
240 sub insert_day_month_holiday {
244 my $dbh = C4::Context->dbh();
245 my $insertHoliday = $dbh->prepare("insert into repeatable_holidays (id,branchcode,weekday,day,month,title,description) values ('', ?, NULL, ?, ?, ?,? )");
246 $insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{title}, $options{description});
247 $insertHoliday->finish;
249 $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title};
250 $self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description};
254 =item insert_single_holiday
256 insert_single_holiday(day => $day,
260 description => $description);
262 Inserts a new single holiday for $self->{branchcode}.
264 C<$day> Is the day month to make the date to insert.
266 C<$month> Is month to make the date to insert.
268 C<$year> Is year to make the date to insert.
270 C<$title> Is the title to store for the holiday formed by $year/$month/$day.
272 C<$description> Is the description to store for the holiday formed by $year/$month/$day.
276 sub insert_single_holiday {
280 my $dbh = C4::Context->dbh();
282 my $insertHoliday = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)");
283 $insertHoliday->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description});
284 $insertHoliday->finish;
286 $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
287 $self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
291 =item insert_exception_holiday
293 insert_exception_holiday(day => $day,
297 description => $description);
299 Inserts a new exception holiday for $self->{branchcode}.
301 C<$day> Is the day month to make the date to insert.
303 C<$month> Is month to make the date to insert.
305 C<$year> Is year to make the date to insert.
307 C<$title> Is the title to store for the holiday formed by $year/$month/$day.
309 C<$description> Is the description to store for the holiday formed by $year/$month/$day.
313 sub insert_exception_holiday {
317 my $dbh = C4::Context->dbh();
319 my $insertException = $dbh->prepare("insert into special_holidays (id,branchcode,day,month,year,isexception,title,description) values ('', ?,?,?,?,?,?,?)");
320 $insertException->execute( $self->{branchcode}, $options{day},$options{month},$options{year}, $isexception, $options{title}, $options{description});
321 $insertException->finish;
323 $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{title} = $options{title};
324 $self->{'exception_holidays'}->{"$options{year}/$options{month}/$options{day}"}{description} = $options{description};
330 delete_holiday(weekday => $weekday
335 Delete a holiday for $self->{branchcode}.
337 C<$weekday> Is the week day to delete.
339 C<$day> Is the day month to make the date to delete.
341 C<$month> Is month to make the date to delete.
343 C<$year> Is year to make the date to delete.
351 # Verify what kind of holiday that day is. For example, if it is
352 # a repeatable holiday, this should check if there are some exception
353 # for that holiday rule. Otherwise, if it is a regular holiday, it´s
354 # ok just deleting it.
356 my $dbh = C4::Context->dbh();
357 my $isSingleHoliday = $dbh->prepare("select id from special_holidays where (branchcode = '$self->{branchcode}') and (day = $options{day}) and (month = $options{month}) and (year = $options{year})");
358 $isSingleHoliday->execute;
359 if ($isSingleHoliday->rows) {
360 my $id = $isSingleHoliday->fetchrow;
361 $isSingleHoliday->finish; # Close the last query
363 my $deleteHoliday = $dbh->prepare("delete from special_holidays where (id = $id)");
364 $deleteHoliday->execute;
365 $deleteHoliday->finish; # Close the last query
366 delete($self->{'single_holidays'}->{"$options{year}/$options{month}/$options{day}"});
368 $isSingleHoliday->finish; # Close the last query
370 my $isWeekdayHoliday = $dbh->prepare("select id from repeatable_holidays where (branchcode = '$self->{branchcode}') and (weekday = $options{weekday})");
371 $isWeekdayHoliday->execute;
372 if ($isWeekdayHoliday->rows) {
373 my $id = $isWeekdayHoliday->fetchrow;
374 $isWeekdayHoliday->finish; # Close the last query
376 my $updateExceptions = $dbh->prepare("update special_holidays set isexception = 0 where (WEEKDAY(CONCAT(special_holidays.year,'-',special_holidays.month,'-',special_holidays.day)) = $options{weekday}) and (branchcode = '$self->{branchcode}')");
377 $updateExceptions->execute;
378 $updateExceptions->finish; # Close the last query
380 my $deleteHoliday = $dbh->prepare("delete from repeatable_holidays where (id = $id)");
381 $deleteHoliday->execute;
382 $deleteHoliday->finish;
383 delete($self->{'week_days_holidays'}->{$options{weekday}});
385 $isWeekdayHoliday->finish; # Close the last query
387 my $isDayMonthHoliday = $dbh->prepare("select id from repeatable_holidays where (branchcode = '$self->{branchcode}') and (day = '$options{day}') and (month = '$options{month}')");
388 $isDayMonthHoliday->execute;
389 if ($isDayMonthHoliday->rows) {
390 my $id = $isDayMonthHoliday->fetchrow;
391 $isDayMonthHoliday->finish;
392 my $updateExceptions = $dbh->prepare("update special_holidays set isexception = 0 where (special_holidays.branchcode = '$self->{branchcode}') and (special_holidays.day = '$options{day}') and (special_holidays.month = '$options{month}')");
393 $updateExceptions->execute;
394 $updateExceptions->finish; # Close the last query
396 my $deleteHoliday = $dbh->prepare("delete from repeatable_holidays where (id = '$id')");
397 $deleteHoliday->execute;
398 $deleteHoliday->finish; # Close the last query
399 $isDayMonthHoliday->finish; # Close the last query
400 delete($self->{'day_month_holidays'}->{"$options{month}/$options{day}"});
409 $isHoliday = isHoliday($day, $month $year);
412 C<$day> Is the day to check whether if is a holiday or not.
414 C<$month> Is the month to check whether if is a holiday or not.
416 C<$year> Is the year to check whether if is a holiday or not.
421 my ($self, $day, $month, $year) = @_;
422 # FIXME - date strings are stored in non-padded metric format. should change to iso.
423 # FIXME - should change arguments to accept C4::Dates object
427 my $weekday = &Date::Calc::Day_of_Week($year, $month, $day) % 7;
428 my $weekDays = $self->get_week_days_holidays();
429 my $dayMonths = $self->get_day_month_holidays();
430 my $exceptions = $self->get_exception_holidays();
431 my $singles = $self->get_single_holidays();
432 if (defined($exceptions->{"$year/$month/$day"})) {
435 if ((exists($weekDays->{$weekday})) ||
436 (exists($dayMonths->{"$month/$day"})) ||
437 (exists($singles->{"$year/$month/$day"}))) {
448 my ($day, $month, $year) = $calendar->addDate($date, $offset)
450 C<$date> is a C4::Dates object representing the starting date of the interval.
452 C<$offset> Is the number of days that this function has to count from $date.
457 my ($self, $startdate, $offset) = @_;
458 my ($year,$month,$day) = split("-",$startdate->output('iso'));
460 if ($offset < 0) { # In case $offset is negative
461 # $offset = $offset*(-1);
464 my $daysMode = C4::Context->preference('useDaysMode');
465 if ($daysMode eq 'Datedue') {
466 ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset );
467 while ($self->isHoliday($day, $month, $year)) {
468 ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep);
470 } elsif($daysMode eq 'Calendar') {
471 while ($offset != 0) {
472 ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $daystep);
473 if (!($self->isHoliday($day, $month, $year))) {
474 $offset = $offset - $daystep;
477 } else { ## ($daysMode eq 'Days')
478 ($year, $month, $day) = &Date::Calc::Add_Delta_Days($year, $month, $day, $offset );
480 return(C4::Dates->new( sprintf("%04d-%02d-%02d",$year,$month,$day),'iso'));
485 my $daysBetween = $calendar->daysBetween($startdate, $enddate )
487 C<$startdate> and C<$enddate> are C4::Dates objects that define the interval.
489 Returns the number of non-holiday days in the interval.
490 useDaysMode syspref has no effect here.
494 my ( $self, $startdate, $enddate ) = @_ ;
495 my ($yearFrom,$monthFrom,$dayFrom) = split("-",$startdate->output('iso'));
496 my ($yearTo,$monthTo,$dayTo) = split("-",$enddate->output('iso'));
497 if (Date_to_Days($yearFrom,$monthFrom,$dayFrom) > Date_to_Days($yearTo,$monthTo,$dayTo)) {
499 # we don't go backwards ( FIXME - handle this error better )
504 if (($yearFrom != $yearTo) || ($monthFrom != $monthTo) || ($dayFrom != $dayTo)) {
505 if (!($self->isHoliday($dayFrom, $monthFrom, $yearFrom))) {
508 ($yearFrom, $monthFrom, $dayFrom) = &Date::Calc::Add_Delta_Days($yearFrom, $monthFrom, $dayFrom, 1);
524 Koha Physics Library UNLP <matias_veleda@hotmail.com>