commit 50df5d5acaf8b21ee242318a8173c32c172c9ae5 Author: Martin Renvoize Date: Mon Mar 23 11:14:40 2026 +0100 Bug 40136: (RM follow-up) Add missing pod coverage for private subs Signed-off-by: Martin Renvoize commit 863b68b1356a27f1a023a53e7f57409bcef05f54 Author: Martin Renvoize Date: Mon Mar 23 11:05:36 2026 +0100 Bug 40136: (RM follow-up) Fix logaction to JSON-encode plain hashref infos Commit 55689d41ba6 changed Koha::Patron::extended_attributes() and add_extended_attribute() to pass plain hashrefs to logaction() and updated tests to expect JSON in the info column. However, logaction() still had a code path that converted any non-CATALOGUING hashref $infos to a Dumper() string before the encode_json() at line 151 could fire, so JSON was never stored and the tests failed. Remove the catch-all Dumper branch; non-CATALOGUING hashref inputs now fall through to the existing encode_json() call. The CATALOGUING/MODIFY biblio-Dumper special case is preserved. Signed-off-by: Martin Renvoize commit 25b7068b497b0014c910f3b3d8af164f6943a3eb Author: Martin Renvoize Date: Thu Mar 12 09:23:14 2026 +0000 Bug 40136: (follow-up) Log newly-filled fields when editing a patron Previously, _unblessed_for_log strips undef/empty fields, so fields that were blank before an edit were absent from $from_storage. Because @keys was built only from keys %{$from_storage}, any field that transitioned from empty to a value was never iterated and the change went unlogged. Fix by unioning keys from both old and new state so that added, changed, and cleared fields are all detected. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit f4db130ad4f9a956dfee804711bb2134b8905f6c Author: Martin Renvoize Date: Wed Mar 11 12:49:05 2026 +0000 Bug 40136: (follow-up) Unify patron log entries when attributes change with patron data Three issues were reported with patron action logging: 1. CREATE followed by extended_attributes() produced two log entries (CREATE for patron fields + MODIFY for attributes) instead of one. 2. MODIFY that changed both regular fields and patron attributes produced two separate MODIFY entries instead of one unified entry. 3. DELETE log did not include the patron's extended attribute values. Fix: - logaction() now explicitly returns the stored Koha::ActionLog object so callers can capture the action_id. - Koha::Patron::store() saves the action_id of the CREATE or MODIFY log it writes into $self->{_patron_log_id}. - Koha::Patron::extended_attributes() setter checks for _patron_log_id. If set, it calls _merge_attribute_log() to fold the attribute changes into the existing log entry (updating its info and diff JSON) instead of creating a new MODIFY entry. This covers both the CREATE and MODIFY cases. - Koha::Patron::delete() now iterates extended_attributes before deletion and adds attribute.CODE keys to the patron_data snapshot, so the DELETE diff includes the removed attributes. - New private helper _merge_attribute_log() decodes an existing action log entry's info/diff JSON, merges in the attribute change data using Struct::Diff, and saves the updated entry. - Tests added to t/db_dependent/Koha/Patrons.t covering all three scenarios. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 7287b091a45691ff8f01d23229be388bf88ff340 Author: Lisette Scheer Date: Tue Mar 10 14:27:44 2026 +0000 Bug 40136: (QA follow-up) Fix tests Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 543ebdc2ff6fd5b7678f1988409203454e05cd0d Author: Martin Renvoize Date: Tue Mar 10 09:39:18 2026 +0000 Bug 40136: (follow-up) Strip undef and empty fields from patron log data Exclude fields with undef or empty string values from _unblessed_for_log so that CREATE and DELETE log diffs only show fields with meaningful values. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 55689d41ba6d6e6feabc6b19ebd9ada869d338c7 Author: Martin Renvoize Date: Mon Mar 9 22:15:08 2026 +0000 Bug 40136: (follow-up) Fix extended_attributes logaction to populate diff column The extended_attributes setter and add_extended_attribute both logged attribute changes using the old custom {before, after} format passed as the info string, with no $original argument, so the diff column was never populated. Split the existing $change->{before}/$change->{after} into separate $log_from/$log_to hashrefs and call logaction with the standard signature, so Struct::Diff generates the diff column as with other MEMBERS/MODIFY entries. Update tests to reflect the new info column format (after-state only) and remove a stray debug Data::Dumper/print left in the test. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 9ae4911704082121ac18b13491272b68809db4e0 Author: Martin Renvoize Date: Mon Mar 9 22:05:08 2026 +0000 Bug 40136: (follow-up) Refactor MODIFY log to use _unblessed_for_log Replace the manual unblessed + skip_fields + blessed-stringify logic in the MODIFY actionlog section with calls to _unblessed_for_log, which already handles all three concerns. This removes the need for @skip_fields, the dateexpiry normalisation workaround, and the inline blessed checks. Also restrict the log_from/log_to hashrefs to only the changed keys, so the diff column contains only fields that actually changed rather than the full patron state. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit f83424d3dd92b7ed03fded2a4725d3043eb65e3c Author: Martin Renvoize Date: Fri Mar 6 17:02:26 2026 +0000 Bug 40136: Populate diff column for patron CREATE, MODIFY and DELETE logs Previously MEMBERS/CREATE and MEMBERS/DELETE logged empty info with no diff, and MEMBERS/MODIFY stored a custom {field:{before,after}} JSON in the info column with no diff column entry. This updates all three to use the standard logaction pattern: - CREATE: diff({}, patron_data) — all fields shown as added - MODIFY: diff(old_state, new_state) via Struct::Diff; info column now holds the full updated patron state (consistent with other modules) - DELETE: diff(patron_data, {}) — all fields shown as removed - MODIFY_CARDNUMBER: likewise uses standard pattern with diff column Password, lastseen and updated_on are excluded from all log payloads. DateTime objects (inflated date/datetime columns) are stringified to their ISO representation before JSON serialisation. Tests updated to verify changes via the diff column rather than the former custom info format. Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 9d20ea636ad1780beeb4086904632a8fe1775984 Author: Lisette Scheer Date: Fri Mar 6 18:05:08 2026 +0000 Bug 20956: (QA follow-up) Restore info pretty I restored the pretty code for the info file because the page needs to be able to wrap, like it does for other logs. Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit f528142daa322796c9848e2baf7def12298f7d79 Author: Martin Renvoize Date: Fri Mar 6 16:55:28 2026 +0000 Bug 20956: (follow-up) Nest permissions data under 'permissions' key in MEMBERS/MODIFY log Changes to patron permissions via member-flags.pl are logged as MEMBERS/MODIFY, indistinguishable from regular patron field edits. This patch wraps the before/after permission hashes under a 'permissions' key so that the diff renderer displays changes as 'permissions.cataloguing' etc., making it clear the diff relates to permissions rather than first-level patron fields. Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 182ccd1c0b363c3f0497000f9ea42662e1950b4a Author: Ayoub Glizi-Vicioso Date: Wed Feb 4 17:07:08 2026 -0500 Bug 20956: Fix test failures Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit cd34882803ea78b285bf811dc3c05ac74e136594 Author: Martin Renvoize Date: Mon Dec 22 17:06:31 2025 +0000 Bug 20956: (QA follow-up) Match getuserflags() return structure This patch changes Koha::Patron->permissions() to return the same structure as C4::Auth::getuserflags() for architectural consistency. Previously, permissions() only returned granted permissions: { catalogue => 1, circulate => { override_renewals => 1 } } Now it returns ALL flags (matching getuserflags()): { superlibrarian => 0, catalogue => 1, circulate => { override_renewals => 1 }, borrowers => 0, ... } This provides several benefits: 1. Consistency - Matches established C4::Auth::getuserflags() pattern 2. Simpler checks - Can use "if ($flags->{module})" instead of "if (exists $flags->{module})" 3. Future compatibility - Enables eventual deprecation of getuserflags() in favor of the ORM-based $patron->permissions() 4. Helper compatibility - Works with existing _dispatch() logic The logging functionality still works correctly - the diff will now show explicit changes from 0 to 1 rather than absence to presence. Test plan: 1. prove t/db_dependent/Koha/Patron.t 2. prove t/db_dependent/Log.t 3. Verify all tests pass 4. Confirm permissions() now returns all flags with 0/1 values Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit ae60527f91422b053fc55018b35f161362e0fa14 Author: Martin Renvoize Date: Mon Dec 22 16:38:42 2025 +0000 Bug 20956: (QA follow-up) Fix tests and refactor to use ORM This patch addresses several QA concerns: 1. Fixed duplicate subtest name - renamed second "is_superlibrarian() tests" to "permissions() tests" which accurately reflects what it tests 2. Fixed incorrect hash assignment - permissions() returns a hashref, not a hash. Changed `my %permissions` to `my $permissions` 3. Improved test coverage - expanded from 2 to 8 assertions covering: - Hashref return type verification - Single flag permission - No permissions - Multiple flags - Granular subpermissions from user_permissions table 4. Refactored permissions() method to use DBIx::Class ORM instead of raw SQL queries, following Koha::Object architecture principles All tests now pass without warnings. Test plan: 1. prove t/db_dependent/Koha/Patron.t 2. prove t/db_dependent/Log.t 3. Verify all tests pass 4. Confirm the test now properly validates the intended behavior Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit c092059a7756b8074d6f27d9de41806f2677da7f Author: Hammat Wele Date: Tue Oct 21 20:45:58 2025 +0000 Bug 20956: (follow-up) Tidyness and fix no pod coverage in Koha/Patron.pm Signed-off-by: Hammat Wele Signed-off-by: Martin Renvoize Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 489f19a410376847eed3fd2eba4b7352404b62c1 Author: Kyle M Hall Date: Wed Oct 8 13:41:33 2025 -0400 Bug 20956: (QA follow-up) Move subs to Koha::Patron, add unit tests Subroutines in members/member-flags.pl are combined and moved to Koha::Patron Removed the html-based english description of each permission from the logging Signed-off-by: Kyle M Hall Signed-off-by: Martin Renvoize Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 553a18da0984215767a954cab937e0307f0a9dd4 Author: Hammat Wele Date: Fri Sep 12 19:14:59 2025 +0000 Bug 20956: BorrowersLog is not logging permission changes Changes to permissions are not logged in the Koha action_logs, making it impossible to trace changes to staff permissions. This patch ensures that all changes to permissions are logged. Test plan: 1. Go to a staff interface 2. Search for a patron and change their permissions (note their borrowernumber) 3. Go to tools/Log viewer 4. Filter by Module = Patrons, Object = . 5. Click on submit ==> No permission changes are logged. 6. Apply the patch 7. Repeat step 1, 2, 3, 4, 5 ==> Permission changes are now logged 8. Check that the diff column contains the change: select diff from action_logs where object= order by action_id desc limit 1; Signed-off-by: David Nind Signed-off-by: Kyle M Hall Signed-off-by: Martin Renvoize Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 983792537973060c258c0097113ed4c58a4c0dbf Author: Martin Renvoize Date: Thu Mar 12 10:51:09 2026 +0000 Bug 40135: (follow-up) Add tests for Koha::Biblio::_unblessed_for_log Add a '_unblessed_for_log() tests' subtest to t/db_dependent/Koha/Biblio.t that verifies: - the method returns a plain hashref - fields with real values (biblionumber, title, author) are present - timestamp is excluded - undef fields are excluded - empty-string fields are excluded - the ADD action log diff column is populated and does not contain timestamp Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit a8578c93f0f8ac01d1630520412b681d9a762ed8 Author: Martin Renvoize Date: Thu Mar 12 10:48:13 2026 +0000 Bug 40135: (follow-up) Strip undef and empty fields from biblio log data Add _unblessed_for_log to Koha::Biblio, mirroring the same method in Koha::Patron (bug 40136). It excludes undef/empty-string columns and the auto-updated timestamp field so that biblio diffs only contain meaningful values. Update AddBiblio, ModBiblio and DelBiblio in C4/Biblio.pm to use _unblessed_for_log instead of raw unblessed when building the hashrefs passed to logaction, eliminating noise from null columns in ADD/MODIFY/DELETE diffs. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit ef7dde45f773d7ec06c749935f3e359728429d7b Author: Martin Renvoize Date: Mon Mar 9 21:46:09 2026 +0000 Bug 40135: Fix info column prefix for biblio MODIFY logs The MODIFY path in logaction received the updated biblio as a plain hashref (not a Koha::Object), so the info column was populated with raw Dumper output instead of the expected "biblio ..." prefix. This broke two things: the 'Modification Log' link from the bib record sidebar (which filters on info LIKE 'biblio%'), and the Object column in the log viewer (which detects biblio entries via info.substr(0,6)). Following the same pattern as the Koha::Item MODIFY special case, add a parallel branch for CATALOGUING MODIFY with a hashref \$infos that sets the info column to "biblio " . Dumper(\$original). This restores backward-compatible detection while keeping the diff column correctly populated from the before/after hashrefs (including _marc changes). Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit f8f653f71ef9674c5753956aacc1a5499bf60ba5 Author: Martin Renvoize Date: Mon Mar 9 16:26:42 2026 +0000 Bug 40135: Include MARC field changes in CATALOGUING diff logs The previous commit populated the diff column for biblio ADD/MODIFY/DELETE logs with changes to biblio table columns (title, author, frameworkcode, etc.), but lost the MARC-level change tracking that previously stored a pre-change MARC dump in the info column. This follow-up extends the diff to also capture MARC field changes by including a synthetic _marc key in the before/after hashrefs passed to logaction. MARC fields are represented as tag => array-of-formatted-strings (e.g. "10 $a Title" for data fields, scalar for control fields), allowing Struct::Diff to produce readable field-level diffs. The _marc entries appear alongside biblio column changes in the existing diff table in the log viewer, using dotted keys like _marc.245.0. A helper _marc_record_to_diffable() converts a MARC::Record to this diffable hashref. All three functions (AddBiblio, ModBiblio, DelBiblio) use record_strip_nonxml (wrapped in eval) to safely capture the MARC even for records with invalid XML characters, without producing warnings or affecting the success of the main operation. C4/Log.pm is also updated to Dumper() a plain hashref passed as $infos, so the info column contains useful data rather than a stringified ref. Tests are extended to verify that the diff column is populated and that _marc changes are captured when MARC content actually changes. Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit f16d5f3ad4c0a39dc6014db1f3056eba69179f5d Author: Martin Renvoize Date: Fri Mar 6 16:35:08 2026 +0000 Bug 40135: Populate diff column for biblio ADD/MODIFY/DELETE logs Previously the CATALOGUING action log entries for biblio operations stored minimal data: ADD and DELETE logged just the string "biblio", while MODIFY logged a raw MARC-formatted dump of the pre-change record as a plain text string. None of these populated the diff column. This follow-up updates AddBiblio, ModBiblio and DelBiblio in C4/Biblio.pm to follow the same pattern as Koha::Item::store, passing the Koha::Biblio object and an original unblessed hashref to logaction so that the diff column is automatically populated with Struct::Diff JSON reflecting the changes to the biblio table columns (title, author, frameworkcode, etc.). For ADD, logaction diffs an empty hashref against the new biblio state, producing added-field entries for all columns. For DELETE, it diffs the pre-deletion state against an empty hashref, producing removed-field entries. For MODIFY, the before-state is captured prior to the update and the after-state is read back once ModBiblioMarc and _koha_modify_biblio have completed, so the diff reflects the actual committed changes. The test for ModBiblio on an invalid MARC record is updated to reflect that the MARC decoding error is no longer logged in the info column; the biblio table data is now logged instead. Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 788d1b455fd7b816cb9899fa7d17b0a9dc8471b4 Author: Martin Renvoize Date: Fri Mar 6 16:16:23 2026 +0000 Bug 36698: Expand nested object values in diff table When the diff column contains a value that is itself an object (e.g. a set of granular subpermissions such as {"override_renewals":1,"manage_curbside_pickups":1}), the previous renderer would JSON.stringify it into a single unreadable cell. This follow-up makes fmt() recurse into objects, rendering them as an indented
    list of key: value pairs instead. The / colour wrapper then highlights the entire expanded block, making it clear at a glance which subpermissions were added or removed. null values (e.g. suspend_until transitioning to/from null) are rendered as empty, letting the red/green cell background convey the presence or absence of the value. Signed-off-by: David Nind Signed-off-by: Lisette Scheer Signed-off-by: Martin Renvoize commit 56a8a9a9346e78fd7ee927a9aa54881b12a73eab Author: Martin Renvoize Date: Fri Mar 6 15:54:46 2026 +0000 Bug 36698: Render diff column as a human-readable table in the log viewer Previously the diff column in the log viewer displayed raw Struct::Diff JSON (e.g. {"D":{"superlibrarian":{"N":1,"O":0}}}), which was not useful to end users. This follow-up adds a JavaScript renderer (renderStructDiff) to viewlog.js that parses the Struct::Diff JSON and presents it as a compact Field / Before / After table, reusing the existing / colour styling already present for the jsdiff compare feature. Nested diffs (e.g. granular subpermissions) are flattened using dot-separated key names. Non-Struct::Diff content falls back gracefully to a
        block so that entries from other modules are not affected.
        
        The change benefits all modules that currently populate the diff column:
        HOLDS (MODIFY/SUSPEND/RESUME/CANCEL/FILL), CATALOGUING (MODIFY),
        APIKEYS (MODIFY/REVOKE/ACTIVATE), and MEMBERS (MODIFY for permissions).
        
        Signed-off-by: David Nind 
        Signed-off-by: Lisette Scheer 
        Signed-off-by: Martin Renvoize 
    
    commit bf0c748315301bda5b8794542eb06c25e4e04237
    Author: Kyle M Hall 
    Date:   Fri Feb 20 15:58:51 2026 +0000
    
        Bug 41107: (QA follow-up) Tidy status.t
        
        Signed-off-by: Kyle M Hall 
        Signed-off-by: Martin Renvoize 
    
    commit f64051cddb875b7c87f6e877af6ad1c2bf4d4699
    Author: Tomás Cohen Arazi 
    Date:   Wed Nov 5 11:28:59 2025 -0300
    
        Bug 41107: (follow-up) Use Koha::Status in Koha::Template::Plugin::Koha
        
        This patch makes the template plugin used for rendering the Koha version
        use the introduced method.
        
        I did this checks:
        
        ```shell
        cd koha-tmpl
        git grep Koha.Version
        ```
        
        The places Koha.Version is used, it is used as:
        
        * `Koha.Version.maintenance`
        * `Koha.Version.release`
        * Assigned to a variable like this `SET koha_version = Koha.Version`
        
        All occurences of the `koha_version` template variable are:
        
        * `koha_version.development`
        * `koha_version.major`
        * `koha_version.minor`
        
        This implies the newly added `.version` attribute has no undesired side
        effects in templates.
        
        Note: plugins-home.tt has a different use of a variable named the same,
        which is unrelated.
        
        To test:
        1. Apply this patch
        2. Run:
           $ ktd --shell
          k$ prove t/Koha_Template_Plugin_Koha.t
        => SUCCESS: Tests pass!
        3. Sign off :-D
        
        Signed-off-by: David Nind 
        Signed-off-by: Kyle M Hall 
        Signed-off-by: Martin Renvoize 
    
    commit 68c8b8f13fad886b3d516fbfdc17a3b2198a0bdf
    Author: Tomás Cohen Arazi 
    Date:   Wed Nov 5 10:20:48 2025 -0300
    
        Bug 41107: Add /status/version API endpoint
        
        Adds a new REST API endpoint to retrieve Koha version information.
        
        This implementation includes:
        - Koha::Status class for instance status information
        - /status/version endpoint returning structured version data
        - OpenAPI specification with koha_version definition
        - REST controller for handling the endpoint
        
        The returned version object includes:
        - version: full version string (e.g., '25.06.00.029')
        - major: major version number
        - minor: minor version number
        - release: major.minor version
        - maintenance: major.minor.maintenance version
        - development: development version (if applicable)
        
        This prepares the foundation for a future /status endpoint that will
        include all information displayed in the about page.
        
        To test:
        1. Apply the patch
        2. Run:
           $ ktd --shell
          k$ yarn api:bundle
        3. Run the tests:
          k$ prove t/Koha/Status.t \
                   t/db_dependent/api/v1/status.t
        => SUCCESS: Tests pass!
        4. Sign off :-D
        
        Signed-off-by: David Nind 
        Signed-off-by: Kyle M Hall 
        Signed-off-by: Martin Renvoize 
    
    commit 7929a1198edb30519c5519e1d85400508e18290c
    Author: Martin Renvoize 
    Date:   Mon Mar 23 09:30:12 2026 +0100
    
        Bug 41814: DBRev 25.12.00.032
        
        Signed-off-by: Martin Renvoize 
    
    commit 41e729baba99c23da452cb287f5966f8446093e0
    Author: Martin Renvoize 
    Date:   Mon Mar 23 09:15:11 2026 +0100
    
        Bug 41814: (RM follow-up) Add PatronAgeRestriction to UsageStats
        
        Signed-off-by: Martin Renvoize 
    
    commit 8948d7117ad6fc2fe1532ff722b7734774c04343
    Author: Katrin Fischer 
    Date:   Fri Feb 20 14:59:00 2026 +0000
    
        Bug 41814: (QA follow-up) Add bug number to atomic update and some style fixes
        
        Sponsored-by: Cheshire West and Chester Council
        Signed-off-by: Katrin Fischer 
        Signed-off-by: Martin Renvoize 
    
    commit c1f0d97e8b8318ab479960294db7188ecf931b96
    Author: Jake Deery 
    Date:   Wed Feb 11 09:16:49 2026 +0000
    
        Bug 41814: Add PatronAgeRestriction syspref and code
        
        This patch adds a new PatronAgeRestriction, which acts in the same way
        PatronSelfRegistrationAgeRestriction (a restriction on the maximum age
        of a borrower), except for the intranet. It will also act as the
        maximum age restrictor on the OPAC, in the event that the
        PatronSelfRegistrationAgeRestriction is not set.
        
        To test:
        == APPLY PATCH ==
        a)  updatedatabase
        b)  Set the PatronAgeRestriction syspref to 20, set the
            PatronSelfRegistrationAgeRestriction to 30
        c)  On the OPAC, try to create or modify a patron whose age is 35 years
            *)  Note the error message presented, suggesting the age exceeds the
            maximum
        d)  On the OPAC, try to create or modify a patron whose age is 25 years
            *)  Note the submission succeeds
        e)  On the staff client, try to create or modify a patron whose age is
            25 years *)  Note the error message presented, suggesting the age
            exceeds the maximum
        f)  Set the PatronSelfRegistrationAgeRestriction to empty
        g)  On the OPAC, try to create or modify a patron whose age is 25 years
            *)  Note the error message presented, suggesting the age exceeds
            the maximum
        h)  On the OPAC, try to create or modify a patron whose age is 19 years
            *)  Note the submission succeeds
        i)  Set the PatronAgeRestriction to empty
        j)  On the staff client, try to create or modify a patron whose age is
            75 years
            *)  Note the submission succeeds
        k)  On the OPAC, try to create or modify a patron whose age is 75 years
            *)  Note the submission succeeds
        == SIGN OFF ==
        
        Sponsored-by: Cheshire West and Chester Council
        Signed-off-by: Owen Leonard 
        Signed-off-by: Katrin Fischer 
        Signed-off-by: Martin Renvoize 
    
    commit 23c88ff85b34c2b040e657a075b412a538132dc3
    Author: Martin Renvoize 
    Date:   Mon Mar 23 08:55:57 2026 +0100
    
        Bug 40286: RM follow-up: Add POD coverage for private subs in C4/Auth.pm
        
        Adds POD documentation for _version_check, _timeout_syspref,
        _get_session_params, and _dispatch to fix pod_coverage QA failures.
        
        Signed-off-by: Martin Renvoize 
    
    commit 9f08e3a1c360abba858b801ae758a931e0917079
    Author: Tomás Cohen Arazi 
    Date:   Fri Mar 13 12:39:28 2026 -0300
    
        Bug 40286: (follow-up) Fix password_validation.t for find_by_identifier behavior
        
        The change to use find_by_identifier in checkpw_internal means userid
        is now checked before cardnumber. This updates the test to reflect that
        when an identifier matches both a userid and cardnumber, the userid
        match takes precedence.
        
        To test:
        1. Apply this patch
        2. Run:
           $ ktd --shell
           k$ prove t/db_dependent/api/v1/password_validation.t
        => SUCCESS: Tests pass!
        
        Signed-off-by: Martin Renvoize 
    
    commit bf0ed60e73baf23e3a8824e996054c9970fce605
    Author: Tomás Cohen Arazi 
    Date:   Mon Jul 21 13:52:57 2025 -0300
    
        Bug 40286: Make C4::Auth::checkpw_internal use Koha::Patrons->find_by_identifier
        
        This patch does what the title says. The code change is clear to
        understand.
        
        The check for userid vs. cardnumber is done in the `find_by_identifier`
        method so no need to do it here.
        
        Note: When `find_by_identifier` was written, I picked some other place's
        logic (API password validation) so `userid` is used first for finding
        the patron. Because of this, tests in t/db_dependent/Auth.t need to be
        adjusted. I believe this is not an issue, as those tests should be
        removed once we move forward with bug 33905, entirely.
        
        To test:
        1. Apply this patch
        2. Run:
           $ ktd --shell
          k$ prove t/db_dependent/Auth.t
        => SUCCESS: Tests pass!
        3. Sign off :-D
        
        Signed-off-by: Tomas Cohen Arazi 
        Signed-off-by: David Nind 
        Signed-off-by: Martin Renvoize 
    
    commit 91f3e51e1a9d50a82fa78e470547a9003167710e
    Author: Martin Renvoize 
    Date:   Mon Mar 23 07:53:40 2026 +0100
    
        Bug 40962: Apply ViewPolicy filter consistently in OAI Server test setup
        
        The test built @marcxml and @oaidc expected data using metadata_record()
        with no parameters, while the OAI server's get_biblio_marcxml() always
        calls metadata_record({ interface => 'opac' }), which applies the
        ViewPolicy filter. On nodes where the MARC framework has non-default
        hidden values (or a stale cache entry), ViewPolicy strips fields like 245,
        causing the expected and actual responses to diverge.
        
        Fix by using interface => 'opac' when building the expected data, and
        deriving dc:title from the filtered MARC record rather than hardcoding it,
        so both sides of every comparison go through the same code path.
        
        Signed-off-by: Martin Renvoize 
    
    commit cde9628b86951209f7c9099ef4907abf29753b82
    Author: Martin Renvoize 
    Date:   Mon Mar 23 00:21:39 2026 +0100
    
        Bug 40962: Fix race condition in OAI Server test for OpacHiddenItems
        
        The 'Tests for OpacHiddenItems' subtest captured Perl's wall clock time
        *after* calling build_sample_item(), then used that timestamp as both the
        expected OAI datestamp and the 'from' filter. On slow systems the INSERT
        can straddle a second boundary, so MySQL records T:40 while dt_from_string
        returns T:41, causing noRecordsMatch on the ListRecords tests and a
        datestamp mismatch on the GetRecord tests.
        
        Fix by calling $item->discard_changes and deriving $utc_timestamp from the
        timestamp MySQL actually assigned, matching the pattern already used in the
        Bug 19725 subtest in the same file.
        
        Signed-off-by: Martin Renvoize 
    
    commit ad1caed65c83e1d3355d235500f5e44222c3b03b
    Author: Martin Renvoize 
    Date:   Sun Mar 22 23:59:03 2026 +0100
    
        Bug 23415: DBRev 25.12.00.031
        
        Signed-off-by: Martin Renvoize 
    
    commit 38f298962719a607b4418913360ad8ff048f3633
    Author: Martin Renvoize 
    Date:   Sun Mar 22 23:51:20 2026 +0100
    
        Bug 23415: (RM follow-up) Add new sysprefs to HEA data sharing
        
        Add FineNoRenewals, FineNoRenewalsBlockAutoRenew,
        FineNoRenewalsBlockSelfCheckRenew, and FineNoRenewalsIncludeCredits
        to the list of system preferences shared with the Hea (Koha Usage
        Stats) service.
    
    commit 7367ac3273fca6111a61545fa7dbf435201cbc20
    Author: Martin Renvoize 
    Date:   Sun Mar 22 23:32:21 2026 +0100
    
        Bug 23415: (RM follow-up) Add POD coverage for private subs in C4/Circulation.pm
        
        Adds POD for _check_max_qty, _calculate_new_debar_dt,
        _CalculateAndUpdateFine, and _CanBookBeAutoRenewed to fix QA pod_coverage
        failures.
    
    commit a359ed47b19ec2fad35f6c2da65fa21339286c6d
    Author: Martin Renvoize 
    Date:   Fri Feb 13 15:04:17 2026 +0000
    
        Bug 23415: (follow-up) Fix typo 'oweing' -> 'owing' in templates and notices
        
        This patch corrects a typo in the auto renewal error code and related
        notice templates:
        - Adds database update to fix existing notice templates in letter table
        - Fixes sample notices for new installations
        - Fixes renew_strings.inc template include
        
        The error code changes from 'auto_too_much_oweing' to 'auto_too_much_owing'
        throughout.
    
    commit 1eb1cfdbefb22f44631a900029900122430eb1c5
    Author: Martin Renvoize 
    Date:   Thu Nov 20 09:30:15 2025 +0000
    
        Bug 23415: (follow-up) Rename sysprefs and add self-checkout control
        
        This follow-up patch addresses feedback from the QA process:
        
        1. System preference naming consistency
           Renamed the following preferences to remove "OPAC" prefix and align
           with the FineNoRenewals naming convention:
           - OPACFineNoRenewalsIncludeCredits → FineNoRenewalsIncludeCredits
           - OPACFineNoRenewalsBlockAutoRenew → FineNoRenewalsBlockAutoRenew
        
        2. Self-checkout backward compatibility
           Added new system preference FineNoRenewalsBlockSelfCheckRenew to
           control whether fine limits block renewals via web-based self-checkout.
        
           Previously, OPACFineNoRenewals did not block self-checkout renewals.
           With the rename to FineNoRenewals, this behavior changed. The new
           preference defaults to "0" (don't block) to maintain backward
           compatibility, allowing sites to opt-in to blocking self-checkout
           renewals when patrons exceed the fine threshold.
        
        Test plan:
        1. Run prove t/db_dependent/Circulation.t - all tests should pass
        2. Run prove t/db_dependent/api/v1/checkouts.t - all tests should pass
        3. Verify system preferences are correctly renamed in the admin interface
        4. Test self-checkout renewals with FineNoRenewalsBlockSelfCheckRenew
           set to 0 (default) - renewals should work even when fines exceed limit
        5. Test self-checkout renewals with FineNoRenewalsBlockSelfCheckRenew
           set to 1 - renewals should be blocked when fines exceed limit
        
        Sponsored-by: OpenFifth 
        Signed-off-by: Andrew Fuerste Henry 
        Signed-off-by: Martin Renvoize 
    
    commit 06fd7ed7e44c84a1310d6b228604bc7885a2ccac
    Author: Martin Renvoize 
    Date:   Thu Oct 30 22:04:17 2025 +0000
    
        Bug 23415: (follow-up) Respect OPACFineNoRenewalsIncludeCredits preference
        
        This patch fixes a regression introduced in the previous commits where
        we changed FineNoRenewals checking to use non_issues_charges instead
        of balance. While this change was correct for focusing on blocking
        charges, we inadvertently removed the handling of the
        OPACFineNoRenewalsIncludeCredits preference.
        
        The OPACFineNoRenewalsIncludeCredits preference controls whether
        unapplied account credits should be included when calculating if a
        patron exceeds the FineNoRenewals threshold. When this preference is
        enabled, the patron's net balance (debits minus credits) should be
        used instead of just their outstanding debits.
        
        This patch restores the preference handling for both:
        1. Manual renewals in CanBookBeRenewed()
        2. Auto renewals in _CanBookBeAutoRenewed()
        
        When OPACFineNoRenewalsIncludeCredits = 1:
          Use balance (all charges net of credits)
        When OPACFineNoRenewalsIncludeCredits = 0:
          Use non_issues_charges (only blocking charges, no credits)
        
        This ensures that patrons with sufficient credits can renew their
        items when the preference is enabled, while still maintaining the
        focus on non-issuing charges introduced in the previous commits.
        
        Test plan:
        1. Run prove t/db_dependent/Circulation.t
        2. All tests should pass, particularly the
           "auto_too_much_owing | OPACFineNoRenewalsBlockAutoRenew &
           OPACFineNoRenewalsIncludeCredits" subtest
        
        Sponsored-by: OpenFifth 
        Signed-off-by: Andrew Fuerste Henry 
        Signed-off-by: Martin Renvoize 
    
    commit 8b35dfcc9dafb99f689cd142bcb774fe6981f40e
    Author: Martin Renvoize 
    Date:   Thu Oct 30 14:56:34 2025 +0000
    
        Bug 23415: Add debt override support to circulation checkout page
        
        This patch implements fine override functionality for the checkouts
        table on the circulation page (circ/circulation.pl), completing the
        debt override feature for all renewal workflows.
        
        Changes:
        - Added override_debt checkbox to checkouts-table.inc when
          AllowFineOverrideRenewing preference is enabled
        - Updated /svc/renew to accept and process override_debt parameter,
          matching the pattern used for override_limit
        - Enhanced circulation-api-client.js to pass override_debt parameter
          through the renewal API call
        - Implemented specific CSS classes for renewal error types
          (renewals-allowed-too_many, renewals-allowed-too_much_owing, etc.)
          to enable selective checkbox control
        - Modified override checkbox handlers to selectively enable only
          relevant renewal checkboxes based on the specific blocking error:
          * override_limit enables checkboxes for 'too_many' and 'on_reserve'
          * override_debt enables checkboxes for 'too_much_owing' and
            'auto_too_much_owing'
        - Added AllowFineOverrideRenewing JavaScript variable to circulation.tt
        
        This provides clear visual feedback to staff about which renewals will
        be affected by each override option, improving usability and reducing
        confusion when multiple items have different blocking reasons.
        
        Sponsored-by: OpenFifth 
        Signed-off-by: Andrew Fuerste Henry 
        Signed-off-by: Martin Renvoize 
    
    commit 4b88b1de3ddd4de1647ab8f0b3266f6949dbaf57
    Author: Martin Renvoize 
    Date:   Thu Oct 30 13:34:08 2025 +0000
    
        Bug 23415: Fix FineNoRenewals to use non_issues_charges and improve template
        
        This commit addresses two issues:
        
        1. Fixes FineNoRenewals logic to properly use non_issues_charges
           Both CanBookBeRenewed() and _CanBookBeAutoRenewed() were incorrectly
           using the patron's total balance when checking against FineNoRenewals.
           They now use non_issues_charges, which returns only charges that
           should restrict checkouts (e.g., overdues, lost items) as defined by
           debit types with restricts_checkouts=1. This ensures charges like
           rental fees don't inappropriately block renewals.
        2. Improves renewal template for AllowFineOverrideRenewing
           - Adds special handling for auto_too_much_owing error to check
             AllowFineOverrideRenewing preference instead of
             AllowRenewalLimitOverride
           - Adds missing id="barcode" attribute to input field for Cypress tests
           - Adds .dialog CSS class to error/success divs for consistent styling
           - Fixes HTML structure with proper 
    • wrapping - Adds btn btn-default classes to override button 3. Fixes Cypress test issues - Corrects data structure access: items[0] instead of item - Uses external_id instead of barcode (API field name) - Improves form submission selector specificity - Uses REPLACE INTO for system preference setup Test plan: 1. Run t/cypress/integration/Circulation/FineNoRenewals_spec.ts 2. Verify 4 out of 5 tests pass (one remaining template comparison issue) 3. Manually test that patrons with non-issue charges (rental fees) can renew when those charges alone don't exceed FineNoRenewals 4. Verify that patrons with issue-blocking charges (overdues) are properly blocked from renewal when exceeding FineNoRenewals Sponsored-by: OpenFifth Signed-off-by: Andrew Fuerste Henry Signed-off-by: Martin Renvoize commit 018e65c8115c22cfffc5b1f511bc5e2b22433f95 Author: Martin Renvoize Date: Thu Oct 23 12:12:10 2025 +0100 Bug 23415: Add REST API support for fine override on renewal This commit adds support for the AllowFineOverrideRenewing functionality to the REST API renewal endpoints using the standard x-koha-override pattern. Changes: 1. Added x-koha-override header parameter to both renewal endpoints: - POST /checkouts/{checkout_id}/renewal - POST /checkouts/{checkout_id}/renewals 2. Updated Koha::REST::V1::Checkouts::renew() to: - Check for 'debt_limit' in the overrides stash - Check AllowFineOverrideRenewing preference when override is requested - Allow renewal override only when both: * x-koha-override header contains 'debt_limit' AND * AllowFineOverrideRenewing preference is enabled - Follows the established x-koha-override pattern used by other endpoints 3. Updated OpenAPI specification (swagger) to document the new header using the standard pattern with enum values Usage: curl -X POST /api/v1/checkouts/123/renewal \ -H "x-koha-override: debt_limit" The override only works for too_much_owing errors and requires the AllowFineOverrideRenewing system preference to be enabled. This implementation follows the same pattern as holds and other endpoints that support overrides, maintaining consistency across the REST API. Sponsored-by: OpenFifth Signed-off-by: Andrew Fuerste Henry Signed-off-by: Martin Renvoize commit dcc946473ba8e4a8a6684856a10d0a47f6d7c188 Author: Martin Renvoize Date: Thu Oct 23 12:23:31 2025 +0100 Bug 23415: Add API tests for fine override on renewal This commit adds REST API tests to verify the x-koha-override: debt_limit functionality for renewals. Tests cover: - Renewal blocked due to excessive fines - Override fails when AllowFineOverrideRenewing is disabled - Override succeeds when AllowFineOverrideRenewing is enabled - Both /renewal and /renewals endpoints Test plan: 1. Run: prove t/db_dependent/api/v1/checkouts.t 2. All 110 tests should pass Sponsored-by: OpenFifth Signed-off-by: Andrew Fuerste Henry Signed-off-by: Martin Renvoize commit caa3922d270b25aba9214531684e8c72a506f1d2 Author: Martin Renvoize Date: Thu Oct 23 11:56:27 2025 +0100 Bug 23415: Add Cypress test coverage for FineNoRenewals This commit adds end-to-end tests for the fine-based renewal blocking functionality using Cypress. Test coverage includes: 1. Blocking renewal when patron fines exceed FineNoRenewals limit 2. Displaying override button when AllowFineOverrideRenewing is enabled 3. Hiding override button when AllowFineOverrideRenewing is disabled 4. Successful override when permission is enabled 5. Allowing renewal when fines are below the limit The test creates test data including: - A patron with checkouts - Account fines that exceed the FineNoRenewals threshold - Tests both blocking and override scenarios Tests verify the UI behavior matches the business logic: - Error messages are displayed correctly - Override buttons appear based on preference setting - Override functionality works as expected - Security is maintained (no override without permission) To run these tests: npx cypress run --spec "t/cypress/integration/Circulation/FineNoRenewals_spec.ts" Sponsored-by: OpenFifth Signed-off-by: Andrew Fuerste Henry Signed-off-by: Martin Renvoize commit 58b560d9f90885f9858927438ed880210ea32fb0 Author: Martin Renvoize Date: Thu Oct 23 11:50:27 2025 +0100 Bug 23415: (QA follow-up) Fix spelling: oweing -> owing Standardizes error code spelling across the codebase: - Changes 'too_much_oweing' to 'too_much_owing' - Changes 'auto_too_much_oweing' to 'auto_too_much_owing' The word "owing" is the correct spelling in English. Files updated: - C4/Circulation.pm - C4/SIP/Sip/MsgType.pm - circ/renew.pl - koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt - koha-tmpl/intranet-tmpl/prog/js/checkouts.js - koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-reserve.tt - koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt - misc/cronjobs/automatic_renewals.pl - opac/opac-reserve.pl - opac/opac-user.pl - t/db_dependent/Circulation.t All tests should pass successfully. Sponsored-by: OpenFifth Signed-off-by: Andrew Fuerste Henry Signed-off-by: Martin Renvoize commit 160b1556b6ca67d2219f273098ac50b2307b1519 Author: Martin Renvoize Date: Thu Oct 23 11:44:52 2025 +0100 Bug 23415: (QA follow-up) Fix logic and security issues This commit addresses several issues found in QA review: 1. Fixed logic bug in C4::Circulation::CanBookBeRenewed - Removed incorrect check of AllowFineOverrideRenewing preference - The function now always returns 'too_much_oweing' error when patron balance exceeds FineNoRenewals limit - AllowFineOverrideRenewing should only control UI override capability, not the core renewal check 2. Added permission check in circ/renew.pl - Override is now only allowed when both override_debt parameter is set AND AllowFineOverrideRenewing preference is enabled - Prevents security issue where staff could bypass the preference by crafting POST requests 3. Fixed template to conditionally display override button - Override button in renew.tt now only shows when AllowFineOverrideRenewing is enabled - Prevents confusion when override is not permitted 4. Added test coverage - Tests verify CanBookBeRenewed behavior with AllowFineOverrideRenewing both enabled and disabled - Confirms error is always returned regardless of preference setting 5. Fixed minor issues - Fixed typo: "he patron" -> "the patron" in checkouts.js - Fixed typo: OPACFineNoRenewalsIncludeCredit -> OPACFineNoRenewalsIncludeCredits in test All tests should pass successfully. Sponsored-by: OpenFifth Signed-off-by: Andrew Fuerste Henry Signed-off-by: Martin Renvoize commit e06e59bee4765921c8941ff3673ff675fb64fedb Author: Emmi Takkinen Date: Mon Sep 1 13:22:51 2025 +0300 Bug 23415: Fix QA issues Sponsored-by: OpenFifth Signed-off-by: Andrew Fuerste Henry Signed-off-by: Martin Renvoize