commit 7bdf3269367f04bf407b6c6fc830396c01511560 Author: Owen Leonard Date: Thu Apr 16 10:25:00 2026 -0400 Bug 42399: Update some tools pages to use grid layout for forms - Part 2 This patch updates several more tools templates with new markup for laying out forms using CSS grids. To test, apply the patch rebuild the staff interface CSS. Check the following pages, confirming that the "New" and "Edit" versions of the form look correct in each case: - Tools -> Notices and slips -> Create or edit notice - Tools -> Batch patron modification - Check the forms under each tab - Submit a patch of patrons for modification and check the "Edit patrons" form. Pay special attention to the way the patron attribute fields work, including adding and deleting additional patron attribute fields. - Tools -> Upload patron images - Tools -> Quote editor - New quote - Import quotes - Tools -> Task scheduler - Tools -> Uploads - Tools -> Log viewer - Cataloging -> Stage MARC records for import - Cataloging -> Manage staged MARC records - Cataloging -> Stock rotation - New rota - Manage stages -> Add stage - Manage stages -> Edit stage Sponsored-by: Athens County Public Libraries commit 0fc43dd5a3fb70b3cd2b7e572acc747e26fe1f8d Author: Baptiste Wojtkowski Date: Wed Sep 16 13:48:03 2026 +0000 Bug 41742: (follow-up) Add pod to AddBudgetPeriod Create a pod coverage for AddBudgetPeriod Signed-off-by: Pedro Amorim commit 0ae6c196ecc59404f8d6ecd10d4bf437689f28a4 Author: Olivia Reynolds Date: Wed Sep 16 09:51:28 2026 +0000 Bug 39337: (follow-up) Mock OpacSuppression in Output tests Before the refactoring in this bug, redirect_if_opac_suppressed was intended to be called after checking OpacSuppression was enabled. Now it performs this check internally, so to adapt these unit tests correspondingly, we mock OpacSuppression to be enabled, as was the implied state before. Test plan: 1. Prove t/db_dependent/Output.t and verify all tests pass. Sponsored-by: Open Fifth Signed-off-by: Pedro Amorim commit bb05ef7ce8bface1d77704d415d83b336164ca5a Author: Pedro Amorim Date: Tue Sep 15 16:06:59 2026 +0000 Bug 42310: DBRev 26.06.00.026 Signed-off-by: Pedro Amorim commit 1b903bc3c58ee05f1a524726e513971423cd2c9b Author: Pedro Amorim Date: Tue Sep 15 15:52:35 2026 +0000 Bug 42310: (RM follow-up) Refresh stale DBIC checksum on Koha::Schema::Result::Branch Signed-off-by: Pedro Amorim commit 76d156d4fcc8672cf6e751de6d2a83be1bcf7453 Author: Tomás Cohen Arazi Date: Tue Sep 15 11:27:36 2026 -0300 Bug 42310: (QA follow-up) Clean up stale references to dropped calendar tables - cleanup_database.pl: rewrite DeleteSpecialHolidays to purge the new library_single_closures and library_closure_exceptions tables via their Koha::Objects classes (was querying the dropped special_holidays table). - kohastructure.sql: fix the comment header above library_repeating_closures that still referred to repeatable_holidays. - C4::Overdues: drop the dead GetSpecialHolidays / GetRepeatableHolidays / GetWdayFromItemnumber routines (unreferenced, exported nowhere) that still queried the dropped special_holidays / repeatable_holidays tables, along with the now-unused Date::Calc and Date::Manip imports. Signed-off-by: Pedro Amorim commit 51fd136eb11befc204f830fcb40ad2e04a7a7eb3 Author: Tomás Cohen Arazi Date: Mon Sep 14 10:58:14 2026 -0300 Bug 42310: (follow-up) Retire t/db_dependent/Holidays.t t/db_dependent/Holidays.t was a legacy file whose coverage is now provided by the two dedicated calendar test files. Its calendar behaviour assertions (is_holiday for weekly/day-month/single holidays) are already exercised by t/db_dependent/Calendar.t and t/db_dependent/Koha/Library/Calendar.t. The remaining unique cases queried the special_holidays / repeatable_holidays tables directly, which this bug drops during the migration to the Koha::Library::Calendar::*Closure schema, so the file could no longer run. This commit folds the unique coverage into t/db_dependent/Koha/Library/Calendar.t, rewritten against the new closure objects/API (no raw legacy-table SQL): - is_holiday DST edge case (America/Santiago days_between) - next_open_days / prev_open_days throwing NoOpenDays when the library is never open, and finding an open day created via an exception - copy_to completeness: repeating-closure copy, exception copy, and exclusion of past-dated single closures and exceptions, plus the no-duplication guarantee for all four closure types and then deletes t/db_dependent/Holidays.t. Test plan: - prove t/db_dependent/Koha/Library/Calendar.t - prove t/db_dependent/Calendar.t Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 755521ba0f6f362b5390127c9876346c9f486fd9 Author: Tomás Cohen Arazi Date: Mon Sep 14 11:23:35 2026 -0300 Bug 42310: (follow-up) Make 16.12.00.032 upgrade self-contained The historical 16.12.00.032 upgrade step (Bug 12063) instantiated Koha::Calendar to push reserves.expirationdate forward by the max pickup delay in open days. Depending on a live application class from a frozen upgrade step is fragile: when this bug renamed and removed Koha::Calendar, the migration had to be edited to chase the new namespace. Frozen updatedatabase.pl steps should be self-contained and prefer direct DB access. Reimplement the holiday-aware date advance inline, reading the legacy repeatable_holidays / special_holidays tables (which still exist at this point in the upgrade path) directly, with no dependency on any Koha::* calendar class. This keeps the step working regardless of later refactors and removes the calendar-class reference from updatedatabase.pl entirely. The weekly / day-month / single-closure logic and exception (open override) handling mirror the historical C4::Calendar semantics. Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit f4268951f08955d78bf5dee063df273def1f6239 Author: Tomás Cohen Arazi Date: Mon Sep 14 11:12:10 2026 -0300 Bug 42310: (follow-up) Fix POD coverage for Koha::Checkouts::_type The koha-qa pod_coverage check flags 'sub _type has no pod coverage' in Koha/Checkouts.pm. The POD block above the sub was headed '=head3 type' while the sub is named '_type', so the documentation was not associated with the sub. Correct the heading to '=head3 _type' to match, mirroring the adjacent object_class POD. Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 134ce6aa7c2d92ef4c1ab8fa3f3e3cf3ae060997 Author: Martin Renvoize Date: Wed Aug 5 09:07:04 2026 +0100 Bug 42310: (QA follow-up) Add test coverage for add_* cache invalidation, empty calendars, and leap-year repeating closures Coverage gaps identified during QA review: - add_single_closure/add_exception were only ever tested against a cold cache; nothing proved they invalidate a cache already warmed with the stale answer before the add. - No test exercised a library with no closures at all. - No test exercised a repeating (day/month) closure on 29 February across a leap and a non-leap year. Atomicupdate migration coverage is intentionally left out of scope. Test plan: 1) prove t/db_dependent/Koha/Library/Calendar.t t/db_dependent/Calendar.t t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 3ef756f5a0e9adb6ce9d71592bd82a88846c5e83 Author: Martin Renvoize Date: Wed Aug 5 09:05:17 2026 +0100 Bug 42310: (QA follow-up) Refresh in-process closure state on add/delete_weekly_closure and add/delete_repeating_closure add_weekly_closure/delete_weekly_closure and add_repeating_closure/ delete_repeating_closure returned $self without refreshing $self->{weekly_closed_days}/{day_month_closed_days}, so a calendar object would keep reporting the pre-change state to is_holiday (and everything built on it - days_forward, next_open_days, etc.) until it was re-instantiated. This is distinct from the _holidays Koha::Caches entry, which single/exception closures already flush correctly on store/delete. Call _init to rebuild both structures from the database after each add/delete, so the same object reflects the change immediately. Test plan: 1) prove t/db_dependent/Koha/Library/Calendar.t t/db_dependent/Calendar.t t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t t/db_dependent/Holds/WaitingReserves.t t/db_dependent/Koha/CurbsidePickups.t t/db_dependent/Reserves/CancelExpiredReserves.t t/db_dependent/api/v1/libraries.t Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 004fe4de21e83ebb0695233a4e3d4a9604ee7a01 Author: Martin Renvoize Date: Wed Aug 5 09:02:27 2026 +0100 Bug 42310: (QA follow-up) Reject in-place date changes on SingleClosure/Exception store() only flushes the _holidays cache on insert, on the assumption that updates only ever touch title/description. That assumption held for every current caller (ModSingleholiday/ModExceptionholiday only ever change those two fields), but nothing enforced it - a future caller updating date in place would silently desync the cache for up to its TTL, with no error. Make the assumption explicit: reject an update that changes date, rather than silently allowing it. Callers that need to move a closure/exception to a different date must delete and re-add. Test plan: 1) prove t/db_dependent/Koha/Library/Calendar.t t/db_dependent/Calendar.t t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 1399f8af42721e21125d4c0eefaec81dde11ceee Author: Martin Renvoize Date: Wed Aug 5 08:55:52 2026 +0100 Bug 42310: (QA follow-up) Restore weekday validation on weekly closures C4::Calendar::insert_week_day_holiday used to croak "Invalid weekday $weekday" unless $weekday =~ m/^[0-6]$/. That guard was dropped when the insert delegated to Koha::Library::Calendar::WeeklyClosure, and nothing replaced it - an out-of-range or undef weekday now persists silently to library_weekly_closures instead of failing at the API boundary. Add the check to WeeklyClosure->store() rather than the legacy wrapper, so every caller (C4::Calendar, Koha::Library::Calendar->add_weekly_closure, and any future REST/admin caller) gets it, not just the old entry point. Test plan: 1) prove t/db_dependent/Koha/Library/Calendar.t t/db_dependent/Calendar.t t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t t/db_dependent/Holds/WaitingReserves.t Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit d0645cc8b1c0c39c80efbf5027211555847dad1c Author: Martin Renvoize Date: Wed Aug 5 08:53:40 2026 +0100 Bug 42310: (QA follow-up) Restore in-memory holiday cache sync in C4::Calendar insert_single_holiday and insert_exception_holiday delegate to Koha::Library::Calendar::SingleClosure/Exception, but stopped updating $self->{single_holidays}/{exception_holidays} on the C4::Calendar object itself, unlike the sibling insert_week_day_holiday/insert_day_month_holiday methods which still do. isHoliday() reads exactly those hashes, so a date just inserted via insert_single_holiday/insert_exception_holiday would read back as "not a holiday" for the rest of that object's lifetime - reachable from tools/newHolidays.pl and tools/exceptionHolidays.pl, which loop over several dates on one $calendar object, checking isHoliday() before each insert to skip duplicates. While adding a regression test, also found that _init() has the same class of bug on the DB-load path: it builds the single/exception lookup keys from `split(/-/, $row->{date})`, which keeps the zero-padding from the DATE string (e.g. "06"), while isHoliday() numifies its lookup key (e.g. "6"). Any single/exception holiday with a single-digit month or day was therefore invisible to isHoliday() even on a freshly reloaded C4::Calendar object. Both call sites now numify year/month/day before building the hash key. Test plan: 1) prove t/db_dependent/Holidays.t t/db_dependent/Calendar.t t/db_dependent/Koha/Library/Calendar.t t/db_dependent/HoldsQueue.t Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit e56aff8dfc24351d0f77daf3b74c0a2b62a9d8e2 Author: Martin Renvoize Date: Wed Apr 22 15:36:25 2026 +0100 Bug 42310: (follow-up) Update Holidays.t for normalized calendar tables The normalization commit dropped `repeatable_holidays` and `special_holidays` but t/db_dependent/Holidays.t still referenced them directly via raw SQL, so the test blew up on the first `DELETE FROM special_holidays` with "Table doesn't exist". The earlier namespace follow-up touched this file but only renamed Koha::Calendar references, missing the SQL. Replace the legacy table references with the four new normalized tables: repeatable_holidays (weekday set) -> library_weekly_closures repeatable_holidays (weekday NULL) -> library_repeating_closures special_holidays (isexception=0) -> library_single_closures special_holidays (isexception=1) -> library_closure_exceptions - Two fixture-cleanup DELETEs now wipe all four new tables. - The copy_to_branch 'no duplicates' check, previously two raw-SQL queries against the old two tables, becomes four queries against the new tables, keyed on each table's natural unique key (library_id+weekday / library_id+day+month / library_id+date). - Plan for the copy_to_branch subtest bumps from 8 to 10 to cover the two extra duplicate-check assertions. Test plan: 1. prove t/db_dependent/Holidays.t 2. All 15 top-level tests pass, including the 10 subtest assertions in copy_to_branch. Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 811d8bfd37dc190a999ae8b2078872d3236062af Author: Martin Renvoize Date: Fri Apr 17 16:41:21 2026 +0100 Bug 42310: (follow-up) Move Koha::Calendar tree under Koha::Library::Calendar Koha::Calendar is, by construction, a per-library object — it croaks without a branchcode argument and every method is branch-scoped. The top-level namespace hides that. Move the whole tree under Koha::Library::Calendar to match the actual semantics, the existing /libraries/{library_id}/calendar REST routes, and the established Koha::Library::* convention (Group, Hour, FloatLimit, OverDriveInfo). This commit: - renames the Koha::Calendar(::*) tree to Koha::Library::Calendar(::*) - updates package declarations, POD and internal 'use' statements within the moved tree - updates the four DBIC Schema Result overrides (koha_object_class / koha_objects_class) to the new namespace - updates callers inside C4::* modules (Calendar, Circulation, Reserves, Overdues, HoldsQueue), Koha::{Patron,Hold,Checkouts, CurbsidePickup}, circ/returns.pl, the installer and cronjobs - updates the 42310-owned tests (Calendar tests, HoldsQueue.t, Holds/WaitingReserves.t, Holidays.t, Koha/CurbsidePickups.t, Reserves/CancelExpiredReserves.t and the libraries.t CRUD block) Koha::Library->calendar, the REST controllers and the 42311 tests are updated in separate follow-up commits under their respective bugs. Test plan: - prove t/db_dependent/Koha/Library/Calendar.t - prove t/db_dependent/Calendar.t - prove t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t - prove t/db_dependent/Holds/WaitingReserves.t - prove t/db_dependent/Reserves/CancelExpiredReserves.t Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 7a8a220842fd992a9ad9c6cf389183ad6af6e30a Author: Martin Renvoize Date: Fri Apr 17 07:36:04 2026 +0100 Bug 42310: (QA follow-up) Add closed_dates_in_range to Koha::Calendar Introduces a public Koha::Calendar->closed_dates_in_range($from_dt, $to_dt) method that returns an arrayref of ISO date strings representing every closed day in the inclusive range, honouring weekly, annual repeating, single and exception (open-override) closures. This replaces callers that were reaching into Koha::Calendar private state (_holidays, weekly_closed_days, day_month_closed_days) to reconstruct the same logic. A follow-up under Bug 42206 converts the REST controller; further callers can be migrated incrementally. Test plan: 1. prove t/db_dependent/Koha/Calendar.t 2. Verify the new 'closed_dates_in_range' subtest passes Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 5875ce4c752a75d9f98a6637bb8a636ce6b63054 Author: Martin Renvoize Date: Fri Apr 17 07:32:55 2026 +0100 Bug 42310: (QA follow-up) Report duplicate rows skipped during migration The new calendar tables add UNIQUE(library_id, weekday), UNIQUE(library_id, day, month) and UNIQUE(library_id, date) constraints that did not exist on repeatable_holidays / special_holidays, so the INSERT IGNORE migration can silently drop legacy duplicate rows. This patch compares source vs destination row counts for each of the four migrations and emits a say_warning naming the constraint and pointing the operator at their pre-upgrade backup so titles or descriptions can be recovered if needed. Success lines now include the migrated row count. DROP statements for the legacy tables are guarded with TableExists and reported via say_success for consistency with the rest of the atomicupdate. Test plan: 1) Apply the update on a database containing legacy duplicates and verify the warning is emitted with the correct count. 2) Apply on a database with no duplicates and verify no warning appears. 3) Re-run the update and verify it is idempotent (no warnings, no re-migration). Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 548903ba022338f9dca7863d1b3c156d9070d5b8 Author: Martin Renvoize Date: Fri Apr 17 07:31:52 2026 +0100 Bug 42310: (QA follow-up) Harden Koha::Calendar->copy_to Wrap the body in schema->txn_do so a failure partway through does not leave the target library partially populated. Flush the target's _holidays cache after the copy, and document the behaviour in POD: weekly and repeating closures are always copied, but single closures and exceptions are filtered to today-or-later dates by design. Test plan: 1) prove t/db_dependent/Koha/Calendar.t 2) Confirm existing copy_to tests still pass. Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit c3880a70e6dcbfba9c817c25ac0b77477a0e8cc6 Author: Martin Renvoize Date: Fri Apr 17 07:30:42 2026 +0100 Bug 42310: (QA follow-up) Fire per-row delete hooks in Koha::Calendar delete_* methods 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 commit d4e4f57072e86b65624a93115f4fd41b15281781 Author: Tomás Cohen Arazi Date: Thu Apr 9 12:48:59 2026 -0300 Bug 42310: (follow-up) Bake cache invalidation into Koha::Object classes When using the new Koha::Calendar::* classes for writing the CRUD API endpoints I noticed that in my attempt to keep C4::Calendar similar to what it was, I ended up with cache invalidation not always done in the right place. The holidays cache (keyed by {branchcode}_holidays) stores dates and their open/closed status, not titles or descriptions. This means only inserts and deletes need to invalidate it — metadata updates (title/description) do not. Following the pattern established by Koha::AuthorisedValue and Koha::ItemType, I added store() and delete() overrides to Koha::Calendar::SingleClosure and Koha::Calendar::Exception: - store() flushes the cache only on insert (!in_storage), not on updates, since the cache doesn't store titles or descriptions. - delete() always flushes, since removing a closure changes the cached set. This allowed removing the now-redundant _clear_cache calls from Koha::Calendar::add_single_closure, add_exception, delete_single_closure, delete_exception, and from C4::Calendar::ModSingleholiday and ModExceptionholiday. Signed-off-by: Tomás Cohen Arazi Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit cb7968387a96636eff093a6ca6d427088fa93990 Author: Tomás Cohen Arazi Date: Wed Apr 8 16:07:44 2026 -0300 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 Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 4d23dff4339e14a8d527397652edd6c54d4b168e Author: Tomás Cohen Arazi Date: Wed Apr 8 15:48:56 2026 -0300 Bug 42310: (follow-up) Adapt Calendar tests to new schema Replace all references to the dropped tables (RepeatableHoliday, SpecialHoliday resultsets and raw DBI inserts) with Koha::Object classes: Koha::Calendar::WeeklyClosure, RepeatingClosure, SingleClosure, and Exception. Signed-off-by: Tomás Cohen Arazi Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 166e9831ea3ede2971f9445cf037cf0bc722b952 Author: Martin Renvoize Date: Wed Aug 5 08:59:14 2026 +0100 Bug 42310: DBIC schema manual updates Add koha_object_class/koha_objects_class overrides for the four new Result classes backing the normalized calendar tables, below the auto-generated marker. Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit c0349ad1426e4668b94bf04e060d2982c0a829d8 Author: Martin Renvoize Date: Wed Aug 5 08:58:38 2026 +0100 Bug 42310: DBIC schema update Regenerated via dbic --force after the library_weekly_closures, library_repeating_closures, library_single_closures, and library_closure_exceptions tables replaced repeatable_holidays and special_holidays. Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit ca487a18e0d4ad2e9284079d395f4e301215894d Author: Tomás Cohen Arazi Date: Wed Apr 8 15:37:35 2026 -0300 Bug 42310: (follow-up) Add missing POD Signed-off-by: Tomás Cohen Arazi Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 0629de1e54ec242db52a768c9256ca4a569d76a8 Author: Tomás Cohen Arazi Date: Wed Apr 8 15:32:20 2026 -0300 Bug 42310: Refactor Koha::Calendar to use Koha::Calendar::* classes Replace raw DBI queries in _init() and _holidays() with Koha::Calendar::WeeklyClosures, RepeatingClosures, SingleClosures, and Exceptions searches. The internal data structures remain identical (weekly_closed_days array, day_month_closed_days hash, _holidays hash with YYYYMMDD keys) so all consumers (is_holiday, addDuration, next_open_days) continue to work unchanged. Signed-off-by: Tomás Cohen Arazi Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 402938f7cdc8e7f4670e9b92a2738f2304ddbcdb Author: Tomás Cohen Arazi Date: Wed Apr 8 15:32:11 2026 -0300 Bug 42310: Add Koha::Calendar::* Object classes Four Koha::Object + Koha::Objects pairs following the Koha::City(ies) pattern: - Koha::Calendar::WeeklyClosure(s) -> library_weekly_closures - Koha::Calendar::RepeatingClosure(s) -> library_repeating_closures - Koha::Calendar::SingleClosure(s) -> library_single_closures - Koha::Calendar::Exception(s) -> library_closure_exceptions DBIC schema files to be generated via the 'dbic' alias in KTD after the database migration runs. Signed-off-by: Tomás Cohen Arazi Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 5a3e86d0b6901c171b0e991a6de9fdb268132b2d Author: Tomás Cohen Arazi Date: Wed Apr 8 15:28:12 2026 -0300 Bug 42310: Normalize calendar tables Replace the two overloaded tables (repeatable_holidays, special_holidays) with four purpose-specific tables: - library_weekly_closures: weekly closed days (e.g. every Sunday) - library_repeating_closures: annual repeating closures (e.g. Dec 25) - library_single_closures: one-off closures with a DATE column - library_closure_exceptions: open overrides with a DATE column All use library_id FK and follow current community standards. It points to API usage in a short term so it follows the API naming conventions. Signed-off-by: Tomás Cohen Arazi Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Tomás Cohen Arazi Signed-off-by: Pedro Amorim commit 4ff58e553b33a495d5d0564ab5db63f7dbbdcf8d Author: Martin Renvoize Date: Tue Sep 15 11:16:46 2026 +0100 Bug 31391: (QA follow-up) Remove unused variables in ModReserve recall conversion $due_interval and $due_date (and $recall itself) returned by Koha::Recalls->add_recall were captured but never used in either branch of the new rank => "recall" handling. Drop the unused assignment - no behaviour change. Test plan: 1) prove t/db_dependent/Holds.t t/db_dependent/Reserves.t - all pass Signed-off-by: Pedro Amorim commit 0b7d3b856a20743c40897a754a20934fbe36e48e Author: Martin Renvoize Date: Tue Sep 15 11:15:04 2026 +0100 Bug 31391: (QA follow-up) Add missing test coverage for hold-to-recall conversion Two code paths introduced by this bug had no direct test coverage: - C4::Reserves::ModReserve's title-level branch of the new `rank => "recall"` conversion (only the item-level branch was tested). - The `hold_convert` bypass in Koha::Item::can_be_recalled, which skips the "patron already has a hold on this item" check so an existing hold can be converted to a recall for the same patron. No production code changes here, coverage only. Test plan: 1) prove t/db_dependent/Holds.t t/db_dependent/Koha/Item.t - all pass 2) Confirm the new tests actually exercise the code they claim to: reverting the `unless ( $params->{hold_convert} )` guard in Koha/Item.pm locally makes the new Item.t subtest fail, as expected. Signed-off-by: Pedro Amorim commit cd30d78c0ed074587e54adae76ac49b38ce61282 Author: Martin Renvoize Date: Tue Sep 15 11:10:58 2026 +0100 Bug 31391: (QA follow-up) Fix UseRecalls check in Transfers REST controller UseRecalls was converted from a YesNo syspref to a Choice preference ("off"/"opac"/"staff"/"opac_and_staff") earlier in this bug, and every call site was updated from a truthy check to `ne "off"` - except this one. Since even the string "off" is truthy in Perl, the guard in Koha::REST::V1::Transfers::cancel was silently defeated: cancelling a transfer via the REST API always attempted to revert an in-transit recall, even with recalls disabled. Test plan: 1) prove t/db_dependent/api/v1/transfers.t - new subtest 'cancel() - UseRecalls disabled' fails against the old code (the in-transit recall gets reverted even though UseRecalls is off) 2) Apply this patch 3) Same test now passes Signed-off-by: Pedro Amorim commit 85c37deb774d151e673f3f179daf5194510c798d Author: Martin Renvoize Date: Tue Sep 15 12:24:49 2026 +0100 Bug 41898: (follow-up) Guard bookings.js against missing DOM when patron has no bookings js/tables/bookings.js unconditionally called AdditionalFilters.init() for 'filter-completed' and 'filter-cancelled' on every page load where the script is included. patron-detail-tabs.inc only renders those filter elements (and #bookings_table itself) when the patron has at least one booking, past or present. For any patron with no booking history, this produced two console.debug 'Element not found' messages on moremember.pl and circ/circulation.pl. Guard the ready handler on the presence of #bookings_table, mirroring the existing pattern in holds.js. Test plan: 1) Open moremember.pl for a patron with no bookings; confirm no AdditionalFilters console messages appear. 2) Open moremember.pl / circ/circulation.pl for a patron with bookings; confirm the Bookings tab, filters, and table still work as before. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Pedro Amorim commit d0a79a677ca609147687e52b3b57483827671663 Author: Pedro Amorim Date: Tue Sep 15 09:38:08 2026 +0000 Bug 41920: (RM follow-up) Remove dead resultset build in Koha::Reports::running Signed-off-by: Pedro Amorim commit 8d9e7e641aa2c4e3b38fdb764c264f9f78b9a57c Author: Lucas Gass Date: Thu Sep 10 15:32:13 2026 +0000 Bug 41920: Add unit tests Signed-off-by: Pedro Amorim commit fd82dca909ec25e34bcbcf7110889928d2a102a6 Author: Lucas Gass Date: Thu Sep 10 15:07:24 2026 +0000 Bug 41920: Remove code from reports/guided_reports.pl Signed-off-by: Pedro Amorim commit ada73c317c31827072938ad066006aefdce72f58 Author: Lucas Gass Date: Thu Sep 10 15:06:44 2026 +0000 Bug 41920: Move total_running_reports_per_instance_limit to Koha/Reports.pm Signed-off-by: Pedro Amorim commit 7ba7bbab7d74e557a834d55e0a9b6817ea9b8d79 Author: Kyle M Hall Date: Wed Feb 25 13:05:03 2026 -0500 Bug 41920: Limit number of concurrent reports that can be run simultaneously for an instance of Koha As a continuation of bug 41919, we should limit the total number of simultaneous reports that can be run at a time. Test Plan: 1) Set total_running_reports_per_instance_limit to 2 in your koha-conf.xml 2) Create 3 long running reports like: SELECT COUNT(*) FROM items i1 JOIN items i2 JOIN items i3 JOIN items i4 JOIN items i5 JOIN items i6 3) Run each report in turn by opening a new tab, browsing to the reports module, and choosing to run that report 5) Note the first two continue to run, but the last one gives an error that you have too many reports running simultaneously! Signed-off-by: Alex Carver [Acerock7] Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 92cbbd59d52f440942e1148c6ee68c1f5febd71f Author: Thibaud Guillot Date: Mon Sep 14 14:01:23 2026 +0000 Bug 32748: (QA follow-up) Fix duplicate AV when limited to several libraries at once When an authorised value is limited to more than one library, the no_limit query in GetAuthorisedValues joins authorised_values_branches and returns one row per associated library, so the value was listed several times in the item edition dropdown. Group by the authorised value so each one is only returned once, and aggregate the restricted flag with MIN() so the value stays unrestricted as soon as one of its libraries matches the current one. Sponsored-by: BibLibre Signed-off-by: Pedro Amorim commit d7f1426d581f59e1346d29ac12b6fd30ae6fac5a Author: Thibaud Guillot Date: Fri Aug 28 09:23:24 2026 +0200 Bug 32748: (QA follow-up) Tidy test file Signed-off-by: Lisette Scheer Signed-off-by: Pedro Amorim commit e2506598c87f5efd0205b68e3b2d83a6673bbf09 Author: Thibaud Guillot Date: Fri Aug 28 09:19:22 2026 +0200 Bug 32748: (QA follow-up) Fix branchcode filtering on itemtypes Signed-off-by: Lisette Scheer Signed-off-by: Pedro Amorim commit 0794f75adc86a432e40a7ae4a60745b810072db7 Author: Thibaud Guillot Date: Tue Aug 11 16:42:28 2026 +0200 Bug 32748: (QA follow-up) Fix cache key and add tests Sponsored-by: BibLibre Signed-off-by: Lisette Scheer Signed-off-by: Pedro Amorim commit 5205fc8bcc56b0019d12613fdd28221a9f40080f Author: Lisette Scheer Date: Tue Nov 18 02:47:21 2025 +0000 Bug 32748: (QA follow-up) Fix spelling and tidy Signed-off-by: Lisette Scheer Signed-off-by: Pedro Amorim commit b443b319988352c21432c688878092d1367b356b Author: Thibaud Guillot Date: Thu Apr 6 17:16:22 2023 +0200 Bug 32748: Fix item edition when authorised values is restricted When we set an authorised value linked to one library, users who do not belong to this library do not get the value and can therefore overwrite it. This patch add current value to the dropdown list even if it comes from an authorized value of another library. Test plan : 1) Edit an item with one of these fields has an authorized value from another library. 2) On 'edit' you will see AV but with '(Not an authorised value)' string and a warn 3) Apply this patch 4) Refresh page and edit item again 5) Now if the authorised value belongs to another lib and is the current value, you will see it with a tooltip and a warn. But if there are authorised values restricted to another lib and isn't current value, normally it will be not present in the option list. Sponsored-by: BibLibre Signed-off-by: Mathieu Saby Signed-off-by: Lisette Scheer Signed-off-by: Pedro Amorim commit f2aa1ecb536a7cecc468645038a3542599914118 Author: Pedro Amorim Date: Mon Sep 14 14:15:10 2026 +0000 Bug 31391: DBRev 26.06.00.025 Signed-off-by: Pedro Amorim commit 8ccba18691853c6aae072fe5c5aff84102440a0a Author: Pedro Amorim Date: Mon Sep 14 13:30:02 2026 +0000 Bug 31391: (RM follow-up) Enforce recalls permission when converting holds to recalls The previous follow-up only blanked the button's label via JS for users without the recalls permission; the button still rendered, was still clickable, and modrequest.pl's cud-convertall had no permission check at all, so the conversion still succeeded. Adds CAN_user_recalls to the button's template condition (matching the existing "Move selected holds" button) so it doesn't render at all without the permission, drops the now-redundant JS check in holds.js, and adds a manage_recalls check in modrequest.pl itself. checkauth()'s userid is the login username, not a borrowernumber, so this uses C4::Auth::haspermission() directly rather than Koha::Patrons->find(). Test plan: 1) Set a default recalls rule in admin/smart-rules.pl. 2) Set UseRecalls to 'staff' or 'opac_and_staff'. 3) Give a test patron 'catalogue' + 'reserveforothers' but not 'recalls'. 4) Check out an item, place a hold on it for another patron. 5) As the test patron, go to that record's Holds tab, confirm 'Convert selected to recall' doesn't appear. 6) Since the button is gone, confirm the server side is enforced too: post op=cud-convertall directly to modrequest.pl and confirm it no longer converts the hold. 7) Grant 'recalls' and confirm the button reappears and works. Co-Authored-By: Claude Sonnet 5 Signed-off-by: Pedro Amorim commit 324b4d2fbedd5f94ef9675adb6abafd281880de8 Author: Katrin Fischer Date: Mon Sep 14 12:39:33 2026 +0000 Bug 31391: (QA follow-up) Hide "Convert selected to recall" for users with no recalls permission This introduces a permission check on "recalls" for the link on the holds summary page. 1) Go to http://localhost:8081/cgi-bin/koha/admin/smart-rules.pl, and under the default rule, set: - 'Recalls allowed (total)': 5 - 'Recalls per record': 3 - 'On shelf recalls allowed': if any unavailable - 'Recall due date interval': 5 - 'Recall overdue fine amount': 5 - 'Recall pickup period': 2 2) Go to 'Administration' > 'Global system preferences' (http://localhost:8081/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=UseRecalls), set 'UseRecalls' to 'can be placed through the staff interface only'. 3) Go to Henry's patron account, borrowernumber 19, set him a password (http://localhost:8081/cgi-bin/koha/members/member-password.pl?member=19), then edit his permissions (http://localhost:8081/cgi-bin/koha/members/member-flags.pl?member=19) and give him only 'catalogue' and 'reserveforothers' (place holds), do not give him 'recalls'. 4) As a superlibrarian, check out item 39999000003154 (biblionumber 76) to borrowernumber 23, then place a hold on that same record for borrowernumber 49 5) Log out and log back in as Henry. 6) Go to http://localhost:8081/cgi-bin/koha/reserve/request.pl?biblionumber=76, tick the checkbox next to the hold, click 'Convert selected to recall', confirm in the modal. 7) The hold gets cancelled and a recall gets created, even though Henry has no recalls permission at all, proving the action isn't actually gated by it. 8) Apply patch, re-run test plan to 6) - The link to convert should no longer display. 9) Toggle the recalls permission for Henry, link to convert should now reappear. Signed-off-by: Pedro Amorim commit 3df791492577c138213ec02a89facb32bebb4ab1 Author: Katrin Fischer Date: Fri Sep 11 16:00:12 2026 +0000 Bug 31391: (QA follow-up) Make sure pickup-library is kept when converting holds to recalls The code was using the patron's home library instead of passing the pickup-location of the original hold. This is a simple variable change in 2 places for record level and item level holds. A) Set 'UseRecalls' to 'staff' at http://localhost:8081/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=UseRecalls B) At http://localhost:8081/cgi-bin/koha/admin/smart-rules.pl set the default rule: 'Recalls allowed' = 5, 'Recalls per record' = 3, 'On shelf recalls allowed' = 'if any unavailable' (not 'all'). C) Use biblionumber '437' (has just one item, barcode '39999000019186'), check that item out to 'Henry Acevedo' (Patron A). D) Place a record-level hold on it for 'Johnny Bryan' (Patron B), who's from 'Midway' — but set the hold's pickup location to 'Centerville' instead. E) On http://localhost:8081/cgi-bin/koha/reserve/request.pl?biblionumber=437, tick the hold, click 'Convert selected to recall', confirm. F) Check the new recall's pickup location on http://localhost:8081/cgi-bin/koha/recalls/request.pl?biblionumber=437 - Expected: 'Centerville' - Without the patch applied, it will be the patron's home library: Midway - With the patch applied, the pickup-location of the hold is kept: Centerville. G) Cancel the recall. H) Repeat the test plan, but in step D) place an item level hold instead of a record level hold. Signed-off-by: Katrin Fischer Signed-off-by: Pedro Amorim commit e128051d09cd48062b712fe374e386606b6cf32b Author: Katrin Fischer Date: Fri Sep 11 15:40:54 2026 +0000 Bug 31391: (QA follow-up) Fix check for UseRecalls for messaging preferences in OPAC We are skipping the notice, if UseRecalls == "off". This now matches the check in staff too. A) Go to the KTD staff interface at http://localhost:8081/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=UseRecalls and set 'UseRecalls' to any non-'off' value, e.g. 'can be placed through the OPAC only'. B) Log into the OPAC at http://localhost:8080/cgi-bin/koha/opac-user.pl as any patron. C) Go to http://localhost:8080/cgi-bin/koha/opac-messaging.pl D) Look for the recall-related notice row (item recalled / recall notices) — it's missing, even though recalls are enabled. E) Now flip 'UseRecalls' back to 'off' in step 1's page. F) Reload http://localhost:8080/cgi-bin/koha/opac-messaging.pl — the recall notice row now shows up, even though recalls are off. G) Steps 4 and 6 are the reverse of what should happen — confirms the condition is inverted. Signed-off-by: Katrin Fischer Signed-off-by: Pedro Amorim commit a5e8fdccbd780dd348738fa6c46d3ee543404660 Author: Katrin Fischer Date: Fri Sep 11 15:38:33 2026 +0000 Bug 31391: (QA follow-up) Adjust for changes made by bug 42443 This fixes a test to use 'opac' in transfers.t Signed-off-by: Katrin Fischer Signed-off-by: Pedro Amorim