commit 6b3fdfc0394634f5e2466204ffc940d062143417 Author: Pedro Amorim Date: Tue Oct 27 15:02:22 2026 -0100 Bug XXXXX: Set ILL requests to 'Downloaded by patron' on the first download Adds a core 'Downloaded by patron' (DOWNLOADED) ILL status, available to every backend like 'Checked out' and 'Returned to library'. The patron's first download of a document from the OPAC sets the request to it, unless the request is already completed. Staff can then mark it completed. Test plan: 1) Apply patch, restart plack 2) Add a document under 'Documents' on any ILL request at 'http://localhost:8081/cgi-bin/koha/ill/ill-requests.pl' 3) Get its token: SELECT token FROM ill_documents WHERE illrequest_id IS NOT NULL; 4) Logged out, open 'http://localhost:8080/cgi-bin/koha/opac-ill-document.pl?token=' and click 'Download' 5) Confirm the request's status is 'Downloaded by patron' and it offers 'Mark completed' 6) Click 'Mark completed', download again and confirm the status stays 'Completed' 7) Run: prove t/db_dependent/Koha/ILL/Documents.t t/db_dependent/Koha/ILL/Requests.t Co-Authored-By: Claude Opus 5.5 commit 21d98133627af54f451499b891d08c121f2c7755 Author: Pedro Amorim Date: Tue Oct 27 14:10:04 2026 -0100 Bug XXXXX: Purge patron ILL documents in cleanup_database.pl Adds --ill-patron-documents-days DAYS to cleanup_database.pl. It deletes documents delivered to patrons once the patron first downloaded them more than DAYS days ago, or once they were uploaded more than DAYS days ago if the patron never downloaded them (default 30). Documents supplied to other libraries are not affected. To alert staff to documents patrons have not downloaded before they are purged, save a report such as this one, with DAYS below the purge's: SELECT CONCAT('', r.illrequest_id, '') AS 'ILL request', r.status AS 'Status', p.cardnumber AS 'Card number', p.surname AS 'Surname', p.firstname AS 'First name', p.email AS 'Email', d.file_name AS 'Document', d.uploaded_on AS 'Uploaded on', DATEDIFF(NOW(), d.uploaded_on) AS 'Days without download' FROM ill_documents d JOIN illrequests r ON r.illrequest_id = d.illrequest_id LEFT JOIN borrowers p ON p.borrowernumber = r.borrowernumber WHERE d.downloaded_on IS NULL AND d.uploaded_on < NOW() - INTERVAL <> DAY ORDER BY d.uploaded_on Test plan: 1) Apply patch 2) Add a document under 'Documents' on any ILL request at 'http://localhost:8081/cgi-bin/koha/ill/ill-requests.pl' 3) Run: misc/cronjobs/cleanup_database.pl -v --ill-patron-documents-days 4) Confirm 0 patron ILL documents would have been removed 5) Pretend it was uploaded 40 days ago and never downloaded: UPDATE ill_documents SET uploaded_on = NOW() - INTERVAL 40 DAY WHERE illrequest_id IS NOT NULL; 6) Repeat 3) and confirm 1 would have been removed 7) Pretend the patron downloaded it 10 days ago: UPDATE ill_documents SET downloaded_on = NOW() - INTERVAL 10 DAY WHERE illrequest_id IS NOT NULL; 8) Repeat 3) and confirm 0 would have been removed 9) Pretend the patron downloaded it 40 days ago: UPDATE ill_documents SET downloaded_on = NOW() - INTERVAL 40 DAY WHERE illrequest_id IS NOT NULL; 10) Repeat 3) with --confirm and confirm the document is gone from the ILL request's 'Documents' 11) Run: prove t/db_dependent/Koha/ILL/Documents.t Co-Authored-By: Claude Opus 5.5 commit 921ffee7640c3c621ff2ba63eb981507919266da Author: Pedro Amorim Date: Tue Oct 27 13:03:02 2026 -0100 Bug XXXXX: Add a notice to send ILL documents to patrons Adds the ILL_DOCUMENT_READY notice (email and SMS), which links to the OPAC download page of each document attached to the ILL request. It is sent according to the patron's 'Interlibrary loan ready' messaging preference, like ILL_PICKUP_READY, and is offered in 'Send notice to patron' when the request has documents. Test plan: 1) Apply patch, run updatedatabase, restart plack 2) Give a patron an email address and tick 'Email' for 'Interlibrary loan ready' in their messaging preferences 3) Create an ILL request for that patron at 'http://localhost:8081/cgi-bin/koha/ill/ill-requests.pl' 4) Confirm 'Send notice to patron' does not offer 'ILL document ready for download' 5) Add a document under 'Documents' and confirm it is now offered 6) Click it and confirm the notice was queued by email 7) Check the notice links to the document: SELECT content FROM message_queue WHERE letter_code='ILL_DOCUMENT_READY'; 8) Open the link logged out and download the document 9) Run: prove t/db_dependent/Koha/ILL/Requests.t Co-Authored-By: Claude Opus 5.5 commit 8171bae42a43a3814cceb924448c4ebd081dcf84 Author: Pedro Amorim Date: Mon Oct 26 15:45:18 2026 -0100 Bug XXXXX: Add an OPAC page for patrons to download ILL documents Adds opac-ill-document.pl?token=, where patrons download the documents of their ILL requests. Opening the page records nothing; the 'Download' button POSTs, records the download and serves the file, so email link scanners that open links before the patron do not count as a download. The first download date and a download count are stored in the new ill_documents.downloaded_on and download_count columns, and shown to staff in the ILL request's 'Documents' section. Only documents linked to an ILL request are served; documents supplied to other libraries are not. Test plan: 1) Apply patch, run updatedatabase, rebuild the API bundle, restart plack: yarn api:bundle 2) Add a document to an ILL request at 'http://localhost:8081/cgi-bin/koha/ill/ill-requests.pl' 3) Get its token: SELECT token FROM ill_documents WHERE illrequest_id IS NOT NULL; 4) Logged out, open: 'http://localhost:8080/cgi-bin/koha/opac-ill-document.pl?token=' 5) Confirm the page shows the file name and a 'Download' button, and the request's 'Documents' section in the staff interface shows 'Not downloaded yet' and 0 patron downloads 6) Click 'Download' and confirm the file downloads, and the 'Documents' section shows the download date and 1 patron download 7) Open the page with token=nope and confirm 'This document link is not valid, or the document is no longer available.' 8) Run: prove t/db_dependent/Koha/ILL/Documents.t Co-Authored-By: Claude Opus 5.5 commit 3bed3ac9bc2799455f36893279bcd0b20d98362e Author: Pedro Amorim Date: Mon Oct 26 15:15:44 2026 -0100 Bug XXXXX: Allow adding documents to ILL requests from the staff interface Adds a 'Documents' section to the ILL request page, listing the request's documents with a download link and a form to add one. Files over max_allowed_packet are rejected with a warning. Test plan: 1) Apply patch, restart plack 2) Create an ILL request with any backend and open it at 'http://localhost:8081/cgi-bin/koha/ill/ill-requests.pl' 3) Confirm a 'Documents' section shows 'There are no documents for this request.' 4) Pick a PDF under 'Document' and click 'Add document' 5) Confirm the document is listed with its upload date, and clicking its name downloads the file 6) Add a file larger than max_allowed_packet (16MB on KTD) and confirm 'The document was not added because it is too large.' shows Co-Authored-By: Claude Opus 5.5 commit 3bc436660410dab4fd179f453152c763a453b124 Author: Pedro Amorim Date: Mon Oct 26 15:14:34 2026 -0100 Bug XXXXX: Add documents to ILL requests Adds Koha::ILL::Request->documents and ->add_document, storing documents in ill_documents against the ILL request. Any backend can use them to hold documents to deliver to the patron. Test plan: 1) Apply patch 2) Run: prove t/db_dependent/Koha/ILL/Requests.t Co-Authored-By: Claude Opus 5.5 commit ac62f0e11656c64cf3fce09548658470b9a18db5 Author: Pedro Amorim Date: Mon Oct 26 14:36:05 2026 -0100 Bug XXXXX: Purge supplied ILL documents in cleanup_database.pl Adds --ill-supplied-documents-days DAYS to cleanup_database.pl. It deletes the documents of CopyCompleted supply requests whose receipt was confirmed by the requesting agency more than DAYS days ago (default 30). The requests themselves are kept. Test plan: 1) Apply patch 2) Complete a Copy request with a document at 'http://localhost:8081/cgi-bin/koha/ill/iso18626_requests' and send a 'Received' requestingAgencyMessage for it 3) Backdate the receipt: UPDATE iso18626_requests SET received_on = NOW() - INTERVAL 40 DAY WHERE received_on IS NOT NULL; 4) Run: misc/cronjobs/cleanup_database.pl -v --ill-supplied-documents-days 5) Confirm it reports 1 document would have been removed 6) Run it again with --confirm and confirm the document is gone and the request is still there: SELECT COUNT(*) FROM ill_documents; 7) Run: prove t/db_dependent/Koha/ILL/Documents.t Co-Authored-By: Claude Opus 5.5 commit c6f32db95281eb95092091d54ceb23aa1322ffd2 Author: Pedro Amorim Date: Mon Oct 26 14:34:37 2026 -0100 Bug XXXXX: Record when the requesting agency confirms receipt A CopyCompleted request now accepts a Received action from the requesting agency, and the first Received records the date in the new iso18626_requests.received_on column. Other actions are still rejected on CopyCompleted. received_on is exposed through the API. Test plan: 1) Apply patch, run updatedatabase, rebuild the API bundle: yarn api:bundle 2) Confirm 'iso18626_requests' has a 'received_on' column 3) Complete a Copy request at 'http://localhost:8081/cgi-bin/koha/ill/iso18626_requests' 4) POST a requestingAgencyMessage with action 'Received' for that request to 'http://localhost:8081/api/v1/public/ill/iso18626' 5) Confirm the response messageStatus is 'OK' and received_on is set: SELECT status, received_on FROM iso18626_requests; 6) Run: prove t/db_dependent/api/v1/iso18626/request.t Co-Authored-By: Claude Opus 5.5 commit 871cb122009c7a81b01dc12a40776d6eac867725 Author: Pedro Amorim Date: Mon Oct 26 14:05:18 2026 -0100 Bug XXXXX: Send the document download URL on CopyCompleted When a CopyCompleted message is sent for a request with a document, deliveryInfo now carries the public download URL of the newest document, deliveryMethod 'URL' and the upload date as dateSent. The URL is built from OPACBaseURL. The document is now stored before the message is built, and removed again if the message fails schema validation. Test plan: 1) Apply patch 2) Set 'OPACBaseURL' to 'http://localhost:8080' 3) Complete a Copy request with a document at 'http://localhost:8081/cgi-bin/koha/ill/iso18626_requests' 4) Confirm the outgoing CopyCompleted message under 'Messages' has a deliveryInfo with deliveryMethod 'URL' and a URL like: 'http://localhost:8080/api/v1/public/ill/iso18626/documents//file/content' 5) Enable 'RESTPublicAPI' and 'RESTPublicAnonymousRequests', open that URL logged out and confirm the file downloads 6) Run: prove t/db_dependent/Koha/ILL/ISO18626/Request.t Co-Authored-By: Claude Opus 5.5 commit 978bfca55139b057aec382b4280f90d450d386a7 Author: Pedro Amorim Date: Mon Oct 26 13:52:36 2026 -0100 Bug XXXXX: Add a public endpoint to download ILL documents Adds GET /public/ill/iso18626/documents/{token}/file/content, which serves a document by its download token without authentication. It is subject to the same ILLModule and RESTPublicAPI/ RESTPublicAnonymousRequests checks as /public/ill/iso18626. Only documents supplied to other libraries are served. Test plan: 1) Apply patch, rebuild the API bundle: yarn api:bundle 2) Enable 'RESTPublicAPI' and 'RESTPublicAnonymousRequests' 3) Complete a Copy request with a document at 'http://localhost:8081/cgi-bin/koha/ill/iso18626_requests' 4) Get the document token: SELECT token FROM ill_documents; 5) Open, logged out: 'http://localhost:8081/api/v1/public/ill/iso18626/documents//file/content' 6) Confirm the file downloads 7) Run: prove t/db_dependent/api/v1/iso18626/request.t Co-Authored-By: Claude Opus 5.5 commit c3a58b8fde6b3214609b6dfec3e7d0ee476c86e1 Author: Pedro Amorim Date: Mon Oct 26 12:57:42 2026 -0100 Bug XXXXX: Allow viewing documents on ISO18626 supply requests Adds a 'Documents' row to supply requests that have documents, with a download link served by a new /ill/iso18626_requests/{id}/documents/{document_id}/file/content endpoint. Documents can also be embedded on the request with 'x-koha-embed: documents'. Test plan: 1) Apply patch, rebuild the API bundle and JS: yarn api:bundle && yarn js:build 2) Complete a Copy request with a document at 'http://localhost:8081/cgi-bin/koha/ill/iso18626_requests' 3) Confirm a 'Documents' row shows under 'Request details' and the file name downloads the uploaded file 4) Run: prove t/db_dependent/api/v1/iso18626/request.t Co-Authored-By: Claude Opus 5.5 commit a2b62c9f4ae7a8304281808c3cffdc4e0879ab53 Author: Pedro Amorim Date: Mon Oct 26 12:57:34 2026 -0100 Bug XXXXX: Preparation: Add a documentUrl prop to DocumentDisplay Lets other modules reuse DocumentDisplay with their own download URL. The component no longer assumes the ERM documents URL: documentUrl is required, and the ERM agreement and license views pass it. Test plan: 1) Apply patch, run yarn js:build 2) Open an ERM agreement and a license with a document at 'http://localhost:8081/cgi-bin/koha/erm/agreements' 3) Confirm the document links still download the file Co-Authored-By: Claude Opus 5.5 commit 8fb1d3fc7b0b0148c1a77af251f83ff15afd51b0 Author: Pedro Amorim Date: Mon Oct 26 12:27:06 2026 -0100 Bug XXXXX: Allow uploading a document when completing a copy supply request Adds an optional 'Document' input to the 'Copy completed' dialog. The file is sent with the status update and stored before the CopyCompleted message goes out. Files over max_allowed_packet get a 413. A document sent with any other status, or without both file_name and file_content, gets a 400. Test plan: 1) Apply patch, run updatedatabase, rebuild the API bundle and JS: yarn api:bundle && yarn js:build 2) Go to 'http://localhost:8081/cgi-bin/koha/ill/iso18626_requests' and open a Copy request 3) Click 'Copy completed', pick a PDF in 'Document' and click 'Confirm' 4) Confirm the document was stored: SELECT iso18626_request_id, file_name, file_type, LENGTH(file_content) FROM ill_documents; 5) Run: prove t/db_dependent/Koha/ILL/ISO18626/Request.t t/db_dependent/api/v1/iso18626/request.t Co-Authored-By: Claude Opus 5.5 commit f7aae2efc30d77299633e274e297b9cd67be3d6d Author: Pedro Amorim Date: Mon Oct 26 11:33:00 2026 -0100 Bug XXXXX: [DO NOT PUSH] DBIC Co-Authored-By: Claude Opus 5.5 commit 39f86c72bd3d9169dac43ef17357ce614d476fe7 Author: Pedro Amorim Date: Mon Oct 26 11:32:45 2026 -0100 Bug XXXXX: Add ill_documents table Stores ILL documents: documents supplied to other libraries, linked to an ISO18626 request, and documents to deliver to patrons, linked to an ILL request. Each document gets a unique download token on creation. Documents are deleted with their request, and neither file_content nor token is exposed through to_api. Test plan: 1) Apply patch, run updatedatabase 2) Confirm the 'ill_documents' table exists, with nullable 'iso18626_request_id' and 'illrequest_id' columns and a unique 'token' column 3) Run: prove t/db_dependent/Koha/ILL/ISO18626/Request.t Co-Authored-By: Claude Opus 5.5 commit 54c43778ed9d2b4a4e4e2fa93ec62ba1c9069e84 Author: Tomás Cohen Arazi Date: Mon Aug 17 09:18:56 2026 -0300 Bug 43312: Add CSRF header to opac-user.tt article request cancellation The OPAC does not have the api-client.js infrastructure yet. As a minimal fix, this adds the CSRF-TOKEN header manually to the jQuery.ajax DELETE call for cancelling article requests. The token is read from the csrf-token meta tag which is already present in the OPAC head. Test plan: 1. Apply patch 2. Log into the OPAC as a patron with an article request 3. Go to Your account > click cancel on an article request => SUCCESS: Request cancelled without 403 error 4. Sign off :-D Signed-off-by: Owen Leonard Signed-off-by: Laura_Escamilla Signed-off-by: Pedro Amorim commit 8a8cbc2a62a20a11e80fd7f2aa9b30d942c853c8 Author: Tomás Cohen Arazi Date: Mon Aug 17 09:17:44 2026 -0300 Bug 43311: Add CSRF header to opac-memberentry.tt API call The OPAC does not have the api-client.js infrastructure yet. As a minimal fix, this adds the CSRF-TOKEN header manually to the jQuery.ajax PUT call for updating guarantor checkout visibility. The token is read from the csrf-token meta tag which is already present in the OPAC head. Test plan: 1. Apply patch 2. Log into the OPAC as a patron with a guarantor 3. Go to Your account > Personal details 4. Change the "Allow guarantor to see checkouts" setting => SUCCESS: Setting updated without 403 error 5. Sign off :-D Signed-off-by: Owen Leonard Signed-off-by: Laura_Escamilla Signed-off-by: Pedro Amorim commit 9e050fbfd6e167039548a1e7b0120490f19c6a6f Author: Tomás Cohen Arazi Date: Fri Aug 14 15:46:42 2026 -0300 Bug 43307: Migrate cataloguing/moveitem.tt to use api-client.js This patch replaces the raw jQuery.ajax() DELETE call for deleting a biblio record with the api-client.js pattern. Changes: - Add biblios.delete method to BiblioAPIClient - Register BiblioAPIClient in the main api-client.js - Replace $.ajax DELETE in moveitem.tt with APIClient.biblio call Test plan: 1. Apply patch 2. Go to Cataloging > Move items 3. Move items from one record to another until source is empty 4. Click "Delete this record" => SUCCESS: Record deleted, success message shown 5. Sign off :-D Signed-off-by: Owen Leonard Signed-off-by: Jonathan Druart Signed-off-by: Pedro Amorim commit e251be1a8f0df09273b429a3d0aea1e16ba22262 Author: Pedro Amorim Date: Fri Oct 23 15:31:06 2026 +0000 Bug 42621: DBRev 26.06.00.039 Signed-off-by: Pedro Amorim commit 5e8e7fc12ff3805913bcbafd3a43c12d8a54ae32 Author: Matt Blenkinsop Date: Fri Oct 23 14:23:58 2026 +0100 Bug 42621: (QA follow-up) Use the root library group for report limits The saved reports list and direct report access used different rules when a group had sub-groups. The list collected the libraries under the user's immediate parent group. Direct access collected the libraries under the limited library's immediate parent group. With a root group holding Centerville and a sub-group holding Fairfield, a Centerville user saw a Fairfield-limited report but could not run it, and a Fairfield user could run a Centerville-limited report that was not listed. A library group now means the whole tree under the root group that has "Limit report access by group" ticked. This is the rule that local hold groups and local float groups already use (get_hold_libraries and get_float_libraries). library_group_limits returns the root groups and search_with_library_group_limits expands the root with all_libraries, so both sides agree. Libraries outside any such tree are still enforced as a group of one. The Library limits column now shows the root group title. Test plan: 1. Set LimitReportsBy to Library group 2. Create a library group "Reports test", tick "Limit report access by group", add Centerville to it 3. Add a sub-group "Sub" to "Reports test" and add Fairfield to "Sub" 4. Save a report limited to Fairfield and a report limited to Centerville 5. Create a staff user at Centerville and one at Fairfield with only catalogue and execute_reports 6. As the Centerville user: both reports are listed and both run 7. As the Fairfield user: both reports are listed and both run 8. As a user at a library outside the group: neither report is listed and opening either by URL with op=run gives "Access denied" 9. prove t/db_dependent/Koha/Reports.t Co-Authored-By: Claude Fable 5.1 Signed-off-by: Pedro Amorim commit 770b12d31ce8dead6d508d1d4de3dd44c0a53328 Author: Matt Blenkinsop Date: Fri Oct 23 14:23:55 2026 +0100 Bug 42621: (QA follow-up) Add LimitReportsBy to sysprefs.sql and fix the atomic update sysprefs.sql still listed LimitReportsByLibrary, so a fresh install had no LimitReportsBy row. get_saved_reports then compared an undefined preference value and crashed on the saved reports list with "Can't call method unblessed on an undefined value". check_sysprefs.t also failed with "Too many sysprefs in DB: LimitReportsBy". The atomic update also set options and type on the renamed preference. Since bug 41834 these columns must be NULL in the database, the YAML file owns them. The update now only renames the variable and converts the value. The stale preference name is also replaced in Reports/Guided.t. Test plan: 1. grep -n "LimitReportsBy" installer/data/mysql/mandatory/sysprefs.sql shows ('LimitReportsBy','none') 2. In ktd --shell: updatedatabase && restart_all 3. koha-mysql kohadev -e "SELECT variable, value, options, type FROM systempreferences WHERE variable = 'LimitReportsBy'" shows value none and NULL for options and type 4. prove t/db_dependent/check_sysprefs.t 5. Open the saved reports list, it loads without error Co-Authored-By: Claude Fable 5.1 Signed-off-by: Pedro Amorim commit 447b46002aea98030f1ddd5573ea8ae072f3e21f Author: Matt Blenkinsop Date: Fri Oct 9 10:07:57 2026 +0100 Bug 42621: (QA follow-up) Refactor for bug 43591 Assisted-by: Sonnet 5 (Anthropic) Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 5bfec2a55c53a22b296f75028f3ab1c4d71e8103 Author: Matt Blenkinsop Date: Thu Sep 24 11:19:10 2026 +0100 Bug 42621: (QA follow-up) Always render the column to prevent datatables error The library limit column was only rendered if the syspref was switched on but this would cause a databtables column index mismatch and throw an error. This patch always renders the column and handles the column value based on the syspref value rather than just showing/hiding it Assisted-by: Sonnet 5 (Anthropic) Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 7d4df738e24df6cef2e8def124fb3e0e78b83883 Author: Matt Blenkinsop Date: Fri Sep 18 16:56:15 2026 +0100 Bug 42621: (QA follow-up) Add POD to private subs in C4::Reports::Guided The QA script reports missing POD coverage for _get_columns, _build_query and _get_display_value. This is pre-existing but was requested during QA of this bug. Test plan: 1. prove t/db_dependent/Reports/Guided.t 2. Run the QA script, C4/Reports/Guided.pm no longer fails pod_coverage Co-Authored-By: Claude Fable 5.1 Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 7ba5aa2290baa327620d70bbac8719f3627935b9 Author: Matt Blenkinsop Date: Fri Sep 18 16:53:42 2026 +0100 Bug 42621: (QA follow-up) Display and enforce limits to ungrouped libraries When LimitReportsBy is set to library_group and a report is limited to a library that is not in any group with "Limit report access by group" enabled, the limit was enforced in the saved reports list but the "Library limits" column showed "No limitation". Direct access via can_access also ignored the limit entirely, because it only checked qualifying groups. An ungrouped library is now treated as a group of one. Two helpers are added to Koha::Object::Limit::LibraryGroup: - ungrouped_library_limits returns the limited libraries that are not members of any qualifying group - library_group_limit_branchcodes returns every branchcode the limit resolves to (stored branchcodes plus all members of qualifying groups) can_access uses the resolved branchcodes so listing and direct access agree. The saved reports table shows group titles followed by any ungrouped libraries as "Branch name (CODE)". Test plan: 1. Set LimitReportsBy to Library group 2. Create a library group containing Centerville and Fairfield, tick "Limit report access by group" 3. As a superlibrarian at Centerville, create a report limited to Fairview (not in any group) 4. Saved reports list: the report is hidden 5. Set your library to Fairview, reload the saved reports list 6. The report is visible and the Library limits column shows "Fairview (FRV)" instead of "No limitation" 7. Edit the report and add Centerville to the limit. The column shows the group title followed by "Fairview (FRV)" 8. Log in as a non-manager user at Fairfield and open the report from step 3 by URL. Access is denied 9. prove t/db_dependent/Koha/Reports.t Co-Authored-By: Claude Fable 5.1 Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit a078732c70422f061d0cec9d8d2b4d424363b0bc Author: Matt Blenkinsop Date: Wed Jun 10 13:47:26 2026 +0100 Bug 42621: DBIC Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit d0d50e14ebf28e949867255ab7e6caeb0a812893 Author: Matt Blenkinsop Date: Wed Jun 10 13:47:16 2026 +0100 Bug 42621: Add unit test for lib group limits Test plan: Prerequisites 1. Three branches: Centerville, Fairfield, Fairview 2. Admin - Library groups: create root group "Test Group", enable Limit report access by group, add Centerville and Fairfield as child libraries (not Fairview) 3. Create an admin user with manage_report_limits permission (or superlibrarian) at branch Centerville 4. Create regular users with reports + execute_reports only (no manage_report_limits), one at each of Centerville, Fairfield, and Fairview 5. Admin - Administration - Columns settings - Reports - Saved reports (table_reports) - enable the Library limits column (it is hidden by default) Baseline - LimitReportsBy = No restriction 6. Set LimitReportsBy = No restriction 7. Admin user - create Report A - no "Library limitation" field visible, save report with any parameters, content is not important 8. Admin user - Reports list - no "Library limits" column visible even if enabled in column settings. Library mode - regression 9. Set LimitReportsBy = Library 10. Admin user - Reports list - "Library limits" column visible (if enabled in column settings) 11. Log in as the Fairview user - Reports list - "Library limits" column not visible as user doesn’t have manage_reports_limit permission 12. Admin user - edit Report A - Library limitation field should be visible - set limit to Centerville - report saves with Centerville limit 13. Fairview user - Reports list - Report A not visible 14. Regular user at Centerville - Reports list - Report A visible 15. Regular user at Centerville - edit Report A - save - limits preserved (fieldset not shown; backend preserves existing limits silently) 16. Admin user - Report A visible with "1 library limitation" tooltip showing Centerville. Delete Report A Library group mode - setup and limits column 17. Set LimitReportsBy = library_group 18. Admin user - Reports list - "Library limits" column still visible 19. Regular user at Centerville - Reports list - "Library limits" column not visible 20. Admin user - create Report B, set limit to Centerville - "Library limitation" fieldset visible, saves with Centerville as the limit 21. Admin user - Reports list - Report B shows "Test Group" in limits column 22. Admin user - create Report C with no limit - Report C shows "No limitation" in limits column Library group mode - access by group membership 23. Fairfield user - Reports list - Report B visible (Fairfield is in the same group as Centerville). Report C also visible (no limitation) 24. Fairview user - Reports list - Report B not visible (Fairview not in group) 25. Fairview user - navigate directly to Report B URL - access denied 26. Fairview user - Reports list - Report C visible (no limitation) Library group mode - ft_reports flag required 27. Admin - Library groups: disable "Limit report access by group" on "Test Group" 28. Regular user at Fairfield - Reports list - Report B no longer visible as it was limited to Centerville 29. Admin user - Report B limits column - shows "No limitation" 30. Re-enable the flag - Fairfield can see Report B again Library group mode - non-admin save behaviour 31. Regular user at Centerville - create new Report D - save - Report D automatically limited to Centerville (backend sets own branch; no fieldset shown). Verify by viewing the saved reports table as the Admin user - should show Test group as the limitation 32. Regular user at Centerville - edit Report B - save - existing limits preserved unchanged Switching modes 33. With Report B limited to Centerville and LimitReportsBy = library_group - Fairfield can access 34. Switch to LimitReportsBy to Library - Fairfield can no longer access Report B (exact branch match only) 35. Switch back to library_group - Fairfield can access Report B again 36. Switch to none - all reports accessible; no limits column or fieldset anywhere Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit ed83a6ffc062806224349ee63129150874ae2fc9 Author: Matt Blenkinsop Date: Wed Jun 10 13:43:54 2026 +0100 Bug 42621: Update logic involving the old syspref to reflect the new LimitReportsBy Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 9c3c5a0fea123c7898c1cb2640a25586ff0608a8 Author: Matt Blenkinsop Date: Wed Jun 10 13:43:07 2026 +0100 Bug 42621: Update reports search to be able to look up by library group Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit a208eacae5a94736ca8bf2502a20d5783f3c31c1 Author: Matt Blenkinsop Date: Wed Jun 10 13:40:03 2026 +0100 Bug 42621: Add library group limit classes Designed to work as an extra layer on top of library_limits by using the same column but expanding the search to also include any branches in a library group Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit a8e2ffbffeffa22cd4fce5a8bfb165de797c3008 Author: Matt Blenkinsop Date: Wed Jun 10 13:38:33 2026 +0100 Bug 42621: Handle the new ft_reports column in the UI Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit b482621918449c2a1bc088d79c46f7e015eb2e5e Author: Matt Blenkinsop Date: Wed Jun 10 13:37:56 2026 +0100 Bug 42621: Update the LimitReportsByLibrary to LimitReportsBy Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 3e4b103656cf49fc974c005a11c80fc34013d262 Author: Matt Blenkinsop Date: Wed Jun 10 13:34:16 2026 +0100 Bug 42621: Add a ft_reports column to library_groups Signed-off-by: Brendan Lawlor Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 9f2a612d56ae131365767f090a7cda12a84ea60e Author: Lucas Gass Date: Thu Oct 22 16:41:42 2026 +0000 Bug 42627: (follow-up) Add unit tests Signed-off-by: Pedro Amorim commit 46623ca11d33a281d0baf1db138a9e92bb37fa6f Author: Lucas Gass Date: Thu Oct 22 16:40:58 2026 +0000 Bug 42627: (follow-up) Move range logic to its own sub Signed-off-by: Pedro Amorim commit afde4c2f1503ed33ec49bd6f8dbd11e3bcaf37f4 Author: Lucas Gass Date: Tue Jul 7 20:54:27 2026 +0000 Bug 42627: Update labels Signed-off-by: Gretchen Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 1281908d0434eff6c51359024853e54c3c294011 Author: Lucas Gass Date: Tue Jul 7 20:52:37 2026 +0000 Bug 42627: Update scripts to account for count Signed-off-by: Gretchen Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit c94fe5e844dc88e606b3a8246bcff9c797cb6197 Author: Lucas Gass Date: Tue Jul 7 20:52:01 2026 +0000 Bug 42627: Update templates to use count instead of to To test: 1. APPLY PATCH, restart_all 2. Go to Cataloging > Label creator > Print barcode range 3. Notice the labels now read "Starting barcode" and "Number of barcodes to print" 4. Find a barcode in you system. In KTD I do something like 'select barcode from items limit 10;' to find some 5. Enter a barcode and choose 9999 as the "Number of barcodes to print" 6. You should see an error message like "Cannot print more than 1000 barcodes at a time." 7. Choose a more reasonable number like 10 and click 'Print range' 8. On the next page choose a template and a layout and click "Export" 9. On the next page you should see something like "Barcodes from 3999900000001 to 3999900000010". Make sure the range looks correct. 10. Now open the PDF and make sure everything looks correct Signed-off-by: Gretchen Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit fa2a4efb957599ad55a227bf261412aa51d61806 Author: Jacob O'Mara Date: Thu Oct 15 15:06:28 2026 +0100 Bug 43525: (QA follow-up) Show a readable enqueue error Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit 1e638e51931e2780116d732c7c1650d027102a23 Author: Jacob O'Mara Date: Thu Oct 15 15:06:28 2026 +0100 Bug 43525: (QA follow-up) Show why a patron cannot be deleted Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit aa2ecf8c9b64bd254e2a703daed0124e0f4cdf3a Author: Jacob O'Mara Date: Thu Oct 15 15:06:28 2026 +0100 Bug 43525: (QA follow-up) Report patrons that are not found Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit 6153ec8de84fb7bd0f0310beb7f4985150fea41e Author: Jacob O'Mara Date: Thu Oct 15 15:06:28 2026 +0100 Bug 43525: (QA follow-up) Wrap patron deletion in a transaction Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit db312561dd8a22e53c409f903b4120700e423588 Author: Lucas Gass Date: Mon Sep 14 21:23:46 2026 +0000 Bug 43525: Add unit tests prove -v t/db_dependent/Koha/BackgroundJob/BatchDeletePatron.t Signed-off-by: Michelle Spinney Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit f3d1f5e540435a2301180bfcdbd3a4acf4dc2923 Author: Lucas Gass Date: Mon Sep 14 21:16:28 2026 +0000 Bug 43525: Do not enqueue an empty job Noticed while attempting to add tests. Signed-off-by: Michelle Spinney Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit 809c162be428b3eb91cc0d162be7b6859ecaa7b7 Author: Lucas Gass Date: Fri Sep 11 19:57:17 2026 +0000 Bug 43525: Change cleanborrowers to accept a background job Signed-off-by: Michelle Spinney Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit 0d6fcb46168b77fdf82cf5aa52aa9fbff3876d76 Author: Lucas Gass Date: Fri Sep 11 17:28:05 2026 +0000 Bug 43525: Add a BatchDeletePatron background job and register it To test: 0. APPLY PATCH and restart_all 1. Make sure you have some patron ready for deletion. I also check how many borrowers and deletedborrowers I have at this step: select count(*) from borrowers; select count(*) from deletedborrowers; 2. Go to Tools -> Batch patron deletion and anonymization 3. Enter in some params that will return you borrowers. who have not borrowed since, whose expiration date is before, and/or whose patron category is 4. Check 'Verify you want to delete patrons' and run the job 5. On the next step make note of how many borrowers should be deleted 6. Choose 'Permanently delete these patrons'. 7. A background job should be enqueued, when it is finished check borrowers again ( select count(*) from borrowers; ) 8. Also check deletedborrower ( select count(*) from deletedborrowers; ) 9. The borrower who were deleted should be gone for the borrowers table. Deleteborrowers should not have gained any new rows. 10. Now try all the steps again but at step 6 this time choose 'Move these patrons to the trash' 11. This time those borrowers should end up in the deletedborrowers table Signed-off-by: Michelle Spinney Signed-off-by: Jacob O'Mara Signed-off-by: Pedro Amorim commit cc39040876b64ee1ac6157937a1295a421f4ef0e Author: Paul Derscheid Date: Fri Oct 16 12:22:16 2026 +0200 Bug 41514: (QA follow-up) Honour the trail period when extending a booked checkout Koha::Booking->store now enforces lead and trail periods, but Koha::Item->find_booking only checks the lead period at the global level. Renewing a booked checkout, or overriding its due date at checkout, into the next booking's trail window was allowed, and the booking end_date sync then silently failed on the clash. - find_booking with exclude_booking_id also adds the excluded booking's trail period and reads both rules for its pickup library - plain checkout lookups are unchanged Test plan: 1. prove /kohadevbox/koha/t/db_dependent/Circulation.t 2. prove /kohadevbox/koha/t/db_dependent/Koha/Item.t Assisted-by: Opus 5.5 (Anthropic) Signed-off-by: Paul Derscheid Signed-off-by: Pedro Amorim commit e773c3ec16b71c313515562076653f77d3ca1536 Author: Martin Renvoize Date: Thu Sep 3 21:06:50 2026 +0100 Bug 41514: (QA follow-up) Add explicit use Koha::CirculationRules to Koha::Booking _assign_item_for_booking() calls Koha::CirculationRules->get_effective_rules without the module being directly loaded. It currently works only because use Koha::Items transitively loads Koha::Item, which loads Koha::CirculationRules - a fragile, load-order-dependent dependency. Load it explicitly. Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit 215b01c96354ee54217b1609e84628a7398adc0d Author: Martin Renvoize Date: Thu Sep 3 21:06:24 2026 +0100 Bug 41514: (QA follow-up) Use the itemtype_id filter for auto-assignment's lead/trail rule lookup _assign_item_for_booking() always looked up the bookings_lead_period / bookings_trail_period rule using the biblio's default itemtype (biblioitem.itemtype), even when the caller requested an "any item of itemtype X" booking via set_itemtype_filter() (wired up from the REST API's itemtype_id parameter). On a biblio with mixed item-level itemtypes that have different lead/ trail rules, this meant an item could be auto-assigned to a booking that actually violates its own itemtype's configured buffer period, because the exclusion query used the wrong itemtype's rule while the item search correctly used the filter for candidate selection. Use the itemtype filter for the rule lookup when it is set, falling back to the biblio's default itemtype otherwise. Test plan: 1. prove t/db_dependent/Koha/Booking.t Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit 37fa6f5bcb62a0def429e078ce181d6115891e88 Author: Paul Derscheid Date: Thu Sep 3 16:45:50 2026 +0200 Bug 41514: (QA follow-up) Add Koha::Bookings->filter_by_overlapping After the previous follow-up the lead/trail rule lookup and the expanded overlap query existed three times: in Koha::Item::check_booking, Koha::Biblio::check_booking and Koha::Booking::_assign_item_for_booking. - Add Koha::Bookings->filter_by_overlapping, taking the period and the lead/trail days; callers chain it with filter_by_active - Fetch both rules with a single get_effective_rules call at each site - Use the new method at the three call sites Test plan: 1. prove t/db_dependent/Koha/Bookings.t t/db_dependent/Koha/Booking.t t/db_dependent/Koha/Item.t t/db_dependent/Koha/Biblio.t t/db_dependent/api/v1/bookings.t Assisted-by: Fable 5.1 (Anthropic) Signed-off-by: Paul Derscheid Signed-off-by: Pedro Amorim