Bug 42310: (follow-up) Add CRUD methods to Koha::Calendar, delegate C4::Calendar
Add to Koha::Calendar: add_weekly_closure, add_repeating_closure, add_single_closure, add_exception, delete_weekly_closure, delete_repeating_closure, delete_single_closure, delete_exception, copy_to, _clear_cache C4::Calendar write methods now delegate to Koha::Calendar instead of using raw DBI. No old table references remain in C4::Calendar. Tests in t/db_dependent/Koha/Calendar.t cover all CRUD operations: create, verify via is_holiday, delete, copy_to (including idempotency). Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io> Signed-off-by: David Nind <david@davidnind.com> Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk> Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io> Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
This commit is contained in:
parent
4d23dff433
commit
cb7968387a
384
C4/Calendar.pm
384
C4/Calendar.pm
|
|
@ -21,6 +21,7 @@ use vars qw(@EXPORT);
|
|||
|
||||
use Carp qw( croak );
|
||||
use Date::Calc qw( Today );
|
||||
use Koha::Calendar;
|
||||
|
||||
use C4::Context;
|
||||
use Koha::Caches;
|
||||
|
|
@ -64,30 +65,32 @@ sub new {
|
|||
return $self;
|
||||
}
|
||||
|
||||
=head2 _init
|
||||
|
||||
Loads calendar data from the database for the given branch.
|
||||
|
||||
=cut
|
||||
|
||||
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;
|
||||
my $dbh = C4::Context->dbh();
|
||||
|
||||
while ( my $row = $repeatable->fetchrow_hashref ) {
|
||||
my $weekly_sth = $dbh->prepare('SELECT * FROM library_weekly_closures WHERE library_id = ?');
|
||||
$weekly_sth->execute($branch);
|
||||
my %week_days_holidays;
|
||||
while ( my $row = $weekly_sth->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 $repeating_sth = $dbh->prepare('SELECT * FROM library_repeating_closures WHERE library_id = ?');
|
||||
$repeating_sth->execute($branch);
|
||||
my %day_month_holidays;
|
||||
while ( my $row = $repeatable->fetchrow_hashref ) {
|
||||
while ( my $row = $repeating_sth->fetchrow_hashref ) {
|
||||
my $key = $row->{month} . "/" . $row->{day};
|
||||
$day_month_holidays{$key}{title} = $row->{title};
|
||||
$day_month_holidays{$key}{description} = $row->{description};
|
||||
|
|
@ -96,29 +99,26 @@ sub _init {
|
|||
}
|
||||
$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 $exceptions_sth =
|
||||
$dbh->prepare('SELECT date, title, description FROM library_closure_exceptions WHERE library_id = ?');
|
||||
$exceptions_sth->execute($branch);
|
||||
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 );
|
||||
while ( my $row = $exceptions_sth->fetchrow_hashref ) {
|
||||
my ( $year, $month, $day ) = split( /-/, $row->{date} );
|
||||
$exception_holidays{"$year/$month/$day"}{title} = $row->{title};
|
||||
$exception_holidays{"$year/$month/$day"}{description} = $row->{description};
|
||||
$exception_holidays{"$year/$month/$day"}{date} = $row->{date};
|
||||
}
|
||||
$self->{'exception_holidays'} = \%exception_holidays;
|
||||
|
||||
$special->execute( $branch, 0 );
|
||||
my $single_sth = $dbh->prepare('SELECT date, title, description FROM library_single_closures WHERE library_id = ?');
|
||||
$single_sth->execute($branch);
|
||||
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 );
|
||||
while ( my $row = $single_sth->fetchrow_hashref ) {
|
||||
my ( $year, $month, $day ) = split( /-/, $row->{date} );
|
||||
$single_holidays{"$year/$month/$day"}{title} = $row->{title};
|
||||
$single_holidays{"$year/$month/$day"}{description} = $row->{description};
|
||||
$single_holidays{"$year/$month/$day"}{date} = $row->{date};
|
||||
}
|
||||
$self->{'single_holidays'} = \%single_holidays;
|
||||
return $self;
|
||||
|
|
@ -202,17 +202,13 @@ C<$description> Is the description to store for the holiday formed by $year/$mon
|
|||
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 (branchcode,weekday,day,month,title,description) values ( ?,?,NULL,NULL,?,? )"
|
||||
Koha::Calendar->new( branchcode => $self->{branchcode} )->add_weekly_closure(
|
||||
{
|
||||
weekday => $options{weekday}, title => $options{title}, description => $options{description},
|
||||
}
|
||||
);
|
||||
$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};
|
||||
$self->{'week_days_holidays'}->{ $options{weekday} }{title} = $options{title};
|
||||
$self->{'week_days_holidays'}->{ $options{weekday} }{description} = $options{description};
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
|
@ -238,14 +234,11 @@ C<$description> Is the description to store for the holiday formed by $year/$mon
|
|||
sub insert_day_month_holiday {
|
||||
my $self = shift @_;
|
||||
my %options = @_;
|
||||
|
||||
my $dbh = C4::Context->dbh();
|
||||
my $insertHoliday = $dbh->prepare(
|
||||
"insert into repeatable_holidays (branchcode,weekday,day,month,title,description) values (?, NULL, ?, ?, ?,? )"
|
||||
);
|
||||
$insertHoliday->execute(
|
||||
$self->{branchcode}, $options{day}, $options{month}, $options{title},
|
||||
$options{description}
|
||||
Koha::Calendar->new( branchcode => $self->{branchcode} )->add_repeating_closure(
|
||||
{
|
||||
day => $options{day}, month => $options{month}, title => $options{title},
|
||||
description => $options{description},
|
||||
}
|
||||
);
|
||||
$self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{title} = $options{title};
|
||||
$self->{'day_month_holidays'}->{"$options{month}/$options{day}"}{description} = $options{description};
|
||||
|
|
@ -277,28 +270,16 @@ C<$description> Is the description to store for the holiday formed by $year/$mon
|
|||
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 (branchcode,day,month,year,isexception,title,description) values (?,?,?,?,?,?,?)"
|
||||
my $date = $options{date};
|
||||
unless ($date) {
|
||||
$date = sprintf( ISO_DATE_FORMAT, $options{year}, $options{month}, $options{day} );
|
||||
}
|
||||
Koha::Calendar->new( branchcode => $self->{branchcode} )->add_single_closure(
|
||||
{
|
||||
date => $date, title => $options{title}, description => $options{description},
|
||||
}
|
||||
);
|
||||
$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};
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
|
||||
return $self;
|
||||
|
||||
}
|
||||
|
||||
=head2 insert_exception_holiday
|
||||
|
|
@ -326,28 +307,15 @@ C<$description> Is the description to store for the holiday formed by $year/$mon
|
|||
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 (branchcode,day,month,year,isexception,title,description) values (?,?,?,?,?,?,?)"
|
||||
my $date = $options{date};
|
||||
unless ($date) {
|
||||
$date = sprintf( ISO_DATE_FORMAT, $options{year}, $options{month}, $options{day} );
|
||||
}
|
||||
Koha::Calendar->new( branchcode => $self->{branchcode} )->add_exception(
|
||||
{
|
||||
date => $date, title => $options{title}, description => $options{description},
|
||||
}
|
||||
);
|
||||
$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};
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
|
@ -368,13 +336,10 @@ C<$description> Is the description to update for the holiday.
|
|||
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};
|
||||
my $closure =
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $self->{branchcode}, weekday => $options{weekday} } )
|
||||
->next;
|
||||
$closure->title( $options{title} )->description( $options{description} )->store if $closure;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
|
@ -400,16 +365,9 @@ C<$description> The description to be update for the holiday.
|
|||
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};
|
||||
my $closure = Koha::Calendar::RepeatingClosures->search(
|
||||
{ library_id => $self->{branchcode}, day => $options{day}, month => $options{month} } )->next;
|
||||
$closure->title( $options{title} )->description( $options{description} )->store if $closure;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
|
@ -438,25 +396,12 @@ C<$description> Is the description to update for the holiday formed by $year/$mo
|
|||
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};
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
|
||||
my $date = $options{date} || sprintf( ISO_DATE_FORMAT, $options{year}, $options{month}, $options{day} );
|
||||
my $closure = Koha::Calendar::SingleClosures->search( { library_id => $self->{branchcode}, date => $date } )->next;
|
||||
if ($closure) {
|
||||
$closure->title( $options{title} )->description( $options{description} )->store;
|
||||
Koha::Caches->get_instance()->clear_from_cache( $self->{branchcode} . '_holidays' );
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
|
@ -483,27 +428,14 @@ C<$description> Is the description to be modified for the holiday formed by $yea
|
|||
=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};
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
|
||||
my $self = shift @_;
|
||||
my %options = @_;
|
||||
my $date = $options{date} || sprintf( ISO_DATE_FORMAT, $options{year}, $options{month}, $options{day} );
|
||||
my $exception = Koha::Calendar::Exceptions->search( { library_id => $self->{branchcode}, date => $date } )->next;
|
||||
if ($exception) {
|
||||
$exception->title( $options{title} )->description( $options{description} )->store;
|
||||
Koha::Caches->get_instance()->clear_from_cache( $self->{branchcode} . '_holidays' );
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
|
@ -529,68 +461,37 @@ C<$year> Is year to make the date to delete.
|
|||
sub delete_holiday {
|
||||
my $self = shift @_;
|
||||
my %options = @_;
|
||||
my $cal = Koha::Calendar->new( branchcode => $self->{branchcode} );
|
||||
|
||||
# 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.
|
||||
if ( $options{day} && $options{month} && $options{year} ) {
|
||||
my $date = sprintf( ISO_DATE_FORMAT, $options{year}, $options{month}, $options{day} );
|
||||
|
||||
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}"} );
|
||||
}
|
||||
# Try single closure first
|
||||
if ( Koha::Calendar::SingleClosures->search( { library_id => $self->{branchcode}, date => $date } )->count ) {
|
||||
$cal->delete_single_closure( { date => $date } );
|
||||
}
|
||||
|
||||
# Also remove any exception for this date
|
||||
Koha::Calendar::Exceptions->search( { library_id => $self->{branchcode}, date => $date } )->delete;
|
||||
}
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
if ( defined $options{weekday}
|
||||
&& Koha::Calendar::WeeklyClosures->search( { library_id => $self->{branchcode}, weekday => $options{weekday} } )
|
||||
->count )
|
||||
{
|
||||
$cal->delete_weekly_closure( { weekday => $options{weekday} } );
|
||||
} elsif (
|
||||
$options{day}
|
||||
&& $options{month}
|
||||
&& Koha::Calendar::RepeatingClosures->search(
|
||||
{ library_id => $self->{branchcode}, day => $options{day}, month => $options{month} }
|
||||
)->count
|
||||
)
|
||||
{
|
||||
$cal->delete_repeating_closure( { day => $options{day}, month => $options{month} } );
|
||||
}
|
||||
|
||||
$cal->_clear_cache;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
|
@ -613,17 +514,8 @@ C<$year> Is year to make the date to delete.
|
|||
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} );
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
|
||||
my $date = $options{date} || sprintf( ISO_DATE_FORMAT, $options{year}, $options{month}, $options{day} );
|
||||
Koha::Calendar->new( branchcode => $self->{branchcode} )->delete_single_closure( { date => $date } );
|
||||
}
|
||||
|
||||
=head2 delete_holiday_range_repeatable
|
||||
|
|
@ -642,15 +534,8 @@ C<$month> Is month to make the date to delete.
|
|||
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} );
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
Koha::Calendar->new( branchcode => $self->{branchcode} )
|
||||
->delete_repeating_closure( { day => $options{day}, month => $options{month} } );
|
||||
}
|
||||
|
||||
=head2 delete_exception_holiday_range
|
||||
|
|
@ -673,17 +558,8 @@ C<$year> Is year to make the date to delete.
|
|||
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} );
|
||||
|
||||
# changed the 'single_holidays' table, lets force/reset its cache
|
||||
my $cache = Koha::Caches->get_instance();
|
||||
my $key = $self->{branchcode} . "_holidays";
|
||||
$cache->clear_from_cache($key);
|
||||
my $date = $options{date} || sprintf( ISO_DATE_FORMAT, $options{year}, $options{month}, $options{day} );
|
||||
Koha::Calendar->new( branchcode => $self->{branchcode} )->delete_exception( { date => $date } );
|
||||
}
|
||||
|
||||
=head2 isHoliday
|
||||
|
|
@ -734,47 +610,7 @@ sub isHoliday {
|
|||
|
||||
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;
|
||||
my $target_wdh = $target_calendar->get_week_days_holidays;
|
||||
foreach my $key ( keys %$wdh ) {
|
||||
unless ( grep { $_ eq $key } keys %$target_wdh ) {
|
||||
$target_calendar->insert_week_day_holiday( weekday => $key, %{ $wdh->{$key} } );
|
||||
}
|
||||
}
|
||||
|
||||
my $dmh = $self->get_day_month_holidays;
|
||||
my $target_dmh = $target_calendar->get_day_month_holidays;
|
||||
foreach my $values ( values %$dmh ) {
|
||||
unless ( grep { $_->{day} eq $values->{day} && $_->{month} eq $values->{month} } values %$target_dmh ) {
|
||||
$target_calendar->insert_day_month_holiday( %{$values} );
|
||||
}
|
||||
}
|
||||
|
||||
my $exception_holidays = $self->get_exception_holidays;
|
||||
my $target_exceptions = $target_calendar->get_exception_holidays;
|
||||
foreach my $values ( grep { $_->{date} gt $today } values %{$exception_holidays} ) {
|
||||
unless ( grep { $_->{date} eq $values->{date} } values %$target_exceptions ) {
|
||||
$target_calendar->insert_exception_holiday( %{$values} );
|
||||
}
|
||||
}
|
||||
|
||||
my $single_holidays = $self->get_single_holidays;
|
||||
my $target_singles = $target_calendar->get_single_holidays;
|
||||
foreach my $values ( grep { $_->{date} gt $today } values %{$single_holidays} ) {
|
||||
unless ( grep { $_->{date} eq $values->{date} } values %$target_singles ) {
|
||||
$target_calendar->insert_single_holiday( %{$values} );
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return Koha::Calendar->new( branchcode => $self->{branchcode} )->copy_to($target_branch);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
|||
166
Koha/Calendar.pm
166
Koha/Calendar.pm
|
|
@ -7,6 +7,7 @@ use DateTime;
|
|||
use DateTime::Duration;
|
||||
use C4::Context;
|
||||
use Koha::Caches;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
use Koha::Exceptions;
|
||||
use Koha::Exceptions::Calendar;
|
||||
use Koha::Calendar::WeeklyClosures;
|
||||
|
|
@ -422,6 +423,124 @@ sub clear_weekly_closed_days {
|
|||
return;
|
||||
}
|
||||
|
||||
sub add_weekly_closure {
|
||||
my ( $self, $params ) = @_;
|
||||
return Koha::Calendar::WeeklyClosure->new( { library_id => $self->{branchcode}, %$params } )->store;
|
||||
}
|
||||
|
||||
sub add_repeating_closure {
|
||||
my ( $self, $params ) = @_;
|
||||
return Koha::Calendar::RepeatingClosure->new( { library_id => $self->{branchcode}, %$params } )->store;
|
||||
}
|
||||
|
||||
sub add_single_closure {
|
||||
my ( $self, $params ) = @_;
|
||||
my $result = Koha::Calendar::SingleClosure->new( { library_id => $self->{branchcode}, %$params } )->store;
|
||||
$self->_clear_cache;
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub add_exception {
|
||||
my ( $self, $params ) = @_;
|
||||
my $result = Koha::Calendar::Exception->new( { library_id => $self->{branchcode}, %$params } )->store;
|
||||
$self->_clear_cache;
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub delete_weekly_closure {
|
||||
my ( $self, $params ) = @_;
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $self->{branchcode}, weekday => $params->{weekday} } )
|
||||
->delete;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub delete_repeating_closure {
|
||||
my ( $self, $params ) = @_;
|
||||
Koha::Calendar::RepeatingClosures->search(
|
||||
{ library_id => $self->{branchcode}, day => $params->{day}, month => $params->{month} } )->delete;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub delete_single_closure {
|
||||
my ( $self, $params ) = @_;
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $self->{branchcode}, date => $params->{date} } )->delete;
|
||||
$self->_clear_cache;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub delete_exception {
|
||||
my ( $self, $params ) = @_;
|
||||
Koha::Calendar::Exceptions->search( { library_id => $self->{branchcode}, date => $params->{date} } )->delete;
|
||||
$self->_clear_cache;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub copy_to {
|
||||
my ( $self, $target_branchcode ) = @_;
|
||||
croak "No target_branchcode" unless $target_branchcode;
|
||||
|
||||
my $today = dt_from_string()->ymd;
|
||||
|
||||
my $weekly = Koha::Calendar::WeeklyClosures->search( { library_id => $self->{branchcode} } );
|
||||
while ( my $row = $weekly->next ) {
|
||||
next
|
||||
if Koha::Calendar::WeeklyClosures->search( { library_id => $target_branchcode, weekday => $row->weekday } )
|
||||
->count;
|
||||
Koha::Calendar::WeeklyClosure->new(
|
||||
{
|
||||
library_id => $target_branchcode, weekday => $row->weekday,
|
||||
title => $row->title, description => $row->description,
|
||||
}
|
||||
)->store;
|
||||
}
|
||||
|
||||
my $repeating = Koha::Calendar::RepeatingClosures->search( { library_id => $self->{branchcode} } );
|
||||
while ( my $row = $repeating->next ) {
|
||||
next
|
||||
if Koha::Calendar::RepeatingClosures->search(
|
||||
{ library_id => $target_branchcode, day => $row->day, month => $row->month } )->count;
|
||||
Koha::Calendar::RepeatingClosure->new(
|
||||
{
|
||||
library_id => $target_branchcode, day => $row->day, month => $row->month,
|
||||
title => $row->title, description => $row->description,
|
||||
}
|
||||
)->store;
|
||||
}
|
||||
|
||||
my $singles =
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $self->{branchcode}, date => { '>=' => $today } } );
|
||||
while ( my $row = $singles->next ) {
|
||||
next
|
||||
if Koha::Calendar::SingleClosures->search( { library_id => $target_branchcode, date => $row->date } )
|
||||
->count;
|
||||
Koha::Calendar::SingleClosure->new(
|
||||
{
|
||||
library_id => $target_branchcode, date => $row->date,
|
||||
title => $row->title, description => $row->description,
|
||||
}
|
||||
)->store;
|
||||
}
|
||||
|
||||
my $exceptions =
|
||||
Koha::Calendar::Exceptions->search( { library_id => $self->{branchcode}, date => { '>=' => $today } } );
|
||||
while ( my $row = $exceptions->next ) {
|
||||
next if Koha::Calendar::Exceptions->search( { library_id => $target_branchcode, date => $row->date } )->count;
|
||||
Koha::Calendar::Exception->new(
|
||||
{
|
||||
library_id => $target_branchcode, date => $row->date,
|
||||
title => $row->title, description => $row->description,
|
||||
}
|
||||
)->store;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _clear_cache {
|
||||
my ($self) = @_;
|
||||
Koha::Caches->get_instance()->clear_from_cache( $self->{branchcode} . '_holidays' );
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
|
|
@ -598,9 +717,54 @@ 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
|
||||
closed days. This is for testing so that we can alter the Calendar object's
|
||||
list of specified dates
|
||||
|
||||
=head2 CRUD methods
|
||||
|
||||
=head3 add_weekly_closure
|
||||
|
||||
$calendar->add_weekly_closure({ weekday => 0, title => 'Sundays', description => '' });
|
||||
|
||||
=head3 add_repeating_closure
|
||||
|
||||
$calendar->add_repeating_closure({ day => 25, month => 12, title => 'Christmas', description => '' });
|
||||
|
||||
=head3 add_single_closure
|
||||
|
||||
$calendar->add_single_closure({ date => '2026-06-15', title => 'Staff day', description => '' });
|
||||
|
||||
=head3 add_exception
|
||||
|
||||
$calendar->add_exception({ date => '2026-12-25', title => 'Special opening', description => '' });
|
||||
|
||||
=head3 delete_weekly_closure
|
||||
|
||||
$calendar->delete_weekly_closure({ weekday => 0 });
|
||||
|
||||
=head3 delete_repeating_closure
|
||||
|
||||
$calendar->delete_repeating_closure({ day => 25, month => 12 });
|
||||
|
||||
=head3 delete_single_closure
|
||||
|
||||
$calendar->delete_single_closure({ date => '2026-06-15' });
|
||||
|
||||
=head3 delete_exception
|
||||
|
||||
$calendar->delete_exception({ date => '2026-12-25' });
|
||||
|
||||
=head3 copy_to
|
||||
|
||||
$calendar->copy_to($target_branchcode);
|
||||
|
||||
Copies all closure rules to another branch. Only copies future single
|
||||
closures and exceptions.
|
||||
|
||||
=head3 _clear_cache
|
||||
|
||||
Clears the holidays cache for this branch.
|
||||
|
||||
=head2 Internal methods
|
||||
|
||||
=head3 _init
|
||||
|
|
|
|||
|
|
@ -19,12 +19,16 @@
|
|||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::More tests => 3;
|
||||
use Test::More tests => 4;
|
||||
use Test::Exception;
|
||||
use Test::NoWarnings;
|
||||
|
||||
use Koha::Database;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
use Koha::Calendar::WeeklyClosures;
|
||||
use Koha::Calendar::RepeatingClosures;
|
||||
use Koha::Calendar::SingleClosures;
|
||||
use Koha::Calendar::Exceptions;
|
||||
use t::lib::TestBuilder;
|
||||
|
||||
BEGIN {
|
||||
|
|
@ -117,3 +121,109 @@ subtest 'has_business_days_between' => sub {
|
|||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
subtest 'CRUD methods' => sub {
|
||||
|
||||
plan tests => 20;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $library = $builder->build_object( { class => 'Koha::Libraries' } );
|
||||
my $calendar = Koha::Calendar->new( branchcode => $library->branchcode );
|
||||
|
||||
# add_weekly_closure
|
||||
my $weekly = $calendar->add_weekly_closure( { weekday => 0, title => 'Sundays', description => 'Closed' } );
|
||||
isa_ok( $weekly, 'Koha::Calendar::WeeklyClosure', 'add_weekly_closure returns object' );
|
||||
is(
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $library->branchcode } )->count, 1,
|
||||
'Weekly closure created'
|
||||
);
|
||||
|
||||
# add_repeating_closure
|
||||
my $repeating =
|
||||
$calendar->add_repeating_closure( { day => 25, month => 12, title => 'Christmas', description => '' } );
|
||||
isa_ok( $repeating, 'Koha::Calendar::RepeatingClosure', 'add_repeating_closure returns object' );
|
||||
is(
|
||||
Koha::Calendar::RepeatingClosures->search( { library_id => $library->branchcode } )->count, 1,
|
||||
'Repeating closure created'
|
||||
);
|
||||
|
||||
# add_single_closure
|
||||
my $single = $calendar->add_single_closure( { date => '2026-06-15', title => 'Staff day', description => '' } );
|
||||
isa_ok( $single, 'Koha::Calendar::SingleClosure', 'add_single_closure returns object' );
|
||||
is(
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $library->branchcode } )->count, 1,
|
||||
'Single closure created'
|
||||
);
|
||||
|
||||
# add_exception
|
||||
my $exception = $calendar->add_exception( { date => '2026-12-25', title => 'Special opening', description => '' } );
|
||||
isa_ok( $exception, 'Koha::Calendar::Exception', 'add_exception returns object' );
|
||||
is( Koha::Calendar::Exceptions->search( { library_id => $library->branchcode } )->count, 1, 'Exception created' );
|
||||
|
||||
# Verify is_holiday uses the new data
|
||||
my $cal = Koha::Calendar->new( branchcode => $library->branchcode );
|
||||
my $sunday = dt_from_string('2026-06-14'); # a Sunday
|
||||
is( $cal->is_holiday($sunday), 1, 'Sunday is closed after add_weekly_closure' );
|
||||
|
||||
my $june15 = dt_from_string('2026-06-15');
|
||||
is( $cal->is_holiday($june15), 1, 'Single closure date is closed' );
|
||||
|
||||
my $xmas = dt_from_string('2026-12-25');
|
||||
is( $cal->is_holiday($xmas), 0, 'Exception overrides repeating closure' );
|
||||
|
||||
# delete methods
|
||||
$calendar->delete_weekly_closure( { weekday => 0 } );
|
||||
is(
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $library->branchcode } )->count, 0,
|
||||
'Weekly closure deleted'
|
||||
);
|
||||
|
||||
$calendar->delete_repeating_closure( { day => 25, month => 12 } );
|
||||
is(
|
||||
Koha::Calendar::RepeatingClosures->search( { library_id => $library->branchcode } )->count, 0,
|
||||
'Repeating closure deleted'
|
||||
);
|
||||
|
||||
$calendar->delete_single_closure( { date => '2026-06-15' } );
|
||||
is(
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $library->branchcode } )->count, 0,
|
||||
'Single closure deleted'
|
||||
);
|
||||
|
||||
$calendar->delete_exception( { date => '2026-12-25' } );
|
||||
is( Koha::Calendar::Exceptions->search( { library_id => $library->branchcode } )->count, 0, 'Exception deleted' );
|
||||
|
||||
# copy_to
|
||||
$calendar->add_weekly_closure( { weekday => 6, title => 'Saturdays', description => '' } );
|
||||
$calendar->add_single_closure( { date => '2027-01-01', title => 'New Year', description => '' } );
|
||||
|
||||
my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
|
||||
$calendar->copy_to( $library2->branchcode );
|
||||
|
||||
is(
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $library2->branchcode } )->count, 1,
|
||||
'Weekly closure copied'
|
||||
);
|
||||
is(
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $library2->branchcode } )->count, 1,
|
||||
'Single closure copied'
|
||||
);
|
||||
|
||||
# copy_to should not duplicate
|
||||
$calendar->copy_to( $library2->branchcode );
|
||||
is(
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $library2->branchcode } )->count, 1,
|
||||
'No duplicate after second copy'
|
||||
);
|
||||
is(
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $library2->branchcode } )->count, 1,
|
||||
'No duplicate single after second copy'
|
||||
);
|
||||
|
||||
# Verify is_holiday after deletions and re-init
|
||||
my $cal2 = Koha::Calendar->new( branchcode => $library->branchcode );
|
||||
is( $cal2->is_holiday($june15), 0, 'Deleted single closure no longer a holiday' );
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ use t::lib::Mocks;
|
|||
use List::Util qw(min);
|
||||
|
||||
use Koha::Caches;
|
||||
use Koha::Calendar::WeeklyClosures;
|
||||
use Koha::Calendar::RepeatingClosures;
|
||||
use Koha::Calendar::SingleClosures;
|
||||
use Koha::Calendar::Exceptions;
|
||||
use Koha::Libraries;
|
||||
use Koha::Database;
|
||||
|
||||
|
|
@ -461,41 +465,40 @@ subtest 'list_closed_dates() tests' => sub {
|
|||
my $cache = Koha::Caches->get_instance();
|
||||
|
||||
# Clear all closure data so we fully control what exists
|
||||
$schema->resultset('SpecialHoliday')->search( { branchcode => $branchcode } )->delete;
|
||||
$schema->resultset('RepeatableHoliday')->search( { branchcode => $branchcode } )->delete;
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $branchcode } )->delete;
|
||||
Koha::Calendar::RepeatingClosures->search( { library_id => $branchcode } )->delete;
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $branchcode } )->delete;
|
||||
Koha::Calendar::Exceptions->search( { library_id => $branchcode } )->delete;
|
||||
$cache->clear_from_cache( $branchcode . '_holidays' );
|
||||
|
||||
# Weekly closure: Saturday (6)
|
||||
# 2026-06-13 and 2026-06-20 are Saturdays
|
||||
$builder->build(
|
||||
$builder->build_object(
|
||||
{
|
||||
source => 'RepeatableHoliday',
|
||||
value => {
|
||||
branchcode => $branchcode, weekday => 6, day => undef, month => undef,
|
||||
title => 'Saturdays', description => '',
|
||||
},
|
||||
class => 'Koha::Calendar::WeeklyClosures',
|
||||
value => {
|
||||
library_id => $branchcode, weekday => 6, title => 'Saturdays', description => '',
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Single closure: 2026-06-15 (a Monday)
|
||||
$builder->build(
|
||||
$builder->build_object(
|
||||
{
|
||||
source => 'SpecialHoliday',
|
||||
value => {
|
||||
branchcode => $branchcode, day => 15, month => 6, year => 2026,
|
||||
title => 'Test', description => '', isexception => 0,
|
||||
},
|
||||
class => 'Koha::Calendar::SingleClosures',
|
||||
value => {
|
||||
library_id => $branchcode, date => '2026-06-15', title => 'Test', description => '',
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
# Exception: 2026-06-20 (a Saturday — normally closed, but open this day)
|
||||
$builder->build(
|
||||
$builder->build_object(
|
||||
{
|
||||
source => 'SpecialHoliday',
|
||||
value => {
|
||||
branchcode => $branchcode, day => 20, month => 6, year => 2026,
|
||||
title => 'Exception', description => '', isexception => 1,
|
||||
},
|
||||
class => 'Koha::Calendar::Exceptions',
|
||||
value => {
|
||||
library_id => $branchcode, date => '2026-06-20', title => 'Exception', description => '',
|
||||
}
|
||||
}
|
||||
);
|
||||
$cache->clear_from_cache( $branchcode . '_holidays' );
|
||||
|
|
@ -536,8 +539,10 @@ subtest 'list_closed_dates() tests' => sub {
|
|||
# Defaults work (no from/to) — fresh library with no closures at all
|
||||
my $lib2 = $builder->build_object( { class => 'Koha::Libraries' } );
|
||||
my $branchcode2 = $lib2->branchcode;
|
||||
$schema->resultset('RepeatableHoliday')->search( { branchcode => $branchcode2 } )->delete;
|
||||
$schema->resultset('SpecialHoliday')->search( { branchcode => $branchcode2 } )->delete;
|
||||
Koha::Calendar::WeeklyClosures->search( { library_id => $branchcode2 } )->delete;
|
||||
Koha::Calendar::RepeatingClosures->search( { library_id => $branchcode2 } )->delete;
|
||||
Koha::Calendar::SingleClosures->search( { library_id => $branchcode2 } )->delete;
|
||||
Koha::Calendar::Exceptions->search( { library_id => $branchcode2 } )->delete;
|
||||
$cache->clear_from_cache( $branchcode2 . '_holidays' );
|
||||
$t->get_ok("//$userid:$password\@/api/v1/libraries/$branchcode2/closed_dates")
|
||||
->status_is(200)
|
||||
|
|
|
|||
Loading…
Reference in New Issue