From c3880a70e6dcbfba9c817c25ac0b77477a0e8cc6 Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Fri, 17 Apr 2026 07:30:42 +0100 Subject: [PATCH] Bug 42310: (QA follow-up) Fire per-row delete hooks in Koha::Calendar delete_* methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The four delete_*_closure / delete_exception methods in Koha::Calendar were calling ResultSet->delete, which issues a single bulk SQL DELETE and never calls the row-level delete() override. The cache-invalidation hooks on Koha::Calendar::SingleClosure->delete and Koha::Calendar::Exception->delete were therefore skipped when callers went through $library->calendar->delete_single_closure(...) or delete_exception(...), and the _holidays cache kept reporting deleted dates as closed until its TTL expired. The underlying tables enforce UNIQUE constraints on (library_id, weekday), (library_id, day, month) and (library_id, date), so each search can match at most one row. Switch the four methods to ->search({...}, { rows => 1 })->single followed by ->delete on the row, which both makes the single-row expectation explicit and ensures the per-row delete override runs. A regression test is added to t/db_dependent/Koha/Calendar.t asserting that the _holidays cache is cleared after delete_single_closure and delete_exception. Test plan: 1) prove t/db_dependent/Koha/Calendar.t 2) Confirm the new 'delete_*_closure clears _holidays cache' subtest passes. Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim --- Koha/Calendar.pm | 26 ++++++++++++++++++++------ t/db_dependent/Koha/Calendar.t | 31 ++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/Koha/Calendar.pm b/Koha/Calendar.pm index 81b766592f..5fc8cc318c 100644 --- a/Koha/Calendar.pm +++ b/Koha/Calendar.pm @@ -445,27 +445,41 @@ sub add_exception { sub delete_weekly_closure { my ( $self, $params ) = @_; - Koha::Calendar::WeeklyClosures->search( { library_id => $self->{branchcode}, weekday => $params->{weekday} } ) - ->delete; + my $row = Koha::Calendar::WeeklyClosures->search( + { library_id => $self->{branchcode}, weekday => $params->{weekday} }, + { rows => 1 } + )->single; + $row->delete if $row; return $self; } sub delete_repeating_closure { my ( $self, $params ) = @_; - Koha::Calendar::RepeatingClosures->search( - { library_id => $self->{branchcode}, day => $params->{day}, month => $params->{month} } )->delete; + my $row = Koha::Calendar::RepeatingClosures->search( + { library_id => $self->{branchcode}, day => $params->{day}, month => $params->{month} }, + { rows => 1 } + )->single; + $row->delete if $row; return $self; } sub delete_single_closure { my ( $self, $params ) = @_; - Koha::Calendar::SingleClosures->search( { library_id => $self->{branchcode}, date => $params->{date} } )->delete; + my $row = Koha::Calendar::SingleClosures->search( + { library_id => $self->{branchcode}, date => $params->{date} }, + { rows => 1 } + )->single; + $row->delete if $row; return $self; } sub delete_exception { my ( $self, $params ) = @_; - Koha::Calendar::Exceptions->search( { library_id => $self->{branchcode}, date => $params->{date} } )->delete; + my $row = Koha::Calendar::Exceptions->search( + { library_id => $self->{branchcode}, date => $params->{date} }, + { rows => 1 } + )->single; + $row->delete if $row; return $self; } diff --git a/t/db_dependent/Koha/Calendar.t b/t/db_dependent/Koha/Calendar.t index dc91f06fec..7ab73c8efd 100755 --- a/t/db_dependent/Koha/Calendar.t +++ b/t/db_dependent/Koha/Calendar.t @@ -19,10 +19,11 @@ use Modern::Perl; -use Test::More tests => 4; +use Test::More tests => 5; use Test::Exception; use Test::NoWarnings; +use Koha::Caches; use Koha::Database; use Koha::DateUtils qw( dt_from_string ); use Koha::Calendar::WeeklyClosures; @@ -227,3 +228,31 @@ subtest 'CRUD methods' => sub { $schema->storage->txn_rollback; }; + +subtest 'delete_*_closure clears _holidays cache' => sub { + + plan tests => 4; + + $schema->storage->txn_begin; + + my $library = $builder->build_object( { class => 'Koha::Libraries' } ); + my $branchcode = $library->branchcode; + my $cache_key = $branchcode . '_holidays'; + my $cache = Koha::Caches->get_instance; + + my $calendar = Koha::Calendar->new( branchcode => $branchcode ); + + $calendar->add_single_closure( { date => '2027-07-04', title => 'Independence', description => '' } ); + $calendar->is_holiday( dt_from_string('2027-07-04') ); # warm cache + ok( defined $cache->get_from_cache($cache_key), 'Cache warm after is_holiday (single)' ); + $calendar->delete_single_closure( { date => '2027-07-04' } ); + is( $cache->get_from_cache($cache_key), undef, 'Cache cleared after delete_single_closure' ); + + $calendar->add_exception( { date => '2027-07-05', title => 'Special open', description => '' } ); + $calendar->is_holiday( dt_from_string('2027-07-05') ); # warm cache + ok( defined $cache->get_from_cache($cache_key), 'Cache warm after is_holiday (exception)' ); + $calendar->delete_exception( { date => '2027-07-05' } ); + is( $cache->get_from_cache($cache_key), undef, 'Cache cleared after delete_exception' ); + + $schema->storage->txn_rollback; +};