diff --git a/Koha/Library/Calendar/Exception.pm b/Koha/Library/Calendar/Exception.pm index 598c23d020..fb118db204 100644 --- a/Koha/Library/Calendar/Exception.pm +++ b/Koha/Library/Calendar/Exception.pm @@ -21,6 +21,7 @@ use Modern::Perl; use Koha::Caches; use Koha::Database; +use Koha::Exceptions; use base qw(Koha::Object); @@ -38,12 +39,20 @@ Overloaded store method that clears the holidays cache on insert. Only flushes on insert (new exception), not on title/description updates, because the holidays cache only stores dates and their open/closed status. +An update that changes C in place would desync the cache with no +warning, so that is rejected outright - callers must delete and re-add +instead. =cut sub store { my ($self) = @_; + Koha::Exceptions::BadParameter->throw( + error => 'Cannot change date on an existing closure exception; delete and re-add instead', + parameter => 'date' + ) if $self->in_storage && $self->_result->is_column_changed('date'); + my $flush = !$self->in_storage; $self = $self->SUPER::store; diff --git a/Koha/Library/Calendar/SingleClosure.pm b/Koha/Library/Calendar/SingleClosure.pm index 079d712d28..fbe807effd 100644 --- a/Koha/Library/Calendar/SingleClosure.pm +++ b/Koha/Library/Calendar/SingleClosure.pm @@ -21,6 +21,7 @@ use Modern::Perl; use Koha::Caches; use Koha::Database; +use Koha::Exceptions; use base qw(Koha::Object); @@ -38,12 +39,20 @@ Overloaded store method that clears the holidays cache on insert. Only flushes on insert (new closure), not on title/description updates, because the holidays cache only stores dates and their open/closed status. +An update that changes C in place would desync the cache with no +warning, so that is rejected outright - callers must delete and re-add +instead. =cut sub store { my ($self) = @_; + Koha::Exceptions::BadParameter->throw( + error => 'Cannot change date on an existing single closure; delete and re-add instead', + parameter => 'date' + ) if $self->in_storage && $self->_result->is_column_changed('date'); + my $flush = !$self->in_storage; $self = $self->SUPER::store; diff --git a/t/db_dependent/Koha/Library/Calendar.t b/t/db_dependent/Koha/Library/Calendar.t index 2708892d9e..e7b7cfccff 100755 --- a/t/db_dependent/Koha/Library/Calendar.t +++ b/t/db_dependent/Koha/Library/Calendar.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 7; +use Test::More tests => 8; use Test::Exception; use Test::NoWarnings; @@ -339,3 +339,35 @@ subtest 'add_weekly_closure validates weekday' => sub { $schema->storage->txn_rollback; }; + +subtest 'SingleClosure/Exception store() rejects an in-place date change' => sub { + + plan tests => 4; + + $schema->storage->txn_begin; + + my $library = $builder->build_object( { class => 'Koha::Libraries' } ); + my $calendar = Koha::Library::Calendar->new( branchcode => $library->branchcode ); + + my $single = $calendar->add_single_closure( { date => '2027-08-01', title => 'Staff day', description => '' } ); + throws_ok { + $single->date('2027-08-02')->store; + } + 'Koha::Exceptions::BadParameter', 'SingleClosure->store dies when date is changed in place'; + + $single->discard_changes; + $single->title('Staff day (renamed)')->store; + is( $single->title, 'Staff day (renamed)', 'SingleClosure->store still allows a title-only update' ); + + my $exception = $calendar->add_exception( { date => '2027-08-03', title => 'Special open', description => '' } ); + throws_ok { + $exception->date('2027-08-04')->store; + } + 'Koha::Exceptions::BadParameter', 'Exception->store dies when date is changed in place'; + + $exception->discard_changes; + $exception->title('Special open (renamed)')->store; + is( $exception->title, 'Special open (renamed)', 'Exception->store still allows a title-only update' ); + + $schema->storage->txn_rollback; +};