commit b3d0f59453f924855bf58595c1a80cf53b17a844 Author: nela Date: Sat Sep 26 18:25:30 2026 +0100 Bug 43650: incremental EAN-13 barcodes produce unexpected sequence When incremental EAN-13 barcodes are selected for autoBarcode and new item records are created an unexpected sequence of barcode numbers is produced instead of a sequence where the barcode is incremented by 1 between each item. This patch fixes that by adding quote marks in the inline JS, thus treating the barcode as a string rather than an integer :+) Test plan: 1. have records imported from somewhere but with no items 2. autoBarcode set to incremental EAN-13 barcodes 3. create a number of new items 4. observe that the item barcodes don't follow the expected sequence 5. apply patch 6. delete item records 7. repeat step 3 8. observe that the item barcodes follow the expected sequence commit 17cd7f35170a6d5aa203db0c5814c67d8d6547f9 Author: Martin Renvoize Date: Tue Sep 15 13:50:24 2026 +0100 Bug 31925: Document that thesaurus-aware linking depends on index freshness QA (comment 58/60) suggested LinkerConsiderThesaurus only works with Elasticsearch, having observed duplicate authorities being created when testing with Zebra. Reproduced this directly: with AutoCreateAuthorities and LinkerConsiderThesaurus on, saving two bibs with the same new FAST heading back-to-back (no pause) creates a duplicate authority under Zebra, but waiting for Zebra's indexing daemon to catch up (a few seconds) between saves lets the second heading link to the first-created authority correctly, as designed. The same duplicate-on-rapid-succession behaviour also reproduces with LinkerConsiderThesaurus off and a plain LCSH heading - it's a pre-existing race between AutoCreateAuthorities and Zebra's asynchronous indexing daemon, not something specific to thesaurus-aware matching or this bug. Elasticsearch indexes near-synchronously within the same request, so the same race window is far less likely to be hit there, which is almost certainly why this only showed up in manual Zebra testing. This documents that dependency on the LinkerConsiderThesaurus system preference description, rather than gating the feature to Elasticsearch only, since the underlying logic is search-engine agnostic and works correctly on Zebra given normal indexing latency. Sponsored-by: Heythrop Library Co-Authored-By: Claude Sonnet 5 Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit b0c502407df8332222c83c50791d01f7280baa5b Author: Martin Renvoize Date: Thu Sep 10 09:14:07 2026 +0100 Bug 31925: Only code auto-created authorities with the source thesaurus when LinkerConsiderThesaurus is on Comments 43-51 identified a further problem with unconditionally coding a newly auto-created authority's 008/11 (and 040$f) from the source bib heading's thesaurus: when LinkerConsiderThesaurus is off (the default), the linker matches new headings to existing authorities by text alone, regardless of thesaurus. So a bib heading from one thesaurus (e.g. FAST) can auto-create an authority coded for that thesaurus, and a later bib heading with the *same* text but no thesaurus of its own (or a different one) can then link to that same authority purely on the text match. Saving that authority afterwards propagates its 008/11 and 040$f coding back onto every bib heading linked to it - silently adding indicators and subfields the cataloguer never set, on installs that never opted into thesaurus-aware behaviour. Before this bug, AutoCreateAuthorities always created LCSH-coded records, so that propagation was always onto the coding most sites already expect. This bug's earlier patches changed that default for every site regardless of whether they use LinkerConsiderThesaurus, which is what comments 43/45 (reproduced by Pedro Amorim) demonstrated as disruptive. Sites that haven't turned on LinkerConsiderThesaurus don't benefit from thesaurus-aware authority creation anyway, since their linker never searches by thesaurus - C4::Heading::_search and C4::Linker::Default already gate thesaurus-consideration on this same preference for matching. This change gates authority-creation coding on it too, so the behaviour introduced by this bug only applies to installs that already opted into thesaurus-aware linking. Test plan: 1. prove t/db_dependent/Biblio.t Note the new case 7 in the "codes new authorities with the source thesaurus" subtest: with LinkerConsiderThesaurus off, a FAST heading no longer codes the new authority as FAST, it keeps the MARCAuthorityControlField008 syspref default instead. 2. Librarian-facing regression check: with LinkerConsiderThesaurus off (the default), AutoLinkBiblios and AutoCreateAuthorities on, catalogue a 650 with ind2=7 $2=fast and save. The new authority's 008/11 should be whatever MARCAuthorityControlField008 says (LCSH 'a' by default), not 'z'. 3. Confirm the LinkerConsiderThesaurus=on cases from the earlier patches are unaffected: with it on, a FAST heading still codes 008/11='z' with 040$f=fast, and a MeSH heading still codes 008/11='c'. Sponsored-by: Heythrop Library Signed-off-by: Phil Ringnalda Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit c15b42c45797c38ea096e3772c7f5d10f0032da3 Author: Martin Renvoize Date: Tue Sep 1 11:12:57 2026 +0100 Bug 31925: Don't override 008/11 when the heading's thesaurus wasn't identified QA (comments 23-30) flagged a regression in the previous patches: the guard around coding a new authority's 008/11 (and 040$f) from the source heading's thesaurus was `if ( $heading->{thesaurus} )`, but C4::Heading::MARC21::_get_subject_thesaurus() never returns a false value - a heading with a blank/unrecognised indicator 2 (by far the commonest real-world case) comes back as the placeholder string "notdefined", and indicator 2 = 4 comes back as "notspecified". Both are truthy, so the override always fired, unconditionally coding every new authority's 008/11 as 'z' or '|' instead of respecting the site's MARCAuthorityControlField008 default (which defaults to 'a'/LCSH) - a disruptive behaviour change for the majority of headings, not just the non-LCSH ones this bug is meant to fix. Adds Koha::Authority::$MARC21_UNDEFINED_THESAURUS_VALUES, the subset of the existing thesaurus table's keys ('notdefined', 'notspecified') that mean "no thesaurus could be identified" rather than a genuine one, and uses it in LinkBibHeadingsToAuthorities()'s guard so those two values now fall through to the site's own syspref default, unchanged, exactly as before this bug's patches. Test plan: 1. prove t/db_dependent/Biblio.t Note the two new cases in the "codes new authorities with the source thesaurus" subtest: a blank-indicator-2 heading now keeps 008/11 at the syspref default ('a') instead of being forced to 'z', and an indicator-2=4 heading respects a customised syspref default instead of being forced to '|'. 2. Librarian-facing regression check: with AutoLinkBiblios and AutoCreateAuthorities on, catalogue a 650 with a blank/space indicator 2 (e.g. `650 __ $a Some topic`, no $2) and save. The new authority's 008 position 11 should read whatever MARCAuthorityControlField008 says (LCSH 'a' by default), not 'z'. 3. Confirm the non-LCSH cases from the earlier patches are unaffected: a FAST heading (ind2=7, $2=fast) still codes 008/11='z' with 040$f=fast, and a MeSH heading (ind2=2) still codes 008/11='c'. Sponsored-by: Heythrop Library Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit 65dac0fb945bdd295527b097f44e5153b9d2bac1 Author: Martin Renvoize Date: Fri Jul 10 12:12:22 2026 +0100 Bug 31925: AutoCreateAuthorities must preserve subject heading thesaurus When AutoCreateAuthorities creates a new authority for a bib subject heading that didn't match an existing one, it never set 008 or 040 on the new MARC::Record, so C4::AuthoritiesMarc::AddAuthority()'s own defaulting always ran and hardcoded 008/11 to 'a' (LCSH), regardless of the source heading's real thesaurus. A FAST, MeSH, or other non-LCSH heading (MARC indicator 2 = 7 with subfield $2, or indicator 2 = 1-6) therefore always got mis-coded as LCSH on creation. Because the authority was permanently mis-coded, it could never be found again by thesaurus-aware matching (LinkerConsiderThesaurus), so every later import of the same non-LCSH heading created yet another duplicate authority instead of linking to the one already created (see bug 42694 for a real-world report of this). This calls Koha::Authority->default_marc21_008($thesaurus) to build the new authority's 008 - correctly coding position 11 for the source heading's actual thesaurus - and, for headings identified only by a raw $2 code, adds a 040$f before calling AddAuthority(), whose existing "only default if the field isn't already there" guards then leave our correctly-coded fields alone. No change to AddAuthority() itself is needed for this. This is MARC21-only (matches the existing marcflavour branch already in this code path) and ships as an unconditional bug fix, with no new system preference: it only changes how a *new* authority is coded going forward and does not touch or merge any existing authority records. Test plan (librarian-facing): 1. Turn on the AutoLinkBiblios and AutoCreateAuthorities system preferences (Administration -> System preferences -> Cataloging). 2. Catalog a new bibliographic record, or edit an existing one, and add a 650 field coded for a non-LCSH thesaurus, e.g.: 650 _7 $a Miracles $2 fast (2nd indicator = 7, subfield $2 = fast; a FAST heading with no existing matching authority in your catalogue). 3. Save the record. Koha auto-creates a new "Miracles" authority record, since none existed yet to link to. 4. In the Authorities module, open the newly created "Miracles" record for editing and switch to MARC view (Edit -> Edit record, or the "..." menu -> Edit as new). 5. Click into the 008 field to open its editor plugin. Before this fix: the "11- Subject heading system/thesaurus" dropdown is set to "a- Library of Congress Subject Headings", and field 040 has no $f subfield. After this fix: that dropdown is now set to "z- Other", and field 040 has a $f subfield containing "fast" — correctly recording the real source vocabulary instead of silently mis-labelling it as LCSH. 6. As a regression check, repeat steps 2-5 with a plain LCSH heading instead, e.g.: 650 __0 $a Feminism (2nd indicator = 0, no $2). Confirm the resulting authority's 008 still shows "a- Library of Congress Subject Headings" as before — this fix must not change behaviour for ordinary LCSH headings. 7. Optional, Elasticsearch installations only: with LinkerConsiderThesaurus also turned on, re-import or re-save a bib with the same FAST heading from step 2 a second time. It should now link to the authority created in step 3 instead of creating a second duplicate — this is the actual duplicate-authority problem reported in bug 42694. Sponsored-by: Heythrop Library Signed-off-by: Clemens Gresser Signed-off-by: Phil Ringnalda Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit 9186341dddd4577bfac970cfbd119e599d4e5be2 Author: Martin Renvoize Date: Fri Jul 10 12:11:55 2026 +0100 Bug 31925: Make QueryBuilder reuse the shared thesaurus/008 lookup Koha::SearchEngine::Elasticsearch::QueryBuilder kept its own copy of the thesaurus-name to 008/11-code table used when building "thesaurus" search queries against authority records. The previous commit moved that same table to Koha::Authority as a shared lookup. This commit deletes QueryBuilder's duplicate and points $thesaurus_to_value at $Koha::Authority::MARC21_THESAURUS_TO_CONTROL_FIELD_008_11 instead, so there is only one place to update if the code list ever changes. Pure refactor: $thesaurus_to_value keeps its existing name and contents, and build_authorities_query_compat() is unchanged, so query behaviour is identical before and after. Sponsored-by: Heythrop Library Signed-off-by: Clemens Gresser Signed-off-by: Phil Ringnalda Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit 4bfb9abc68bef49e6c23c4abdf20f3f0d6cbc5d0 Author: Martin Renvoize Date: Fri Jul 10 12:11:32 2026 +0100 Bug 31925: Add thesaurus/008 lookup and default MARC21 008 builder to Koha::Authority AutoCreateAuthorities builds a brand-new authority record whenever a bib subject heading (6XX) has no match, but always lets the record fall back to C4::AuthoritiesMarc::AddAuthority()'s default 008/040, which hardcodes 008 position 11 ("Subject heading system/thesaurus") to 'a' (LCSH) no matter what thesaurus the source heading actually uses. This is the first step towards fixing that. Adds two things to Koha::Authority: - $MARC21_THESAURUS_TO_CONTROL_FIELD_008_11: a single-source-of-truth lookup mapping a thesaurus name (as already derived by C4::Heading from MARC indicator 2 / subfield $2, e.g. 'lcsh', 'mesh', or a raw $2 code such as 'fast') to its MARC21 authority 008/11 code, per the LOC ad008 code list. This table previously only existed once, for a different purpose, in Koha::SearchEngine::Elasticsearch::QueryBuilder (used for building thesaurus search queries) - it's promoted here so both that and the authority-creation fix that follows can read from one place instead of two copies that can silently drift apart. - default_marc21_008($thesaurus): builds the default 34-character body of a new MARC21 authority's 008 field, honouring the MARCAuthorityControlField008 system preference. When $thesaurus is given, position 11 is set from the table above instead of whatever the default/syspref value carries, falling back to 'z' (Other) for a thesaurus with no dedicated code. AddAuthority() is refactored to build its own (thesaurus-less, LCSH default) 008 via this new method too, replacing its previous inline copy of the same defaulting logic - pure refactor, no behaviour change. Nothing thesaurus-aware calls it yet. Sponsored-by: Heythrop Library Signed-off-by: Clemens Gresser Signed-off-by: Phil Ringnalda Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit 9eaeae69e5c8154617ab0aa4691fc39c275e1559 Author: Tomás Cohen Arazi Date: Wed Aug 19 09:31:38 2026 -0300 Bug 42719: Handle missing CGISESSID in OAuth login (IdP-initiated flow) When a user initiates login from the IdP (e.g. Okta app tile), they hit the OAuth endpoint without an existing session cookie. The code crashed calling ->value on an undefined cookie object. This patch: - Removes the premature 'No user session found' guard that blocked IdP-initiated flows entirely - Creates a session on-the-fly for the initial request when no cookie exists (IdP-initiated flow) - On callback, redirects with wrong_csrf_token error instead of crashing when the cookie is missing CSRF protection is preserved: the state token is bound to the session created in the initial request, and the browser returns the cookie on callback for validation. Signed-off-by: Tomas Cohen Arazi Signed-off-by: David Nind Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit fda43430192ecac09ae5417887c3fe5d124d64b9 Author: Tomás Cohen Arazi Date: Wed Aug 19 09:31:18 2026 -0300 Bug 42719: Add regression tests Add tests for the OAuth/OIDC login endpoint covering: - IdP-initiated flow (no CGISESSID cookie on initial request) - Callback without CGISESSID cookie (session lost) - Normal SP-initiated flow (cookie present) Tests create a real identity provider in the database and assert: - Initial request without cookie redirects to the IdP authorize URL - A CGISESSID cookie is set for the new session - Callback without cookie returns wrong_csrf_token error (not 500) - Normal flow with cookie redirects to IdP as expected Signed-off-by: Tomas Cohen Arazi Signed-off-by: David Nind Signed-off-by: David Cook Signed-off-by: Pedro Amorim commit 2db06f951075556ae3938e0bb388cea30ccedc8d Author: Jonathan Druart Date: Fri Sep 18 09:20:16 2026 +0200 Bug 43561: Redirect to local use sysprefs instead of 'not found' If a user search for a local use syspref, the name will appear in the autocomplete but when choosen "not found" will be return. This patch suggests to redirect to the "local use" syspref view if we found a local use syspref that match the search term. Test plan: - in admin, type "OPACdid" into the system preference search - see "OPACdidyoumean" is offered as a search term - click OPACdidyoumean => Without this patch you get an error that no such syspref exists => With this patch you are redirected to the local use syspref view Signed-off-by: Laura_Escamilla Signed-off-by: John Vinke Signed-off-by: Pedro Amorim commit f8601c1b0f5dfb7ff5e59c588e75550275d6b38d Author: Martin Renvoize Date: Thu Aug 13 13:38:08 2026 +0100 Bug 43288: Fix change amount missing from printed fee receipts pay.tt, paycollect.tt and boraccount.tt all open printfeercpt.pl with a change_given= query parameter after a payment, but printfeercpt.pl only ever reads a 'change' param into its GetPreparedLetter substitute hash - matching the ACCOUNT_CREDIT/CREDIT_* default notice templates, which use [% change | $Price %], not [% change_given | $Price %]. As a result the change amount is silently blank on every printed fee receipt that shows it, regardless of FinePaymentAutoPopup. Rather than touch printfeercpt.pl or the notice content (both already agree on 'change', matching a similar migration Koha did once before in installer/data/mysql/db_revs/220600072.pl going the same direction), fix the three query strings that build the printfeercpt.pl URL to send change= instead of change_given=. The change_given variable name is kept everywhere else (form fields, JS locals, Perl params) since this is purely about the query key at the printfeercpt.pl boundary. Test plan: 1) Set FinePaymentAutoPopup to 'show' 2) Take a payment for a patron via members/pay.pl or members/paycollect.pl that generates change (fine amount not evenly covered by cash tendered) 3) Note the auto-popped-up receipt shows the change amount (before this patch, the Change line was always blank) 4) Repeat via the boraccount.pl > printfeercpt.pl print receipt route Signed-off-by: David Nind Signed-off-by: Paul Derscheid Signed-off-by: Pedro Amorim commit 7bba6e855aab24da9b58bc999f1850fa571af379 Author: Jonathan Druart Date: Fri Jun 19 12:06:46 2026 +0200 Bug 42697: Add Cypress tests Signed-off-by: David Nind Signed-off-by: Lucas Gass Signed-off-by: Pedro Amorim commit ab1a20b3c833b876f4dfa1b001f34598937300b4 Author: Jonathan Druart Date: Fri Jun 19 12:07:28 2026 +0200 Bug 42697: Revert "Bug 39011: Apply the pre-process to column filters" This reverts commit 4fcff9db9eccff65caf5bc53ad3cccb7be070695. Signed-off-by: David Nind Signed-off-by: Lucas Gass Signed-off-by: Pedro Amorim commit c893f47bb3fe53454c2586ff8d22fe0372232693 Author: Lawrence O'Regan-Lloyd Date: Fri Sep 18 14:31:43 2026 -0400 Bug 41445: Fix cleanup after single hold is suspended This fixes information displayed in the holds table for a patron after a single hold is suspended (in the "Check out" and "Details" sections for a patron record in the staff interface). After suspending a hold, no holds are selected in the holds table, the select_hold_all checkbox is unchecked, and the holds select badge counter is 0. Test plan: 0. Apply patch 1. Go to a patron with 2 or more active holds 2. Navigate to Details -> Holds tab 3. Click Suspend on a single hold and confirm 4. Verify the select-all checkbox remains unchecked 5. Verify the selected holds count is set to 0 6. Repeat steps 3-5 from the Check out -> Holds tab Assisted-by: Opus 5 (Anthropic) Sponsored-by: CLAMS Signed-off-by: Lucas Gass Signed-off-by: Pedro Amorim commit 1b408f7bb20c1d6d77f8ef02c3dfe050c96f4697 Author: Nick Clemens Date: Fri Sep 18 12:49:12 2026 +0000 Bug 36549: (QA follow-up) Restore sleep Signed-off-by: Nick Clemens Signed-off-by: Pedro Amorim commit 6b7db3cfb4b24f861435fa9c036df2ba0b5b18e0 Author: Nick Clemens Date: Fri Aug 21 13:38:37 2026 +0000 Bug 36549: Use Parallel::ForkManager in es_indexer_daemon This patch copies the implementation from the general background worked into the es_indexer daemon Note: There is a 'sleep(10)' in the general indexer and I copied it here, but I don't know why we do it? To test: 1 - Apply the patch 2 - sudo koha-es-indexer --restart kohadev 3 - perl misc/maintenance/touch_all_biblios.pl 4 - Wait a bit 5 - Check the background jobs in the admin interface 6 - Confirm the jobs finish and records are searchable 7 - Test with and without rabbitmq enabled: . Stop rabbitmq service: sudo -s service rabbitmq-server stop . Repeat steps 2 to 5 8 - Sign off Signed-off-by: David Nind Signed-off-by: Aleisha Amohia Signed-off-by: Pedro Amorim commit 7a5c6b6066a0e67c817acf5f694fba783b68c203 Author: Lawrence O'Regan-Lloyd Date: Thu Sep 10 19:16:17 2026 +0000 Bug 43513: Add .mailmap entries for Lawrence O'Regan-Lloyd This patch adds two entries mapping both addresses I commit from to a single identity, so the generated files pick up the right name the next time they are regenerated. Test plan: 1. Apply patch 2. Run: git check-mailmap "lawrenceol-clams " => SUCCESS: returns Lawrence O'Regan-Lloyd 3. Run: git check-mailmap "lawrenceol " => SUCCESS: returns Lawrence O'Regan-Lloyd 4. Run: git shortlog -sne | grep -i "regan-lloyd" => SUCCESS: a single entry, not two Assisted-By: Claude Opus 5 (Anthropic) Signed-off-by: David Nind Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit fb98e7c8099ca3ae0ed0641896b47da471718faf Author: Casey Conlin Date: Sat Sep 19 13:00:01 2026 +0000 Bug 43591: Bring back my libraries filter. This is a patch to bring back a small UI component that was dropped on the previously QA’ed and merged work in bug 16631. Before applying patch, confirm the filter option for Show reports is not available on the Saved Reports page 1. Pull the latest from Main 2. Enable LimitReportsByLibrary under Reports in System Prefernces 3. Visit the Save reports page 4. There should be NO Show reports with selectbox in the Filter pane on the left side 5. Implement the patch 6. Reload Save reports page 7. In the Filter pane on the left side, there should be a Show reports select box with options for Show my library reports and Show all reports options Confirm only permissioned users see this option and reports are filtered 8. Create a staff user with the all reports permissions including Manage Report Limits (manage_report_limits). Home library should be Centerville. 9. Create a staff user with all reports permission but NOT Manage Report Limits (manage_report_limits). Home library should be Centerville. 10. Create a report, “No limit” with no limit. 11. Create a report, “Centerville limit” limited to Centerville. 12. Create a report “Fairfield limit” limited to Fairfield. 13. Log in as the permissioned user. 14. Confirm the filter is available and that it filters reports so that only the No limit and Centerville limit reports show when My library reports only is selected. 15.Select All reports and all 3 reports should be in the list along with the Fairfield report . 16. Log in as the unpermissioned user. 17. The filter option for my / all reports should not be in the leftside pane. 18. Only the Centerville limit and No limit reports should be visible Signed-off-by: Anna Stalter Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit b09bc3c9485dfdad03d716ee5ced6f241ae4d330 Author: Owen Leonard Date: Thu Sep 17 09:32:30 2026 -0400 Bug 43519: Direct links to article request form still work when the feature is disabled This patch adds a check for the ArticleRequests system preference in opac-request-article.pl so that the page will return a 404 error if the preference is disabled. To test, apply the patch and restart services. - If necessary, enable the ArticleRequests system preference and configure a circulation rule to allow article requests. - Locate a bibliographic record in the OPAC which will accept an article request. Note the biblionumber of the record you select. - Click "Request article" and complete the process. It should finish successfully. - Disable the ArticleRequests system preference. - Return to the OPAC and navigate directly to the page for requesting an article: http://localhost:8080/cgi-bin/koha/opac-request-article.pl?biblionumber=X ...where X is the biblionumber you noted before. - This should trigger a 404 error. Sponsored-by: Athens County Public Libraries Signed-off-by: Bastien CHAUVET Signed-off-by: Laura_Escamilla Signed-off-by: Pedro Amorim commit 04314c4fbc6f1966e96f150f5733a6577ae6a65e Author: Owen Leonard Date: Mon Sep 14 08:30:46 2026 -0400 Bug 38948: Modal error on some pages: Can't access property "backdrop" This patch adds some checks to cookieconsent.js to avoid errors in the console: If we try to access 'document.getElementById("cookieConsentModal")' when the element doesn't exist there will be an error: 'Uncaught TypeError: can't access property "backdrop", this._config is undefined' The error can be seen in the browser console on the Circulation home page and the Tools home page when the CookieConsent preference is enabled. To test apply the patch and clear your browser cache if necessary. - Enable the CoookieConsent system preference. - Go to the Circulation home page. There should be no error in the console. - Clear your browser's local storage to forget your consent. - Go to the staff client home page. The cookie consent message should appear. Sponsored-by: Athens County Public Libraries Signed-off-by: Laura_Escamilla Signed-off-by: Jonathan Druart Signed-off-by: Pedro Amorim commit 9e0b6c39144992569497df3ae5aba0ef6fe6dfa7 Author: Paul Derscheid Date: Wed Sep 2 10:53:57 2026 -0400 Bug 42013: Fix missing confirmation dialog for "Remove all reserves" - The confirmDelete dialog for removing all reserves from a course was bound as a click handler on the #rm_items form element, which is never directly clicked by the user - The #rm_items_button click handler called .submit() on the form without checking confirmDelete first, bypassing the confirmation - Move the confirmDelete check into the #rm_items_button click handler and remove the dead #rm_items click handler Test plan: - Enable UseCourseReserves system preference (should be enabled in ktd) - Create a course (or use the existing one) and add at least one reserve to it - On the course details page, click "Remove all reserves" - Observe the form submits immediately without confirmation - Apply patch - Repeat the steps above - Verify a confirmation dialog now appears - Click cancel and verify the reserves are not removed - Click "Remove all reserves" again, confirm, and verify the reserves are removed Signed-off-by: Roman Dolny Signed-off-by: Brendan Lawlor Signed-off-by: Pedro Amorim commit cd3574bdda2311d56930d18b238f5793ad759272 Author: Lucas Gass Date: Wed Aug 26 16:41:23 2026 +0000 Bug 43383: Use checkbox status of :checked when doing cartsubmit or listsubmit To test: 1. Do a catalog search that brings up multiple results 2. Check the checkbox of in the left column for the first two results 3. Click on the title of the 3rd result to take you to the details page for that item 4. Use the borwser's back button to return to the search results 5. Notice the first 2 titles are still checked. 6. Now check the 3rd result and click 'Add to list' 7. Only the 3rd title is added, even though all 3 are checked. 8. Try steps 1 - 7 again but with 'Add to cart', same behavior. 9. Try setps 1 - 7 again but with 'Place hold', all 3 items are selected. 10. APPLY PATCH, clear browser cache and run through all the steps again. This time your selction should be rememebered. Bonus points for trying in as many browsers as possible. Signed-off-by: Bastien CHAUVET Signed-off-by: Brendan Lawlor Signed-off-by: Pedro Amorim commit 3b24981b898c6cef9c7f10e67f135dc77a083ac1 Author: Martin Renvoize Date: Thu Sep 17 16:38:22 2026 +0100 Bug 42608: (follow-up) Adapt tests to Bug 42310 calendar schema Bug 42310 landed on main after this patch's tests were written. It renamed Koha::Calendar to Koha::Library::Calendar and normalized the legacy repeatable_holidays/special_holidays tables into library_weekly_closures/library_single_closures (plus repeating closures and exceptions), managed via Koha::Library::Calendar::* DBIC-backed classes. The new subtests added for this bug still referenced the old class name and the dropped DBIC sources (RepeatableHoliday, SpecialHoliday), so t/db_dependent/Calendar.t and t/db_dependent/Hold.t failed after rebasing onto current main. Update both to build closures via Koha::Library::Calendar::WeeklyClosures/SingleClosures and to instantiate Koha::Library::Calendar, matching the convention already used elsewhere in these files since the Bug 42310 follow-up. No production code changes; test-only fix. Signed-off-by: Martin Renvoize Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 58d41bfedf98e4c9423858766aff213e70590ce6 Author: Martin Renvoize Date: Thu May 14 16:29:06 2026 +0100 Bug 42608: Stop hold pickup expiration from week-jumping over closures Koha::Hold::set_waiting calls Koha::Calendar::days_forward to derive the holds-shelf expiration date when ExcludeHolidaysFromMaxPickUpDelay is on. days_forward iterated next_open_days($dt, 1) ReservesMaxPickUpDelay times, and next_open_days consults get_push_amt for every closed day it encounters. Under useDaysMode=Dayweek, get_push_amt returns 7 for any closure that is not a permanently closed weekday -- so an intermediate Bank Holiday Monday inside the pickup window pushed the cursor a whole week forward instead of one day, inflating the expiration by seven days. Dayweek is a loan-due-date concept: it exists to keep a Friday-due loan due on a Friday across closures. A patron does not pick a weekday for a hold-shelf collection; staff set the expiration when they trap the item, and the only thing that should drive it is how many open days the patron should have to come and collect. days_forward is now decoupled from useDaysMode and always counts forward one open day at a time, ignoring closures without consuming them from the count. next_open_days, prev_open_days, get_push_amt and addDays are unchanged -- loan due-date math keeps the existing Dayweek behaviour. Test plan: 1. Inside KTD, run the updated unit tests: prove t/db_dependent/Calendar.t prove t/db_dependent/Hold.t Confirm both pass, including the new Bug 42608 sub-tests. These cover the full matrix of starting weekdays and useDaysMode values; the manual steps below are a single confirmatory pass through the UI. 2. Manual reproduction (UI only -- no database or CLI access needed): - Set sysprefs: useDaysMode=Dayweek, ReservesMaxPickUpDelay=6, ExcludeHolidaysFromMaxPickUpDelay=ON, ExpireReservesOnHolidays=ON. - Administration > Calendar: on a test branch, add one single (one-time) holiday -- not weekly/repeating -- on any weekday within the next 6 days that isn't already closed (e.g. the day after tomorrow, as long as it isn't a Sunday or other closed day). This one-off closure inside the pickup window is what triggers the bug. - Place a hold on an available item, then check the item in at that branch and confirm/trap it. This stamps waitingdate with today's date automatically -- no manual date entry required. - Check the hold's expiration date (Holds awaiting pickup list, or the patron's holds tab): Without the fix: expiration lands a full 7 days later than it should (today + 6 + 7), from the week-jump. With the fix: expiration is today + 6 open days, only skipping the one closed day. 3. Verify the existing Calendar mode behaviour is unchanged: - Switch useDaysMode to Calendar and repeat step 2 -- the same expected expiration date should apply. 4. Verify loan due-date behaviour is unchanged: - With useDaysMode=Dayweek, check out an item whose loan period would place its due date on the same closed day used in step 2. Confirm the due date still rolls forward by a whole week (the original Dayweek intent), proving this patch did not regress addDays/addDuration. Sponsored-by: OpenFifth Signed-off-by: Jackie Usher Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 9c3d3306e3f692b63381306678e602dd795fd988 Author: Owen Leonard Date: Fri Aug 28 13:47:31 2026 -0400 Bug 43237: (follow-up) Adding [% PROCESS 'i18n.inc' %] to two templates which lack it Signed-off-by: Lucas Gass Signed-off-by: Pedro Amorim commit 3d0b88df0032a65e5cf5d006bd4c383823eb3dbc Author: Owen Leonard Date: Fri Aug 14 14:03:44 2026 -0400 Bug 43237: Add 'Expand' column header to all OPAC responsive DataTables This patch updates several templates in the OPAC so that when a responsive DataTable is partially collapsed, the column with the "+" buttons has "Expand" in the column header. To test, apply the patch and test tables on the affected pages, narrowing the page enough to confirm that when the table collapses, the last column has "Expand" in the header.: - Authorities search results - The details of a course reserve (with titles on reserve) - The holdings table on the bibliographic detail page - Search history - Most popular As a logged-in user: - User summary page (all tabs) - Curbside pickups (with at least one curbside pickup scheduled) - Checkout history - Suggestions - Tags In self-checkout: - The checkouts, holds, and charges tabs. Sponsored-by: Athens County Public Libraries Signed-off-by: David Nind Signed-off-by: Lucas Gass Signed-off-by: Pedro Amorim commit d486b1c68b19c37b9af0da16e1087a08a7973d03 Author: Pedro Amorim Date: Mon Sep 21 14:53:32 2026 +0000 Bug 43336: DBRev 26.06.00.028 Signed-off-by: Pedro Amorim commit 6d160313a2e89fe4fd7277e611b7005a13bd1c84 Author: Magnus Enger Date: Tue Sep 8 14:05:52 2026 +0200 Bug 43336: Remove support for LibrisSpellcheck The API that this feature was based on was removed by the Swedish National Library, so we can remove the code and sysprefs from Koha. Before testing: - Run this SQL in the database and verify the syspref is empty: SELECT value FROM systempreferences WHERE variable = 'OPACdidyoumean'; - Go to Administration > Did you mean? and verify there is a box for LibrisSpellcheck - Move the boxes around and click on "Save configuration" - Run the SQL again and verify the contents of the syspref are now something like this: [{ "name": "AuthorityFile"}, { "name": "LibrisSpellcheck"}, { "name": "ExplodedTerms"}] - Go to Administration > System preferences and search for "libris" - Verify the two sysprefs LibrisKey and LibrisURL show up To test: - Apply this patch and make sure the DB update is run. In KTD you can do: $ sudo koha-upgrade-schema kohadev The output from this should be like this: Removed system preference 'LibrisKey' Removed system preference 'LibrisURL' 'LibrisSpellcheck' was removed from the OPACdidyoumean syspref - Run koha-upgrade-schema again. The output should be: 'LibrisKey' syspref already removed 'LibrisURL' syspref already removed 'OPACdidyoumean' syspref does not contain a setting for 'LibrisSpellcheck' - Run the same SQL as before and verify that LibrisSpellcheck is now gone: [{"name":"AuthorityFile"},{"name":"ExplodedTerms"}] - Go to Administration > Did you mean? and verify there is no box for LibrisSpellcheck - Move the boxes around and click on "Save configuration" - Run the SQL again and verify that there is still no mention of LibrisSpellcheck - Go to Administration > System preferences and search for "libris" - Verify the two sysprefs LibrisKey and LibrisURL do NOT show up - Empty the OPACdidyoumean syspref by running this SQL: UPDATE systempreferences SET value = '' WHERE variable = 'OPACdidyoumean'; - Run koha-upgrade-schema again. The output should be: 'LibrisKey' syspref already removed 'LibrisURL' syspref already removed 'OPACdidyoumean' is not set Signed-off-by: David Nind Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 632017e0221b58eb7bee6f258f6bace7f48b9252 Author: Jonathan Druart Date: Tue Sep 15 12:13:19 2026 +0200 Bug 43267: Avoid flashing the wrong number of visible records Wait before DT has finished the init to display the number of visible records, otherwise there is a flash (display the count of the full set, then the number of records displayed (20)); Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 83f17afef6e3a73abc00b871fc0aab935db39d55 Author: Jonathan Druart Date: Tue Sep 15 12:10:39 2026 +0200 Bug 43267: Disable "Batch operations" menu when there's nothing to send So we don't send an empty set to the tool Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 26914173fde9047233fcfc825e37e1a63b59683c Author: Jonathan Druart Date: Tue Sep 15 12:10:25 2026 +0200 Bug 43267: Reports - only send visible records to batch operations from DT view When opening report results in the new DataTables view, batch operations should only send visible records. Same as the normal view. Test plan: 1. Create and run a report that will display more resulsts than fit on one page 2. Click "Open in DataTables". 3. Note "Batch operations with X visible records" shows the default page size (=20), and open the "Batch operations" dropdown to send results to e.g. batch item modification or batch record modification. 4. Confirm only the values on the currently visible page are sent, not the entire set. 5. Change the DataTable's page, or filter/search within it, and repeat => Confirm the count and the sent values update to the number of visible records 6. Confirm the standard (non-DataTables) report view is unaffected. Signed-off-by: Andrew Fuerste Henry Signed-off-by: Pedro Amorim commit 18aa5d1f4c397f5ba790a4082b843351919ceafd Author: Chloe Zermatten Date: Thu Sep 17 09:52:33 2026 +0000 Bug 10190: (QA follow-up): fixes phase six 1. add missing wrapper element 2. amend casing in cypress test 3. change method name so it is codespell-friendly 4. remove deprecated test from TestBuilder.t (used Overduerules which do not exist anymore. rely on 'Tests with composite FK in userpermission' for FK test coverage instead -> no replacement introduced.) 5. 'Bug 10190: Fix patron_categories permission format' changed the permission for GET requests to patron_categories to catalogue = 1, matching the Koha precedent for such endpoints. However, patron_categories still tested the endpoint with the old permission assigned. Amend this to complete the work started in that commit. 6. remove redundant delete statement in permission test: if the test fails, this means the db update has not run, and should. It would be incorrect for the db to still include the permission at the point where the test runs. Test plan: 1. run `npm run js:build` (or watch the js:watch output) 2. run t/cypress/integration/Admin/CirculationTriggers_spec.ts 3. run prove xt/author/codespell.t 4. run prove t/db_dependent/TestBuilder.t 5. run prove t/db_dependent/api/v1/patron_categories.t 6. run prove t/Koha/Auth/Permissions.t All should run with no warnings or errors. Assisted-by: Claude Opus 5 (Anthropic) Sponsored-by: Glasgow Colleges Library Group Signed-off-by: Pedro Amorim commit c96618f064d079e1d5ae3d5a4b284818fe40471e Author: Chloe Zermatten Date: Fri Sep 11 09:35:24 2026 +0000 Bug 10190: (QA follow-up): fixes phase five 1. apply html filter to letters so notice names are escaped (must be done in attribute so the JSON format of the letters can be parsed). 2. fix a correctness issue where the frontend was pinning the logged in library instead of the logged in user's home library, which would have led to 403s (correct) when saving rules. Since the library dropdown is deliberately disabled unless a user has the manage_circ_rules_from_any_libraries permission, the user would then have needed to use 'Set library' to match their home library to fix this. Prevent the issue by setting the library to the user's home library. Also rename the variable to user_library_id. 3. list_rules correctly references /api/v1/circulation_rules/kinds 4. make untranslatable strings translatable 5. swap svg for font-awesome icon. 6. avoid css duplication: - remove dead / unused scoped css (leftover from an early component extraction) - import vue.css and only leave the minimal override required. 7. improve set_rules test coverage: add tests for manage_circ_rules / manage_circ_triggers separation Test plan: 1) Administration > Circulation triggers: notice the 'Letter' dropdowns list circulation notices as "name (code)" and offer 'No letter'. (no regression) 2) Give a staff user 'catalogue' + 'manage_circ_triggers' only, with home library A. Log in as them, 'Set library' to B, and open Administration > Circulation triggers. Notice the view is pinned to A, and that adding and editing a trigger saves without a 403. (behaviour is now correct) 3) GET /api/v1/circulation_rules?rules=nosuchrule - notice the error points at /api/v1/circulation_rules/kinds. (behaviour is now correct) 4) Run 'gulp po:update --lang fr-FR'. Notice 'Add new trigger {triggerNumber}', 'No letter' and 'any' now appear in misc/translator/po/fr-FR-messages-js.po (behaviour is now correct) 5) Edit a trigger. Notice the delay's reset button is an 'x' inside the input, left of the chevrons, and clears the delay; the letter's reset button does the same for the notice. (no regression) 6) Notice no visual regression across the list, add, edit, reset and delete screens - select widths, chevrons and modals unchanged. Also run t/db_dependent/api/v1/circulation_rules.t Assisted-by: Claude Opus 5 (Anthropic) Sponsored-by: Glasgow Colleges Library Group Signed-off-by: Pedro Amorim commit 167622c08d84d794fe7cd3b2103b77dda604f860 Author: Martin Renvoize Date: Thu Sep 17 12:38:07 2026 +0100 Bug 40934: (follow-up) Fix false positive on --code/--exclude-code mutual exclusivity The mutual-exclusivity check ran before the empty-element cleanup added for bug 37075, so a bare -c (no value) left an empty string in @letter_code, which the check saw as truthy and rejected even though -c had effectively not been used. Move the cleanup above the check. Also add the same mutual-exclusivity guard directly in C4::Letters::SendQueuedMessages, since letter_code and exclude_letter_code build the same search key and passing both would otherwise let one silently clobber the other in the hashref passed to ->search - only the CLI script enforced this until now, so any other caller could hit the silent-clobber bug. Adds regression coverage: unit tests for the new exception in SendQueuedMessages, and a script-level test reproducing the RM's reported false positive. Sponsored-by: OpenFifth Signed-off-by: Pedro Amorim commit 2a652a8d124659d2af58a6dfa7fb86ee8dc72f0d Author: Nick Clemens Date: Fri Aug 21 14:22:02 2026 +0000 Bug 40934: (QA follow-up) Don't delete the queue We already delete the queue at the start of all tests and the tests here are checking using ID, there is no reason to delete the queue again Signed-off-by: Nick Clemens Signed-off-by: Pedro Amorim commit e6908ef0a72b0e9075963aacaaccd5ce1caf50b1 Author: Martin Renvoize Date: Tue Jan 20 13:00:28 2026 +0000 Bug 40934: (follow-up) --code and --exclude-code should be mutually exclusive Both options were being accepted but only the last one in the command line was being applied. Now they are mutually exclusive like --category and --skip-category in longoverdue.pl. Signed-off-by: Nick Clemens Signed-off-by: Pedro Amorim commit 3430793f078ff008d0b0918fe3c077923f014fdf Author: Martin Renvoize Date: Wed Jan 7 15:49:32 2026 +0000 Bug 40934: Add --exclude-code option to process_message_queue.pl Some libraries want to send digest messages once per day (e.g., at 20:05) but send all other messages every hour. Currently, this requires listing almost all letter codes (~85) in the hourly cron job, which is error-prone and makes it easy to forget notifications at upgrades. This patch adds a new --exclude-code (-x) option to process_message_queue.pl that allows excluding specific letter codes from processing, making it much easier to configure digest scheduling. Changes: - Added --exclude-code option to process_message_queue.pl (repeatable) - Modified C4::Letters::SendQueuedMessages to handle exclude_letter_code parameter - Supports both scalar and array reference formats Example usage: # Send all messages except digests every hour 00 */1 * * * process_message_queue.pl --exclude-code DUEDGST \ --exclude-code PREDUEDGST --exclude-code HOLDDGST \ --exclude-code AUTO_RENEWALS_DGST # Send all messages including digests once per day 05 20 * * * process_message_queue.pl Test plan: 1. Apply both patches 2. Run: ktd --shell --run 'prove t/db_dependent/Letters.t' 3. Verify all tests pass (should show 105 tests passing) 4. Create test messages in message_queue with different letter codes: - Insert messages with codes: DUEDGST, PREDUEDGST, ACQ_NOTIF, HOLD 5. Test single exclusion: misc/cronjobs/process_message_queue.pl --exclude-code DUEDGST - Verify DUEDGST messages remain pending - Verify other messages are processed 6. Test multiple exclusions: misc/cronjobs/process_message_queue.pl --exclude-code DUEDGST \ --exclude-code PREDUEDGST - Verify both digest messages remain pending - Verify non-digest messages are processed 7. Test combined with --code option (should work together): misc/cronjobs/process_message_queue.pl --code ACQ_NOTIF \ --exclude-code DUEDGST - Verify only ACQ_NOTIF messages processed (DUEDGST excluded anyway) 8. Test help output: misc/cronjobs/process_message_queue.pl --help - Verify --exclude-code option is documented Sponsored-by: OpenFifth Signed-off-by: Marion Durand Signed-off-by: Nick Clemens Signed-off-by: Pedro Amorim commit 2bf60ebf2139cf409de8ade280831173ec91b8c9 Author: Martin Renvoize Date: Wed Jan 7 15:48:56 2026 +0000 Bug 40934: Add tests for exclude_letter_code in process_message_queue.pl This patch adds unit tests for the new exclude_letter_code functionality in SendQueuedMessages, which will allow excluding specific letter codes when processing the message queue. Test coverage includes: - Excluding a single letter code (array format) - Excluding multiple letter codes - Excluding with scalar parameter format Sponsored-by: OpenFifth Signed-off-by: Marion Durand Signed-off-by: Nick Clemens Signed-off-by: Pedro Amorim commit 0dfcddf383d8239f7ae877f2f0935c0653276f61 Author: Slava Shishkin Date: Wed Sep 16 20:41:11 2026 +0300 Bug 43296: (follow-up) Fix perltidy This follow-up fixes the formatting issue reported by xt/perltidy.t. Test plan: 1. Run prove xt/perltidy.t 2. Confirm it passes. Signed-off-by: Pedro Amorim commit 18469d46c4b09d86c8e666f19ef276407eac8e64 Author: Pedro Amorim Date: Mon Sep 21 11:55:40 2026 +0000 Bug 42667: DBRev 26.06.00.027 Signed-off-by: Pedro Amorim commit 5694e63a8cb1c6342e66226120e060ed93b6c751 Author: Lucas Gass Date: Wed Sep 16 15:07:55 2026 +0000 Bug 42667: (follow-up) Fix edit button inside of preview SQL modal Signed-off-by: Pedro Amorim commit 3d7b5c5a953559dd7ce2d1fc8ef4459f8ca4c857 Author: Lucas Gass Date: Wed Sep 16 14:52:53 2026 +0000 Bug 42667: (follow-up) Update dropdown so users can only choose to edit own report Signed-off-by: Pedro Amorim commit 51d1fe94983ae9dfc7d66338b4ab2280c55d769e Author: Martin Renvoize Date: Thu Jun 11 16:13:14 2026 +0100 Bug 42667: (QA follow-up) Test edit permission on ownerless reports Add two test cases covering reports with no borrowernumber (NULL owner): a patron without edit_all_reports should be denied, one with the permission should succeed. The POD documents this case but it was not previously exercised. Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit 5da8ba1ce9509d21b9644fa27422fd3dc90e2fb9 Author: Martin Renvoize Date: Thu Jun 11 16:12:52 2026 +0100 Bug 42667: (QA follow-up) Fix null guard and exception description - Add null check around Koha::Patrons->find() in guided_reports.pl before calling ->has_permission, matching the defensive pattern already used in Koha::Report::check_edit_permission - Add missing description to Koha::Exceptions::Report base class for consistency with its sub-exceptions Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit 5b5c875df9e79479e83cf6813e57c8fc0632d7c7 Author: Kyle M Hall Date: Thu May 21 13:31:52 2026 -0400 Bug 42667: Enforce permission in Koha::Report Prevents possible template bugs from allowing editing of reports by others without the proper permissions. Signed-off-by: Kyle M Hall Signed-off-by: Brendan Lawlor Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit 1da4dcec000ba4cef13d4e66c6ccfeadf41824f0 Author: Kyle M Hall Date: Thu May 21 12:23:06 2026 -0400 Bug 42667: Hide edit controls as needed Test plan: 1) Apply this patch set 2) Run updatedatabase.pl 3) Restart all the things! 4) Create 2 users with create_reports and not edit_all_reports 5) Create reports with each 6) Note that each cannot edit the others reports 7) Create a user with create_reports and edit_all_reports 8) Note the this user can edit reports from the previous two users Edit button placements to look for: * Reports table row * Actions menu * Toolbar Signed-off-by: Kyle M Hall Signed-off-by: Brendan Lawlor Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit df282a5f893f217eb99653578f9ccbcb1cea0949 Author: Kyle M Hall Date: Thu May 21 12:12:55 2026 -0400 Bug 42667: Require edit_all_reports to edit other librarian's reports Signed-off-by: Kyle M Hall Signed-off-by: Brendan Lawlor Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit d2fa6156fdadadf398a2083d625e6649502a06aa Author: Kyle M Hall Date: Thu May 21 11:34:32 2026 -0400 Bug 42667: Add new edit_all_reports permission Signed-off-by: Kyle M Hall Signed-off-by: Brendan Lawlor Signed-off-by: Martin Renvoize Signed-off-by: Pedro Amorim commit 08a4e352af2b5a0bd53c8cebe8a77bcc99f72b20 Author: Jonathan Druart Date: Fri Sep 18 15:31:22 2026 +0200 Bug 42330: (follow-up) Tidy Something very messy happened during the last rebase before push. Sorry! I've restored the original version: git rebase -i HEAD~258 Edit commit b02ca1270d6eeb3 and remove the next one (Tidy) perl misc/devel/tidy.pl $(git diff --name-only HEAD~1) git commit -a git rebase --continue Luckily there was no conflict! I then picked the version of those files and here is the commit. Use this to confirm: `git show -w ad694a3411e677fcea96f315758793fd1fe0f203` You should see changes that are not related to tidiness Signed-off-by: Owen Leonard Signed-off-by: Pedro Amorim commit dfea14718301faf66f8389e74342a8adcdc59548 Author: Martin Renvoize Date: Thu Jun 18 17:01:00 2026 +0100 Bug 42385: (QA follow-up) Test PickupLibrary fall-through to ItemHomeLibrary The original _GetCircControlBranch tests covered the case where CircControl is PickupLibrary but no userenv branch is available, in which case the resolution falls through to the ItemHomeLibrary behaviour. That coverage was lost when the tests moved to t/db_dependent/Koha/Policy/Circulation.t, since the PickupLibrary subtest always mocks a userenv. This restores coverage for the fall-through path: with CircControl set to PickupLibrary, no userenv, and no pickup_library_id, the controlling library is resolved from the item's home library. Test plan: 1. Apply patch 2. Run: $ ktd --shell k$ prove t/db_dependent/Koha/Policy/Circulation.t => SUCCESS: Tests pass! 3. Sign off :-D Signed-off-by: Martin Renvoize (cherry picked from commit 6a13c6e5066384e59e52f0d48f5a430958671ef2) Signed-off-by: Pedro Amorim