Commit Graph

27407 Commits

Author SHA1 Message Date
Brendan Lawlor ae903a008d
Bug 36868: (QA follow-up) Fix deletion off by one error
When the biblionumber is not in the array -1 is returned.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:12 +00:00
Lucas Gass 9b5f75a79e
Bug 36868: (follow-up) Fix deletion when nothing is in the cart, and make DB update better
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:11 +00:00
Lucas Gass fac6a1adfe
Bug 36868: (follow-up) Fix variable names
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:10 +00:00
Lucas Gass 1e8f39e7a6
Bug 36868: Add logic for OPAC
1. APPLY PATCH, updatedatabase, restart_all
2. Search for the new AutoDeleteFromCartWhenHoldPlaced system preference
3. Turn it on for both staff and OPAC
4. From the staff interface put some items in your cart.
5. Place a hold on all of them.
6. Once the hold(s) have been successfully done those items should no longer be in your cart.
7. Put more items into your staff cart, place a hold on some of them but not all.
8. Only the items you have placed a hold on should be removed.
9. Go to the OPAC and put some items in your cart.
10. Place a hold on all of them, those items should now be deleted from the cart.
11. Place more items into your OPAC cart, place a hold on some of them but not all.
12. Only the items you have placed a hold on should be removed.
13. Switch the AutoDeleteFromCartWhenHoldPlaced to only be for 'staff'.
14. Try steps 4-8 again.
15. Switch the AutoDeleteFromCartWhenHoldPlaced to only be for 'opac'.
16. Try steps 9 -12 again.

Signed-off-by: Sam Lau <samalau@gmail.com>

Signed-off-by: Sarah Fletcher <sfletcher@ncwlibraries.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:08 +00:00
Lucas Gass 42ca5a7b6a
Bug 36868: (follow-up) Fix staff interface code
Signed-off-by: Sam Lau <samalau@gmail.com>

Signed-off-by: Sarah Fletcher <sfletcher@ncwlibraries.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:07 +00:00
Lucas Gass 723258423c
Bug 36868: Add system preference AutoDeleteFromCartWhenHoldPlaced
Signed-off-by: Sam Lau <samalau@gmail.com>

Signed-off-by: Sarah Fletcher <sfletcher@ncwlibraries.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:03 +00:00
Lucas Gass 4d50205d4a
Bug 42722: Add noItemsOnBib error message
Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:50:03 +00:00
Eric Phetteplace f87ee4aecb
Bug 42722: Improve invalidPickupBranch error message
Ensure you have the patch from Bug 41879 and follow its test plan.
You should see the message 'Target item or record has an invalid
pickup location. Either move the hold onto a valid item type or
select a valid pickup location.' when attempting an invalid hold.

Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:50:01 +00:00
Owen Leonard 4c0424994c
Bug 42685: Capitalization corrections in some ILL files
This patch makes two capitalization corrections in files related to ILL:

"ISO18626 Messages" -> "ISO18626 messages"
"Requesting Agencies" -> "Requesting agencies"

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:50:00 +00:00
Owen Leonard 6de2c57c27
Bug 43325: Remove event attribute from point of sale receipt window
This patch removes event attributes from the point of sale receipt
template in favor of adding the "close_window" class to the links. The
class has a globally-defined event handler for the close window
operation

To test, apply the patch and enable the EnablePointOfSale system
preference if necessary.

- If necessary, got to Administration -> Debit types and create at least
  one debit type which has the "Can be sold" checkbox checked.
- Go to the point of sale page and add at least one item to purchase.
- Fill out the "Collect payment" form and confirm.
- When the payment is received, click the "Print receipt button" in the
  dialog.
- On the receipt window which opens, click the "Close" button. The
  window should close.
- Open the receipt window again and change the "accountlines_id"
  parameter in the URL to an accountlines ID which doesn't exist
- The page should show an error message instead of a receipt. Test the
  "Close" button in this view.

Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:49:57 +00:00
Owen Leonard 685be2e643
Bug 43319: Remove event attribute from library_groups.tt
This patch updates the library groups administration page so that an
event attribute is not necessary. We don't need an onclick event handler
to submit the form--we can just use a submit button as the menu item.

To test, apply the patch and go to Administration -> Library groups.

- If necessary, create a new library group.
- From the list of groups, click an "Add library" menu button and then
  click one of the libraries which appear as menu items.
- The page should reload and the library you selected should now show up
  as being part of that library group.

Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:49:56 +00:00
Matt Blenkinsop ec1691b59d
Bug 43320: (QA follow-up) Add html filter and fix translatability
Signed-off-by: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:49:55 +00:00
Nick Clemens 8e663ae7bd
Bug 43320: OPAC adjustments
Similar test plan, but on the OPAC

Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:49:53 +00:00
Nick Clemens 403288c5cd
Bug 43320: Don't quoted already quoted searches and add feedback
Bug 31213 added a quoted search when no results were found,
this patch builds on that to:
1 - Notify the user when their search is repeated quoted
2 - Not repeat a search when already quoted

To test:
 0 - Set system preferences
     RedirectToSoleResult to 'Don't redirect'
     IntranetAddMastheadLibraryPulldown to Show
     IntranetCatalogSearchPulldown to Show
 1 - Add the sample records to your catalog
 2 - Search for the quoted phrase "happy family big" in the 'title' index
 3 - Note you get a result
 4 - Check the record - the phrase is not found, but the record contains all the terms
 5 - Search for the unquoted phrase: 6:20 man
 6 - Confirm search is quoted and result found
 7 - Apply patch, restart all
 8 - Repeat 5
 9 - Confirm you are now told search was quoted and result found
10 - Repeat 2
11 - Confirm no result found, no notice of repeated search

Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:49:52 +00:00
Jacob O'Mara 3e483cd61a
Bug 39658: (follow-up) block checkout when linked accounts over charge limit
When AllowFineOverride is disabled and NoIssuesChargeLinkedAccounts
is exceeded, hide the barcode field and show 'Cannot check out'.
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Kellie Stephens <kellie.stephens@bywatersolutions.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 12:07:41 +00:00
Jacob O'Mara f41cd57410
Bug 39658: Admin: Add linked account system preferences UI
Add prefs for EnablePatronAccountLinking and related settings.
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Kellie Stephens <kellie.stephens@bywatersolutions.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 12:07:34 +00:00
Jacob O'Mara 23de8ce68e
Bug 39658: Patron detail UI: Add linked accounts section
Display linked patrons with Add/Leave link group buttons.
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Kellie Stephens <kellie.stephens@bywatersolutions.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 12:07:33 +00:00
Jacob O'Mara 2b210d6da8
Bug 39658: Circulation UI: Add linked account fee/hold messages
Display warnings for combined debt and linked hold pickup.
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Kellie Stephens <kellie.stephens@bywatersolutions.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 12:07:31 +00:00
Martin Renvoize 9371504d98
Bug 30144: (QA follow-up) Only show servicing instructions when EDIFACT is available
The new servicing instructions UI on the "add order" form was showing
unconditionally, even when the EDIFACT system preference is disabled
or the vendor has no EDI account configured. Elsewhere in acquisitions
(e.g. acqui/basket.tt) EDI-only UI is gated on
Koha.Preference('EDIFACT') && ediaccount, so apply the same check here.

Test plan:
1. With EDIFACT disabled, or EDIFACT enabled but the vendor has no
   entry in vendor_edi_accounts, open Acquisitions > a basket > Add
   order (neworderempty.pl)
   => No "Servicing instructions" field is shown
2. Enable EDIFACT and add a vendor_edi_accounts row for the vendor
   => The "Servicing instructions" field appears and behaves as before

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 12:07:23 +00:00
Jonathan Druart f612fda1e9
Bug 41995: Add nonce
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:14 +00:00
Jonathan Druart 76504e598a
Bug 41995: Remove extra JS code
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:12 +00:00
Jonathan Druart dd536cae2e
Bug 41995: Fix conflict with bug 37762
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:11 +00:00
Jonathan Druart 061cc915ad
Bug 41995: Add autocomplete on the admin home page
Signed-off-by: Anneli Österman <anneli.osterman@koha-suomi.fi>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:10 +00:00
Jonathan Druart c9cfa985b6
Bug 41995: Autocomplete for syspref search
This patch adds autocompletion to the syspref search in the header.

Test plan:
1. Go to the admin home page - /cgi-bin/koha/admin/admin-home.pl
2. In the header start typing the name of a syspref and notice that
   there is now autocompletion (you need at least 3 chars)
3. Select an entry and confirm that you are correctly redirected to the
   correct search result

Signed-off-by: Anneli Österman <anneli.osterman@koha-suomi.fi>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:09 +00:00
Tomás Cohen Arazi 78906e00da
Bug 42443: (QA follow-up) Use POST /transfers/{transfer_id}/cancellation
Cancelling a transfer is a state change on the resource, not a deletion of
it, so it should be modelled as an action sub-resource rather than a DELETE
on the transfer itself. This aligns the endpoint with the API coding
guidelines (REST2: non-CRUD actions use action sub-resources; REST3.2:
conflicts return 409) and with the design used in bug 43454.

Changes:
- Replace DELETE /transfers/{transfer_id} with
  POST /transfers/{transfer_id}/cancellation
- Rename the controller method delete() to cancel(), look the transfer up
  with objects->find_rs, and return 200 with the updated resource
  representation instead of 204 with an empty body
- Make cancellation_reason optional, defaulting to 'Manual', matching the
  legacy returns.pl behaviour
- Return 409 with a structured error_code ('already_arrived',
  'already_cancelled') when the transfer cannot be cancelled, instead of a
  bare 400
- Update the transfers to receive page to POST to the new endpoint and to
  treat 404/409 as "already gone, refresh the table"
- Adapt the tests accordingly, including coverage for the default reason
- The *_date API attribute names introduced by this bug are kept, as they
  are the guideline-compliant form (REST1.3.4.1: *_date, not date_*)

Test plan:
1. Apply patch
2. Run the tests:
   $ ktd --shell
  k$ prove t/db_dependent/api/v1/transfers.t
=> SUCCESS: Tests pass!
3. Rebuild and validate the API spec:
  k$ yarn api:bundle
  k$ prove xt/api.t
=> SUCCESS: Tests pass!
4. In the staff interface, go to Circulation -> Transfers to receive,
   click "Cancel transfer" on a row
=> SUCCESS: The transfer is cancelled and the row drops off the table
5. Cancel the same transfer again from a second tab
=> SUCCESS: The API returns 409 (already_cancelled) and the row is
   treated as already gone
6. Sign off :-D

Assisted-by: Sonnet 4.6 (Anthropic)
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:41 +00:00
Martin Renvoize d7a87e2cbd
Bug 42443: (QA follow-up) Use library selects for Sent from and Home library filters
Replace the free-text filter inputs for the "Sent from" and "Home library"
columns with select dropdowns populated from the full library list, consistent
with other DataTables pages such as the pending bookings page.

The "Sent from" column is made visible again (it was previously hidden since
rowGroup provides the visual grouping); showing it also allows its filter cell
to render.

The "On hold for" column intentionally has no filter: it is computed from two
different embedded sub-objects (item.first_hold.patron or item.recall.patron)
and has no single API field to filter against server-side.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:40 +00:00
Martin Renvoize ebb77c8fa9
Bug 42443: (QA follow-up) Group transfers by sending library using rowGroup
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:38 +00:00
Martin Renvoize 19d1db91d2
Bug 42443: (QA follow-up) Fix escaping of branchcode in JS context
Using | html to embed a TT value inside a JS string literal is
incorrect: it produces HTML entities rather than JS-safe characters.
Store the branchcode in a data attribute (where | html is correct)
and read it from there in JavaScript.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:34 +00:00
Martin Renvoize 16b2ac663e
Bug 42443: (QA follow-up) Guard nullable embed access in JS renderers
from_library and home_library can be null if a transfer references an
orphaned branch row. Accessing .name on null throws a TypeError and
crashes the DataTable renderer; guard both accesses.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:33 +00:00
Kyle M Hall c813fb2574
Bug 42443: Add ability to cancel a transfer via the REST API
This patch adds a DELETE /transfers/{transfer_id} route that cancels the
given transfer by id and reverts an in transit recall for the item the same
way as returns.pl does. The cancellation reason is passed in the request body
so this api endpoint could be used in other places we can cancel transfers.

Signed-off-by: Alex Carver [Acerock7] <alex@rcls.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:29 +00:00
Kyle M Hall 560d7b7ff7
Bug 42443: Convert transfers to receive page to ajax datatable
Updates circ/transferstoreceive.pl to use the new REST API with
an ajax DataTable to display transfer to receive.

Test Plan:
1) Apply this patch
2) Restart all the things!
3) Set an item in transit to your logged in library ( check it in at another
   branch so it is sent home, or place a hold to trigger a transfer )
4) Place a hold on a second transferred item, and a recall on a third
5) Browse to /cgi-bin/koha/circ/transferstoreceive.pl
6) Note the "On hold for" column shows the hold patron, the recall patron or
   "None"
7) Set TransfersMaxDaysWarning low and note the "days late" badge appears
8) Click "Cancel transfer" and note the transfer is cancelled
9) A library with no incoming transfers will get "No transfers to receive"

Signed-off-by: Alex Carver [Acerock7] <alex@rcls.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:28 +00:00
Lisette Scheer 2aa2cc0e7f
Bug 42330: (QA follow-up) Fix file permissions on new test and tidy
This patch
- Fixes the file permissions on the new test
- Removes a variable declaration from the new test that's unused
- Removes a new line from the end of staff-global.scss

Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:24 +00:00
Jonathan Druart 6cb0f5161c
Bug 42330: Auto-tidy
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:23 +00:00
Jonathan Druart fc32990f49
Bug 42330: Add new template tools/restore-records.tt
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:21 +00:00
Owen Leonard 248c0fe224
Bug 42330: (follow-up) Some corrections to sidebars
- The structure of the search facets, advanced MARC editor, and
  HTML customiztions sidebars need to be corrected in order for
  the collapse button to work correctly.
- The "toggle_sidebar" click handler should be inside a
  "$(document).ready()" in order to work correctly on pages where the JS
  is in the header.

Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:19 +00:00
Jonathan Druart ad694a3411
Bug 42330: Tidy
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:17 +00:00
Jonathan Druart b02ca1270d
Bug 42330: Use main-container from all our templates
This goal here is to uniformize the structure of our templates.
Using main-container.inc will also introduce the sidebar collapse (from
bug 42322) where it was missing

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:13 +00:00
David Cook 0acaa7fd55
Bug 43202: Make it easier to find ERM system preferences
This patch makes key ERM system preferences contain the words
ERM, e-resource, and electronic resource to improve discoverability
when searching system preferences.

Test plan:
0. Don't apply the patch yet
1. Go to Administration and type "electronic" into "Search system
   preferences" and search
2. Note you get the message "No system preferences matched your search
   for: electronic"
3. Apply the patch
4. Search for "electronic" in the system preferences again
5. Note that "ERMModule" and "ERMProviders" appear

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 15:54:04 +00:00
Aleisha Amohia 37e6568a9b
Bug 32419: Show item availability on lists view
To test:

1. Create or use a biblio record with multiple items, for example biblionumber 235.
2. Check out an item attached to the record to a patron, i.e. check out barcode 39999000010190 to your logged in user
3. Go to the Detail view for this record.
4. Edit another item attached to the record and give it a not for loan status, i.e. edit barcode 39999000010213 and set it to Not for loan
5. Click the Add to list button above the record. Add the record to an existing list, or create a new one and Save.
6. Go to the Lists module in the staff interface and view the contents of the list you just added your record to.
7. Confirm you see accurate Availability information in the list results within the callnumber column.

Sponsored-by: Pymble Ladies' College
Signed-off-by: Hayley Cheng <hacheng@pymblelc.nsw.edu.au>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 15:54:03 +00:00
Martin Renvoize 9a4a9415ab
Bug 42997: Warn staff when a due date override runs into the next booking
When checking out a booked item, staff may override the suggested due
date. If that override runs into the next booking for the item, the
previous patch would silently keep the booking's original end date -
staff had no way of knowing their override crossed another booking.

This patch adds an exclude_booking_id option to Koha::Item->find_booking
so a lookup can skip a specific booking (here: the patron's own booking
being collected), and uses it in CanBookBeIssued to detect when an
explicitly requested due date would run into the next booking for the
item. When it would, a new BOOKED_DUE_DATE_CLASH confirmation is raised
and displayed on the checkout screen, telling staff the linked booking
will keep its original end date if they continue.

Only explicitly requested due dates trigger the confirmation -
calculated due dates are clamped to the booking end date later in the
staff checkout flow, so checking them would produce false positives.
SIP is unaffected as it never passes a requested due date.

Test plan:
1) Run t/db_dependent/Circulation.t and t/db_dependent/Koha/Item.t
2) Create two consecutive bookings on the same item for two patrons
3) Check the item out to the first patron specifying a due date beyond
   the second booking's start date; confirm the new confirmation
   message appears and checkout only proceeds once confirmed

Sponsored-by: OpenFifth <https://openfifth.co.uk/\>
Sponsored-by: Westminster City Council <https://www.westminster.gov.uk/\>
Signed-off-by: Hannah Dunne-Howrie <hdunne-howrie@westminster.gov.uk>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 15:53:52 +00:00
Marcel de Rooy 3ec3c465ba
Bug 36001: Show MARC21 362 on OPAC and staff
Test plan:
Find a serial.
Add a 362 with some content in $a
Check the normal view on OPAC and staff.

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: sabrina <sabrina.kiehl@gwdg.de>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 15:53:46 +00:00
Brendan Lawlor b7df6f071f
Bug 38196: (QA follow-up) Rename Include as Show
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:57:01 +00:00
Jan Kissig 54c5c2a9c4
Bug 38196: (follow-up) Fix issue with concern filters containing underscores
This fixes the issue that a filter for a ticket status is not applied when the underlying authorised value for that ticket status contains an underscore.
Also the fa icons are changed to be more intuitive.

Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:57:00 +00:00
Jan Kissig f14a046bb1
Bug 38196: (follow-up) Rename Filter to Hide in concerns.tt
This changes the filter names in concerns.tt from "Filter ..." to "Hide ..." to clarify that a filter here will remove items with that value from the table.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:56:59 +00:00
Jan Kissig 69217a2bc4
Bug 38196: Fix filter in catalog concerns to show tickets where status is NULL
This patch fixes issues on catalog concerns when filtering for self defined authorized values (AV).
When querying for status != AV, also rows with status = NULL are omitted as SQL here only checks for defined values in status.
The patch wraps the a filter query with an 'or status is NULL'.

Test plan:
apply patch dependencies (42283) if not already included and run restart_all
a) enable system preference CatalogConcerns
b) create some authorised values in TICKET_STATUS
c) create several concerns/tickets (biblio detail page -> new catalog concern)
d) go to /cgi-bin/koha/cataloguing/concerns.pl and change some ticket status to have some variation for filtering
e) play with the filters on the top (resolved and self created TICKET_STATUS)
- when clicking 'Filter resolved' tickets with status 'Resolved by ... date' get filtered
- when filtering self created TICKET_STATUS values tickets with that status AND tickets with status Open are disappearing
f) apply patch and run restart_all
g) retry steps in e) and check that only the filtered status are filtered from the results list.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:56:58 +00:00
Nick Clemens f1ca516b60
Bug 39829: Allow custom title in SIP responses
This patch adds a custom aj_field_template to the sip accounts
This allows libraries to specify a template for the title (AJ) field in sip
messages

The template allows using item and biblio fields (item provides access to biblio. but we pass
both in order to makes the templates simpler

To test:
1 - Install patches
2 - updatedatabase, yarn build, restart_all
3 - Setup a sip account, KTD already has a sip patron, term1, you can use that
    don't add the aj_field_template yet
4 - Find or create a biblio with 245a and 245b like 245$aTitle : $bSubtitle and add item with TESTBARCODE
5 - From the command line:
    perl misc/sip_cli_emulator.pl -su term1 -sp term1 -l CPL -t CR -a localhost -p 6001 -m item_information --item TESTBARCODE
6 - Confirm AJ field shows "Title :" as expected
7 - Edit sip account, set aj_field_template to:
    [% biblio.title %] [% biblio.subtitle %] [% item.barcode %]
8 - Repeat the sip test
9 - Confirm you get the response like:
    Title : Subtitle TESTBARCODE
10 - Sign off!

Signed-off-by: Bob Bennhoff <bbennhoff@clicweb.org>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:56:52 +00:00
Jonathan Druart 6a040f8003
Bug 42975: (bug 35380 follow-up) Fix patron category filtering on Record overlay rules
Test plan:
Turn on MARCOverlayRules
Go to /cgi-bin/koha/admin/marc-overlay-rules.pl
Confirm the "Filter" column is correctly adjusted when the "source"
dropdown is modified

Signed-off-by: Jan Kissig <bibliothek@th-wildau.de>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:56:50 +00:00
Pedro Amorim 481e170da1
Bug 42968: Revert "Bug 42968: Add fallback label for 505 contents notes"
This reverts commit 3bdecfb4e6.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:52:24 +00:00
Laura_Escamilla 3bdecfb4e6
Bug 42968: Add fallback label for 505 contents notes
To test:

1. Create or locate a bibliographic record with a MARC 505 field.

2. Leave the first indicator blank.

3. Add text to the 505 field.

4. View the record detail page.

5. Notice that the 505 contents display without a label.

6. Apply the patch

7. Refresh the record detail page. Notice that the 505 content displays a label now.

8. Sign off and have a lovely day! :D

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:19 +00:00
Jonathan Druart 02491b08d3
Bug 43394: DT - Cast pageLength to Integer
In "Edit patron card batch" the pageLength is coming from the syspref,
the value is a string.
But DataTable's needs an integer.
Let's fix this in datatables.js, in the kohaTable's constructor

Test plan:
Got to cgi-bin/koha/patroncards/edit-batch.pl
Enter more than 20 borrowernumbers and "Add patron(s)"
Click "next" and notice that with this patch the pagination works.
Without this patch the JS error is
"Uncaught TypeError: can't access property "nTr", p is undefined"

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:14 +00:00
Andrew Fuerste Henry 0c86df4755
Bug 43072: Show Yes when no rule exists for fill_other_biblio_holds_policy
To test
1 - have three test biblios. Bib A has just one item, a Book. Bib B has two items, a Book and a Computer File. Bib C has one item, a Computer File
2 - have KTD default circ rules (holds allowed for all itemtypes in the circ rules table, no values defined in "Default checkout, hold and return policy" or "Default holds and bookings policies by item type
")
3 - set "Default holds and bookings policies by item type" for Computer Files to Hold Policy = "No holds allowed."
4 - observe that "Fill other record level holds on record at checkout" defaults to "Yes" when a value is set to Hold Policy
5 - confirm you can place a holds on Bib A and Bib B but not Bib C
6 - confirm your hold on Bib B is filled when checking out the Computer File item from Bib B
7 - update "Default holds and bookings policies by item type" so Computer Files has Hold Policy = "No holds allowed" and "Fill other record level holds on record at checkout" = No
8 - confirm you're still able to place a hold on Bib B
9 - confirm your hold on Bib B is now *not* filled by checking out the Computer Files item
10 - open the commandline SQL interface (sudo koha-mysql kohadev on KTD)
11 - run query "select * from circulation_rules where rule_name = 'fill_other_biblio_holds_policy'"; confirm an entry for Computer Files with rule_value=0
12 - run command "delete from circulation_rules where rule_name = 'fill_other_biblio_holds_policy'"
13 - reload your circ rules page, confirm the interface still shows "Fill other record level holds on record at checkout" = No for comoputer files
14 - confirm your hold on Bib B can again be filled by checking out the Computer File item

 APPLY PATCH, restart_all

15 - reload circ rule page, confirm it now shows "Fill other record level holds on record at checkout" = Yes for Computer Files
16 - run query "select * from circulation_rules where rule_name = 'fill_other_biblio_holds_policy'"; confirm there is still no entry for Computer Files
17 - place a new hold on Bib B, confirm it fills by checking out the Computer File (not having any rule defined is enforced the same as a "Yes" and displays a "Yes")
18 - in circ rules, set "Fill other record level holds on record at checkout" = Yes for computer files
19 - run query "select * from circulation_rules where rule_name = 'fill_other_biblio_holds_policy'"; confirm there is an entry for Computer Files with rule_value=1
20 - place a new hold on Bib B, confirm it fills by checking out the Computer File (having an explicit Yes rule defined is enforced correctly and displays correctly)
21 - in circ rules, set "Fill other record level holds on record at checkout" = No for computer files
22 - run query "select * from circulation_rules where rule_name = 'fill_other_biblio_holds_policy'"; confirm there is an entry for Computer Files with rule_value=0
23 - place a new hold on Bib B, confirm it does not fill by checking out the Computer File (having an explicit No rule defined is enforced correctly and displays correctly)

Signed-off-by: Lawrence O'Regan-Lloyd <loreganlloyd@clamsnet.org>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:09 +00:00
Martin Renvoize bfc6866200
Bug 39589: Auto-skip to the next page and note hidden results when a page is fully filtered
When every result on a page is hidden (OpacHiddenItemsHidesRecord), rather
than leaving the patron on a dead-end "not available" page, look ahead a
bounded number of pages (3) for one with visible results and redirect
there directly. The lookahead is capped so a library with many
consecutive hidden pages doesn't turn a single search into a long chain
of extra search-engine queries; RSS/atom/opensearchdescription requests
are left alone since redirecting a feed reader makes no sense.

Whenever a hidden page was skipped over (whether we found a visible page
to land on, or exhausted the lookahead and fell back to the "not
available" message), show a caveat next to the results count so the
"Your search returned N results" figure doesn't read as contradicting
what the patron can actually see - this was raised as a sign-off concern
on the original patch (comment 4).

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:07 +00:00
Martin Renvoize a8523740b0
Bug 39589: (QA follow-up) Revert unrelated star rating markup change
The read-only star rating widget in search results was changed from
<span> to <a href="#"> elements, unrelated to this bug's fix. That
activated a pre-existing but previously dead click handler
($(".br-readonly a") in this same template) and turned every star icon
into a focusable, non-functional link, adding up to 5 dead tab stops
per search result. Restore the <span> markup used everywhere else this
read-only widget appears.

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:06 +00:00
Chris Mathevet ff26e80dc8
Bug 39589: (follow-up) Applied suggested changes
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:04 +00:00
Hammat Wele 38e0b734c9
Bug 39589: OPAC search returns 'No results found' despite existing matching records
This issue occurs when the records on the first page of results are not displayed. The message "No results found" is shown, and it is not possible to access records on other pages.

To test

    1. Set the following system preferences:
        OPACnumSearchResults to 5
        OpacHiddenItemsHidesRecord to Hide
        OpacHiddenItems to withdrawn: [1]
    2. Create 6 bibliographic records with the following titles:
        "notice test 1"
        "notice test 2"
        "notice test 3"
        "notice test 4"
        "notice test 5"
        "notice test 6"
    3. For the first 5 records, add an item with Withdrawn status.
    4. For "notice test 6", add an item with Available status.
    5. In the OPAC interface, search for "notice test".
    6. Apply the patch
    7. Repeat step 4
       ---> The results table is now shown with the message: "Search results on this page are not available."
       ---> You can now access the second page and see "notice test 6"

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:03 +00:00
Andrii Nugged fd6a616428
Bug 43354: Fix ILL request table search
Bug 33544 combined the ILL request detail fields into one column. The
combined column kept an empty data property without the related-object
search metadata. A global table search therefore generated a query against
"me.", which the REST endpoint rejected with a 500 error.

Restore the extended attribute search mapping for the fields displayed in
the combined Request details column. Add Cypress coverage for both the REST
query and the matching result.

Test plan:
Before applying the patch:
1. Make sure the ILLModule system preference is enabled.
2. Open a patron record.
3. Click "ILL requests history" in the menu on the left.
4. Type any text in the Search box above the table.
5. Confirm that Koha shows a 500 Internal Server Error message.

Apply the patch.

After applying the patch:
1. Repeat steps 2 to 4 above.
2. Confirm that the table refreshes without an error. It may show no
   matching requests.
3. If the patron has an ILL request, search for part of a title or author
   shown under Request details.
4. Confirm that the matching request remains in the table.

Co-Authored-By: Loontik <loontik@nugged.team>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:00 +00:00
Jonathan Druart 274432cd68
Bug 43259: Fix add/remove basket to/from group
Caused by
  commit e9b8004d19
  Bug 38255: Replace dataTable constructor with kohaTable - Staff

grouped and ungrouped should be DataTable objects.

Test plan:
Create a basket, close it
Create a basket group and test the "Add to group" and "Remove" button on
the basket group edit view

Without this patch there was a JS error:
"Uncaught TypeError: grouped.row is not a function"

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:41:56 +00:00
Jonathan Druart e42b4df37b
Bug 42661: Remove redundant library's name if HidePatronName
If HidePatronName is turned on and a hold is being placed on a hold for
a patron with a different library, there is an alert the duplicate the
library's name:
Pickup library is different. Patron: A patron from library Springfield Patron's home library: (Springfield / SPL)

With this patch:
Pickup library is different. Patron's home library: Springfield / SPL
Pickup library is different. Patron: Keith Hendrix Patron's home library: Springfield / SPL

Test plan:
Go to /cgi-bin/koha/reserve/request.pl?biblionumber=117&borrowernumber=26
And confirm that the changes make sense

Signed-off-by: Anneli Österman <anneli.osterman@koha-suomi.fi>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:45 +00:00
Owen Leonard 0a5919f108
Bug 43257: Remove event attributes from circulation.tt
This patch updates circulation.tt in order to remove event attributes in
favor of defining event handlers in the relevant JS file.

To test, apply the patch and clear your cache if necessary.

- If necessary, enable the SpecifyDueDate system preference.
- Check out to a patron.
- Click the checkout settings icon inside the barcode field.
- Click the "Specify due date" field's "Remember for session" checkbox
  - The focus should move to the barcode field.

- Enable recalls if necessary
- Locate a checked out item which can be recalled.
- Log in to the OPAC and recall the item.
- In the staff interface, try to check that item out to another patron.
  - You should get a "Please confirm checkout" message.
  - Click the "Don't check out and print slip" button.
  - A popup should open for printing a recall slip.
  - The checkout page should reload  without checking out the item.

- If necessary, place a hold on an item for delivery to your logged-in
  library, check in the item, and confirm the hold.
- Try to check out the item to another patron.
  - You should get a "Please confirm checkout" message.
  - Click "Don't check out, confirm hold, and print slip"
  - A popup should open for printing a hold slip.
  - The checkout page should reload  without checking out the item.

- If necessary, place a hold on an item but do not check it in.
- Try to check out the item to a patron.
  - You should get a "Please confirm checkout" message.
  - Click "Cancel checkout and place hold for..."
  - You should be redirected to the holds page, placing a hold for that
    patron and that item.
  - The item should not have gotten checked out in the process.

Sponsored-by: Athens County Public Libraries
Signed-off-by: Olivia Reynolds <olivia.reynolds@openfifth.co.uk>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:41 +00:00
Jonathan Druart b1905338eb
Bug 43373: Holdings table - hide the shelving location column if empty
The shelving location cell is always built with data: an empty HTML tag
is added even if there is no location.
So the "Shelving location" column is always displayed, it should only be
displayed if there are items with data.

Test plan:
Have a biblio with all items without shelving location (or without
several pages and at least one page without data).

If all rows have empty shelving loc, the column should be hidden

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:40 +00:00
Jonathan Druart d80ca5f4e8
Bug 42875: Correct failure message when adding an item to a bundle
If bc_1 is checked out and I try to add bc_2 I get:
"Failure: Item 'bc_2' belongs to another bundle"

It should be:
"Failure: Bundle is currently checked out"

Test plan (using KTD):
1. Pick a record with items, for example: The definitive guide to Catalyst (146)
2. Edit the record and change 000 (the leader):
   - Click the tag editor
   - Change "7- Bibliographic level" to "C- Collection"
3. In the holdings table there is now a "Manage bundle (0|0)" option
   in the far right column for each item.
4. Check an item out for the record out, for example
   I checked out 39999000006117 to Mary Burton.
5. In the holdings table for the record, click on "Manage bundle" for the item
   you checked out (39999000006117).
6. In the expanded text area below the item row, click "+ Add to bundle".
7. In pop-up window, enter 39999000006131 "Item barcode" field (this is one
   of the other items for the record that is not checked out).
8. Click Submit.
9. You get an error:
     Failure: Item '39999000006131' belongs to another bundle
10. Apply the patch.
11. Restart everything: restart all
12. Hard refresh the page for the record.
13. Repeat steps 5 to 8.
14. You now get the correct error:
      "Failure: Bundle is currently checked out"

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:39 +00:00
Andrii Nugged 757b347bed
Bug 42605: Preserve acquisition preference string values
Bug 41563 converted AcqCreateItem and UniqueItemFields to booleans when
adding them to Koha.prefs. Both preferences are strings: AcqCreateItem
controls where items are created, while UniqueItemFields contains a
pipe-separated list.

When a basket inherits AcqCreateItem=ordering, the boolean value matches
none of the receiving page branches and existing items are hidden. When
items are created on receiving, the numeric UniqueItemFields value also
fails when the page calls split().

Preserve both string values in Koha.prefs. Add a Cypress regression test
which renders orderreceive.pl and verifies the values exposed to
JavaScript.

Test plan:

Before applying the patch:

1. Set AcqCreateItem to "placing an order" and UniqueItemFields to
   "barcode".
2. Create a basket that inherits the system preference. Add an order with one
   item, close the basket, and start receiving it.
3. Confirm that the Items table has no existing item row and no Receive
   checkbox.
4. Set AcqCreateItem to "receiving an order" and open the same order for
   receiving.
5. Confirm that the Items section is empty: no item-entry fields and no Add
   item button are shown.

Apply the patch.

After applying the patch:

1. Set AcqCreateItem back to "placing an order" and open the order for
   receiving again.
2. Confirm that its existing item is listed and has a Receive checkbox.
3. Set AcqCreateItem to "receiving an order" and open the same order again.
4. Confirm that the Items section contains item-entry fields and an Add item
   button.

Co-Authored-By: Loontik <loontik@nugged.team>
Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:32 +00:00
Martin Renvoize 2e1f8b8660
Bug 30144: (QA follow-up) Make servicing instruction UI strings translatable
The servicing instructions widget added new user-facing strings (alerts,
button labels, hints) built entirely in JS via string concatenation, none
of which were wrapped for translation - unlike the pre-existing JS in the
same file, which already uses _() throughout. Wrap them the same way,
using _("...").format(...) for the strings that interpolate a value,
matching the existing pattern used elsewhere in this file.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:27 +00:00
Martin Renvoize bbb7f406d2
Bug 30144: (QA follow-up) Fix stored XSS in servicing instructions
The RM's review found two stored XSS vectors in the servicing
instruction free-text (LVT) handling:

1. neworderempty.tt embedded the servicing instruction JSON (and the
   EDIFACT_SI authorised values list) directly into an inline <script>
   block via JSON.parse('[% ... | $raw %]'). TT's html filter does not
   escape single quotes, so a free-text value like
   test' + alert(1) + ' broke out of the JS string literal and
   executed on the next page load of the edit form.

2. basket.pl built the "Servicing instruction" column display by
   concatenating raw LVC/LVT values with '<br>' and rendering the
   result with | $raw in basket.tt, so HTML/script content in a
   free-text value executed directly on the basket page.

Fix the first by moving the JSON into existing/new hidden input
value="" attributes (escaped with the html filter, which is safe for
double-quoted HTML attributes) and reading them back via jQuery's
.val() before JSON.parse(), instead of interpolating untrusted data
into a JS string literal.

Fix the second by passing the display parts to the template as a list
and escaping each with the html filter at render time, instead of
building a pre-escaped raw HTML string in Perl.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:26 +00:00
Martin Renvoize c215f2dd43
Bug 30144: Add UI for servicing instructions
This patch adds the user interface for managing and displaying
EDIFACT servicing instructions in the acquisitions module.

Changes to acqui/neworderempty.pl:
- Parses servicing_instruction JSON for editing existing orders
- Fetches EDIFACT_SI authorized values for dropdown
- Passes data to template in both array and JSON formats

Changes to acqui/addorder.pl:
- Accepts servicing_instruction_groups_json from form submission
- Validates and stores JSON in database

Changes to acqui/basket.pl:
- Fetches EDIFACT_SI authorized values
- Formats servicing instructions for display in get_order_infos()
- Creates human-readable display strings with:
  * LVC codes replaced with descriptions
  * Groups separated by <br> tags
  * Format: "Description" or "Description: free text"

Changes to neworderempty.tt:
- Dynamic UI for adding/removing servicing instruction groups
- Each group can contain:
  * One LVC (coded) instruction only, OR
  * One LVT (free-text) instruction only, OR
  * One LVC + one LVT combination
- Validation prevents:
  * More than 2 instructions per group
  * Duplicate LVC or LVT in same group
- LVC instructions use dropdown populated from EDIFACT_SI authorized values
- LVT instructions use free-text input
- Groups serialized to JSON hidden field for form submission
- Smart button labels show what can be added to each group

Changes to basket.tt:
- Displays servicing instructions in basket table
- Pre-formatted in Perl (no JavaScript parsing needed)
- Shows LVC descriptions instead of codes
- Multiple groups displayed on separate lines

Changes to columns_settings.yml:
- Adds servicing_instruction column to basket table configuration

Display format examples:
- LVC only: "Barcode labelling"
- LVT only: "Handle with care"
- Combined: "Binding: Apply to spine"
- Multiple groups (on separate lines):
  Barcode labelling
  Binding: Special instructions

Test plan:
1. Create/edit order
2. Add servicing instruction groups
3. Try to add more than 2 instructions to a group (should prevent)
4. Try to add duplicate LVC or LVT to group (should prevent)
5. Save order
6. View basket and verify instructions display correctly
7. Edit order and verify instructions load into form

Sponsored-by: Martin Renvoize <martin.renvoize@gmail.com>
Signed-off-by: Hannah Dunne-Howrie <hdunne-howrie@westminster.gov.uk>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-28 16:36:22 +00:00
Amit Gupta 561ef2f025
Bug 42904: Prevent XSS in patron restriction comments
Test plan

1. Search for a patron and open the patron details page.
2. Under "Patron restrictions", add a manual restriction with the following comment:
   <img src=x onerror="alert(document.domain)">
3. Save the restriction.
4. Navigate to the patron checkouts page:
   /cgi-bin/koha/circ/circulation.pl?borrowernumber=xxx
   Verify that the JavaScript payload executes.
5. Edit the patron record:
   /cgi-bin/koha/members/memberentry.pl?op=edit_form&destination=circ&borrowernumber=xxx
   Verify that the JavaScript payload executes.
6. For OPAC - Go to OPAC Verify that the JavaScript payload executes - /cgi-bin/koha/opac-user.pl
7. Apply the patch.
8. Repeat steps 4, 5 and 6.
9. Verify that:
   1. No JavaScript is executed.
   2. The page loads normally without any alert dialog. Applicable for both the staff and opac.

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-26 09:23:34 +00:00
Martin Renvoize d32ae7f064
Bug 42800: (QA follow-up) Fix backslash breaking the shelf list script block
erm.tt built the logged_in_user_lists JS array by manually
interpolating each shelf's id/name into a JS string literal, escaped
with the TT html filter:

    id: "[% shelf.shelfnumber | html %]",
    name: "[% shelf.shelfname | html %]",

The html filter escapes <, >, &, and " -- enough to stop the
<script>-tag and </script>-breakout scenario from the original bug --
but it does not escape backslashes. A list name ending in a backslash
(e.g. "foo\") escapes the closing quote of the JS string literal,
unbalancing it and throwing a JS syntax error that breaks the whole
inline <script> block on every ERM page (including the unrelated
`const logged_in_user = ...` a few lines below), reproducing the
"broken UI" half of the original bug via a different character.

Build the id/name pairs as an actual array of hashes and JSON-encode
them with To.json(), after escaping each value with the html
vmethod. JSON encoding (via the JSON module) correctly escapes
backslashes and quotes for use inside a JS string, while keeping the
values HTML-escaped so they stay inert if ever written into the DOM
via innerHTML (as the DataTables render callback in
EHoldingsLocalTitlesFormImport.vue does).

Test plan:
1. Enable the ERMModule system preference.
2. Create a list named: backslash test \
3. Go to /cgi-bin/koha/erm/eholdings/local/titles/import (or any
   other ERM page).
   => Without this patch: the page's inline script throws a syntax
      error ("Invalid or unexpected token") and
      "logged_in_user_lists is not defined", breaking the Vue
      component.
   => With this patch: the page loads without errors and the list is
      shown correctly in the table.
4. Also verify the original bug's script-tag scenario still works:
   create a list named <script>alert("booh!");</script> and confirm
   it displays as inert text, not executing, on the same pages.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-26 09:23:33 +00:00
Jonathan Druart 22a6ab9729
Bug 42800: Fix XSS in shelf list in the ERM module
const logged_in_user_lists = [% To.json(logged_in_user.virtualshelves.unblessed) | $raw %];

If you have a script tag in a list name the UI will be broken, and there
is potentially a XSS vulnerability

Test plan:
Create a new list with name="<script>alert("booh!");</script>"
Go to /cgi-bin/koha/erm/eholdings/local/titles/import
or any ERM views
=> Without this patch the UI is broken
=> With this patch applied it's not and the table is correctly populated
with the lists

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-26 09:23:32 +00:00
Owen Leonard fc8f56b88f
Bug 42322: (follow-up) Correct markup of ILL sidebar menu
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:45 +00:00
Owen Leonard 71d8564789
Bug 42322: (follow-up) Switch to mobile-first handling of sidebar toggle
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:44 +00:00
Jonathan Druart c407f73309
Bug 42322: Hide collapsed sidebar on small screens
When the sidebar is collapsed and the screen is resized to <= 1000px,
'#sidebar-container' should be hidden

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:43 +00:00
Jonathan Druart 7fb0345f7f
Bug 42322: Correctly toggle aria-expanded
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:42 +00:00
Jonathan Druart e8c7901788
Bug 42322: Add missing raw filter for aside_block
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:41 +00:00
Jonathan Druart 4d87ae3424
Bug 42322: Hide .patroninfo, .browse-controls and #search-facets when collapsed
Fix sidebar when collapsed on:
 * /members/moremember.pl?borrowernumber=42
 * /catalogue/search.pl?advsearch=1&idx=kw&q=d&idx=kw&q=&idx=kw&q=&weight_search_submitted=1&weight_search=1&sort_by=relevance
 * /catalogue/detail.pl?biblionumber=438&searchid=scs_1776086577193
   (with BrowseResultSelection ON)

Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:40 +00:00
Owen Leonard 34644298e4
Bug 42322: (follow-up) A version with just the button
Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:39 +00:00
Owen Leonard f9dc282e26
Bug 42322: (follow-up) Proposed alternative style
This version keeps a visual indicator of the collapsed sidebar.

I've also added handling of the "aria-expanded" attribute.

Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:38 +00:00
Jonathan Druart 4784d952e7
Bug 42322: Vue apps
Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:37 +00:00
Owen Leonard b804854865
Bug 42322: Auto tidy
To ease rebase!

Re-run.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:36 +00:00
Jonathan Druart be9a2c7c5f
Bug 42322: Use main-container.inc from reports
Pass the aside block from the report module

Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:35 +00:00
Jonathan Druart add690d0f4
Bug 42322: Pass the aside to main-container
Improve main-container.inc so we can pass a specific aside block

Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:34 +00:00
Jonathan Druart ab7602b0f3
Bug 42322: Add a 'collapse sidebar' button
On bug 42190 we discuss the possibility to collapse the sidebar in order to enlarge the screen and specifically the table in the main div.

This patch adds the button to main-container.inc that is supposed to be
used from everywhere.

Signed-off-by: Clemens Tubach <clemens.tubach@kit.edu>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:33 +00:00
Matt Blenkinsop ce3643073a
Bug 39959: Add a total column to the invoices table
Test plan:
1. Create an order and receive it to create an invoice
2. In the invoices search, look for your invoice
3. There will be no total against the invoice
4. Apply patch and restart_all
5. Refresh the page, the total column should now be present

Signed-off-by: Coleen Lilly <clilly@aacpl.net>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:32 +00:00
Matt Blenkinsop b114eb709f
Bug 12278: Add a total column to the table in parcels.pl
Test plan:
1. Create an order with multiple items and receive the order in full
2. From the vendor record, click Receive shipments
3. You should be in parcels.pl and the table should show your shipments
4. There will be no column displaying the total
5. Apply patch and restart_all
6. Refresh the page, the column should now be visible showing the total

Signed-off-by: Coleen Lilly <clilly@aacpl.net>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:29 +00:00
Olivia Reynolds ad30c815ce
Bug 34166: Add total column to suggestions table
This patch displays the "total_price" field from the API in the
acquisition suggestions table. In line with other totals, it is
displayed unitless after currency conversion.

Test plan:
1.  Navigate to Acquisitions > Suggestions.
2.  Click "New purchase suggestion", then add a title, price, and
    number of copies.
3.  Make note of the calculated total price.
3.  Save the suggestion to return to the table.
4.  Verify there is no "Total" column on the suggestions table.
5.  Apply patch, update database, and refresh.
6.  Verify there is a "Total" column on the suggestions table that
    matches the previously displayed total price.
7.  Verify the "Total" column is listed under the "Columns" dropdown.
8.  Above the suggestions table, click "Configure".
9.  In the column settings for suggestions, check both "Is hidden by
    default" and "Cannot be toggled" for "total".
10. Underneath the column settings for suggestions, uncheck "Save
    configuration state on page change".
11. Save the column settings.
12. Return to the suggestions table.
13. Verify the "Total" column is hidden.
14. Verify the "Total" column is not listed under the "Columns"
    dropdown.

Sponsored-by: Open Fifth
Signed-off-by: Michaela <michaela.sieber@kit.edu>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-21 15:58:24 +00:00
Owen Leonard 89066b3c7b
Bug 42111: Update various admin pages to use grid layout for forms - Part 1
This patch updates several administration templates with new markup and
CSS for layout forms using CSS grids.

To test, apply the patch rebuild the staff interface CSS.

Check the following pages, confirming that the "New" and
"Edit" versions of the form look correct in each case:

- Administration -> Additional fields
- Administration -> Audio alerts
- Administration -> Cities and Towns
- Administration -> Classification configuration
  -> Classification sources
  -> Classification filing rules
  -> Classification splitting rules

On the classification splitting rules page I've reformatted the regular
expression section to fit better. To test, add or edit a splitting rule.

- Under "Splitting routine" choose "RegEx"
  - "Regular expression" and "Test the regular expressions" fields
    should appear.
- Add one or more regular expressions, e.g.

  s/\s/\n/g
  s/(\s?=)/\n=/g
  s/^(J|K)\n/$1 /

- In the "Test the regular expressions" text area enter some call
  numbers e.g.

  830 Han
  159.9 (091) Gesh
  J 3 Kin =774
  830 Hil =774 4
  830 Las=20 4

- Click "Test"
- The formatted call numbers should appear below in a grid:

+---------+------------------+--------------+----------------+--------------+
| 830 Han | 159.9 (091) Gesh | J 3 Kin =774 | 830 Hil =774 4 | 830 Las=20 4 |
+---------+------------------+--------------+----------------+--------------+
| 830     | 159.9            | J 3          | 830            | 830          |
| Han     | (091)            | Kin          | Hil            | Las          |
|         | Gesh             | =774         | =774           | =20          |
|         |                  |              | 4              | 4            |
+---------+------------------+--------------+----------------+--------------+

Sponsored-by: Athens County Public Libraries
Signed-off-by: Felicie <felicie.thiery@biblibre.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-21 15:58:23 +00:00
Tomás Cohen Arazi d6e40f612c
Bug 20846: Filter suppressed records from public lists in OPAC
When OpacSuppression is enabled, records marked as suppressed
(biblio.opac_suppressed = 1) still appear in public lists viewed
through the OPAC. This is confusing for patrons.

This patch adds a filter_by_not_suppressed method to
Koha::Virtualshelfcontents and uses it in opac-shelves.pl to
exclude suppressed records from list display when OpacSuppression
is enabled. OpacSuppressionByIPRange is respected: users within
the allowed IP range still see all records.

Test plan:
1. Apply patch
2. Enable OpacSuppression system preference
3. Create a public list and add some titles to it
4. Suppress one of the titles (set 942$n = 1)
5. View the list in the OPAC
=> SUCCESS: Suppressed record is no longer shown in the list
6. Set OpacSuppressionByIPRange to match your IP (e.g. 127.)
7. Repeat step 5
=> SUCCESS: All records (including suppressed) are shown
8. Run:
   $ ktd --shell
   k$ prove t/db_dependent/Virtualshelves.t
=> SUCCESS: Tests pass!
9. Sign off :-D

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-21 14:31:50 +00:00
Andrew Fuerste Henry fbfccfdbf2
Bug 43331: Add ccode class to holdings table
To test:
1 - go to a bib record with items
2 - inspect the items table, confirm there is no class on the cell
    containing the ccode
3 - Apply patch, restart_all
4 - reload your bib page
5 - inspect the table again, confirm the cell has the class "ccode"

Signed-off-by: Owen Leonard <oleonard@myacpl.org>

Signed-off-by: Michelle Spinney <mspinney@clamsnet.org>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-21 14:31:44 +00:00
Hammat Wele 35b58d65c5
Bug 43211: (follow-up) fix 'barcode is not defined' error
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-20 16:10:44 +00:00
Janusz Kaczmarek a17d27f8ae
Bug 43211: Koha hangs when receiving order with AcqCreateItem set to 'receiving an order'
Koha hangs when receiving an order with AcqCreateItem set to
"receiving an order".

Test plan:

1. Create a basket and set "Create items when" to "receiving an order".
2. Add an order and close the basket.
3. Attempt to receive the order. Koha will most likely hang.
4. Apply the patch; restart_all.
5. Repeat p. 3. You should be able co proceed.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-20 16:10:38 +00:00
Nick Clemens f473c7d451
Bug 41029: Add option for marc overlay rules to apply when adding to a basket
This patch adds a new option to allow defining overlay rules for 'Add to basket' - such that they
will be used when adding orders in acquisition. Existing 'Staged MARC Import' rules will be copied to
the new fitler in order to preserve behavior

To test:
 1 - Paste the following into MarcFieldsToOrder and save
  price: 975$p
  quantity: 975$q
  budget_code: 975$h
 2 - Paste the following into MarcItemFieldsToOrder and save
  homebranch: 949$a
  holdingbranch: 949$b
  itype: 949$y
  nonpublic_note: 949$x
  public_note: 949$z
  loc: 949$c
  ccode: 949$8
  notforloan: 949$7
  uri: 949$u
  copyno: 949$t
  price: 949$g
  replacementprice: 949$v
  itemcallnumber: 949$o
  quantity: 949$k
  budget_code: 949$l
 3 - Go to Admin -> Record overlay rules
 4 - Define 2 rules:
  Source - Staged Marc Import - 949 - Add and append (the rest of the options are set when add and append is selected
  Source - Staged Marc Import - * - Protect (the rest of the options are set when add and append is selected
 5 - Grab test file from bug 39518
 6 - Import the records, ignoring items
 7 - Edit the test file and change some values for the 949 rows
 8 - Go to Acquisitions, find a basket for a vendor, add to basket from a new file
 9 - Stage the file to find matches (already imported above) and to replace
10 - Complete the orders
11 - View the record and confirm the new 949 are added
12 - Edit the 949 in the file again
13 - Apply patch, update database, restart all
14 - Edit overlay rules and remove the 'Staged Marc Import' rules, leaving only the 'Add to basket rules'
15 - Add to basket again using the updated file and confirm new 949 are added
16 - Success!

Signed-off-by: Benjamin Daeuber <BDaeuber@fargolibrary.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-19 16:07:57 +00:00
Olivia Reynolds dd7777c8b9
Bug 43313: Fix catalogue detail shelving location display
During the tidying up of Bug 41566, av_loc was accidentally changed to
map descriptions to codes, rather than vice-versa. This broke the
formatting of item permanent locations.

Test plan (for KTD):
1.  Navigate to an catalogue detail page, for example
    http://localhost:8081/cgi-bin/koha/catalogue/detail.pl?biblionumber=262
2.  Run the following SQL, replacing 262 with the biblionumber of your
    chosen page:
      UPDATE items SET location='CHILD' SET permanent_location='GEN' WHERE biblionumber=262;
3.  Refresh the page and verify the items' shelving locations display
    "(Children's area)" only.
4.  Apply patch and force refresh.
5.  Verify the shelving location now correctly displays "General
    stacks" and "(Children's area)" on separate lines.

Sponsored-by: Open Fifth
Signed-off-by: John Vinke <jvinke@austinseminary.edu>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-19 14:33:59 +00:00
Martin Renvoize bad9bb47ae
Bug 43215: preferences.js: Report one save confirmation per preference, not per checkbox option
Checkbox-group system preferences (multiple_sortable, ill_backends, and
the OPAC/staff interface language selectors) render one checkbox per
option. All the checkboxes for a given preference share its 'name'
attribute, but each has its own unique 'id'.

Saving such a preference produced one "Saved preference ..."
confirmation line per checkbox instead of a single line for the
preference as a whole, because KOHA.Preferences.Success() built the
message from each modified element's 'id' rather than its 'name'.

A related issue: the checkbox 'change' handler marked every
'.preference-checkbox' on the whole page as modified, regardless of
which preference it belonged to. This meant editing one checkbox-group
preference silently re-saved (and, before this patch, also reported as
saved) any other checkbox-group preference sharing the same tab - for
example, editing OPACLanguages would also touch the unrelated
StaffInterfaceLanguages preference on the I18N/L10N tab.

This patch:
* Scopes the 'modified' marking to checkboxes sharing the same
  preference name, so unrelated checkbox-group preferences on the same
  tab are left alone.
* Groups the save confirmation message by preference name
  (deduplicated), so each preference produces exactly one "Saved
  preference" line regardless of how many options it has.

Test plan:
1. Go to Administration > System preferences and search for
   OPACAuthorIdentifiersAndInformation.
2. Select two or more identifier types and click Save.
3. Confirm the confirmation banner shows a single "Saved preference
   OPACAuthorIdentifiersAndInformation" line, not one per selected
   identifier.
4. Drag one of the selected items to reorder it, click Save again,
   confirm you still get only one confirmation line, then reload the
   page and confirm the new order was kept.
5. Go to Administration > System preferences > I18N/L10N tab.
6. Toggle one of the checkboxes under "Enable the following languages
   on the OPAC" (OPACLanguages) and click Save.
7. Confirm the confirmation only reports OPACLanguages as saved - the
   staff interface language list (StaffInterfaceLanguages) should not
   appear in the message.
8. Reload the page and confirm the staff interface language selection
   is unchanged.
9. As a sanity check, modify an ordinary non-checkbox preference (e.g.
   a free text or yes/no preference) and confirm it still reports
   exactly one "Saved preference" line, same as before this patch.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-19 14:33:58 +00:00
Pedro Amorim 868751b221
Bug 43091: (RM follow-up) Give the OPAC self-renewal island a Pinia store
hydrate() only installs Pinia for an island when its config.stores is
non-empty. patron-self-renewal kept config: {} after islands-opac.ts
was split out, so it never got one.

http-client.js's post() calls submitting(), which needs Pinia's
useMainStore(). With none active, it throws before fetch() runs -
get() skips submitting() by default, so only the actual renewal
submission failed.

Test plan:
prove t/cypress/integration/Islands/SelfRenewal.ts

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-19 11:03:33 +00:00
Andrew Fuerste Henry d3d4a6ca96
Bug 40799: (QA Follow-up) tidy template file
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:34 +00:00
Hammat Wele be7436b429
Bug 40799: Loading spinner not removed because .cover-slider is now used instead of .cover-slides
After Bug 32642, the spinner on cover images is hidden by verify_cover_images() which removes the .cover-slides class from the cover container.

However, Bug 33848 modified the SCSS so that the spinner is now triggered by .cover-slider instead of .cover-slides.

As a result, the spinner is never removed, because verify_cover_images() only removes .cover-slides.

Test plan

1- Follow the test plan from Bug 32642.
   ==> The spinner is displayed and never disappears.
2- Apply the patch
3- Reload the page.
   ==> The spinner disappears once the cover image is loaded.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:33 +00:00
Owen Leonard 813fb3d143
Bug 43260: (follow-up) Move debug menu JS into js_includes.inc
The _() function isn't available to JS in intranet-bottom.inc.

To test, apply the patch and test that the correct strings are
translatable. In this example I'm testing fr-FR:

- Update a translation:

  > gulp po:update
  > cd misc/translator
  > perl translate update fr-FR

- Open the corresponding .po file for the strings pulled from
  the template e.g.  misc/translator/po/fr-FR-staff-prog.po
- Locate strings pulled from includes/js_includes.inc for
  translation, e.g.:

  #: koha-tmpl/intranet-tmpl/prog/en/includes/js_includes.inc:105
  #, fuzzy
  msgid "Disable custom CSS"
  msgstr "Désactiver "

- Remove the "fuzzy" line.
- Edit the "msgstr" string however you want (it's just for testing)
- Install the updated translation:

  > perl translate install fr-FR

Log in to the staff interface as a user with debug permission. Test the
debug menu in the header, confirming that the strings look correct and
that the toggles work correctly.

Switch to your translated templates and test again.

Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:32 +00:00
Owen Leonard b567a5589f
Bug 43260: Debug options in navigation bar untranslatable
These patches update the templates which control the display of the
debug menu item in the staff interface header. The strings need to be
wrapped in the _() i18n function.

The patch also corrects capitalization and uses the term "custom"
instead of "user."

A follow-up patch will move this JS into js_includes.inc so that the _()
is available. This patch is separate to make it easier to view the diff.

Testing requires the follow-up.

Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:31 +00:00
Baptiste Wojtkowski 3d41c25c08
Bug 43245: Redirect user if no email was provided
TO TEST:
0 - Apply patch
1 - Make sure OPACResetPassword is activated
2 - Go to that good old Henry Acevedo's page and reset their password
3 - Notice you have been redirected with an error message telling you
have no email

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:30 +00:00
Lucas Gass 74130f08df
Bug 42112: Add option when changing a patron's category: allow choosing what to do for the expiry date and messaging preferences
To test:
1. APPLY PATCH, updatedatabase, restart_all
2. Find 2 new system preferences UpdateDateExpiryOnCategoryChange and UpdateMessagingPrefsOnCategoryChange
3. Each was the same options:
    -Never update
    -Always ask, default to no
    -Always ask, default to yes
    -Always update without asking

4. Go to  Administration > Patron categories
5. Edit or create some categories with different Enrollment periods and messaaging preferences
6. Try each of the options for BOTH system preferences, making sure they work as described.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:28 +00:00
Hammat Wele 6490728051
Bug 33758: Add a parameter to use the intranet_catalog_biblio_enhancements_toolbar_button Plugin hook
This patch adds a parameter to call the method intranet_catalog_biblio_enhancements_toolbar_button with a biblionumber in the page catalogue/detail.pl.

Modification of cat-toolbar.inc to display new buttons correctly.

To test :
1. Apply the patch
2. Take a plugin who implements the method intranet_catalog_biblio_enhancements_toolbar_button
3. Check if the parameter biblionumber is passed correctly at this method
4. Create the new button in HTML in the plugin method
(button must be like the ones that are in the toolbar of the page detail.pl)
5. Go to the page in browser and check if the new button is displayed

Signed-off-by: Roman Dolny <roman.dolny@jezuici.pl>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:19 +00:00
Martin Renvoize 1e0442b847
Bug 41105: (QA follow-up) DRY out gender label rendering
The gender-code-to-label mapping (F/M/O -> Female/Male/Other) was
duplicated between the results table cell and the edit-form select
options in modborrowers.tt. Extract it into a shared
patron-sex-label.inc so there is a single place defining the mapping,
and drop the now-unused "lib" values from the sex options in
tools/modborrowers.pl (labels are supplied by the include, keyed on
the option value, rather than by Perl).

Test plan:
1. Navigate to Patrons and click Search, to display a list of patrons.
2. Select all results and click "Batch patron modification".
3. Verify the "Gender" column displays Female/Male/Other correctly.
4. Verify the "Gender" edit dropdown still offers Female/Male/Other
   and saves correctly.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:18 +00:00
Martin Renvoize b51a3f111a
Bug 41105: (QA follow-up) Fix gender label translation
The batch patron modification "Gender" column and edit dropdown
hardcoded "Female"/"Male"/"Other" as data passed from
tools/modborrowers.pl, and the "Other" gender label was displayed as
plain text.

Values coming from Perl as template data are never picked up by the
PO extractor, so the gender select options in the edit form could
never be translated. Elsewhere in Koha (moremember.tt,
moremember-brief.tt, memberentrygen.tt, opac-memberentry.tt) the
"Other" gender label is wrapped with tp('gender', 'Other') to give
translators context, since "Other" is ambiguous out of context.

This makes the "Gender" dropdown options translatable directly from
the template, and aligns "Other" with the existing tp('gender', ...)
convention used everywhere else gender is displayed.

Test plan:
1. Navigate to Patrons and click Search, to display a list of patrons.
2. Select all results and click "Batch patron modification".
3. Verify the "Gender" column and "Gender" edit dropdown still work as
   expected.
4. Confirm (e.g. via the .pot file or misc/translator/translate) that
   "Female", "Male" and the "Other" (gender) msgctxt string are now
   extracted for translation from this template.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:17 +00:00
Olivia Reynolds 0bb26abd5a
Bug 41105: Add gender to batch patron modification
This patch adds the ability to batch-edit the gender field for patrons.

Test plan:
1.  Ensure there are a number of patrons in the database.
2.  Apply patch.
3.  Navigate to Patrons and click Search, to display a list of patrons.
4.  Select all results and click "Batch patron modification".
5.  Verify the "Gender" column is displayed.
6.  Verify the "Gender" column may be toggled under the "Columns"
    dropdown.
7.  Select a subset of the patrons for modification.
8.  Verify there is a "Gender" option beneath the table.
9.  Select "Female" as the gender, and click "Save".
10. Verify the gender of all selected patrons was set to "Female".
11. Repeat with "Male" and "Other" as the gender.
12. Repeat with clearing the gender field by ticking the checkbox next
    to the dropdown and saving. Verify the gender field is blank for
    each selected patron.

Sponsored-by: Open Fifth
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Amit Gupta <amit.gupta@informaticsglobal.ai>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-14 12:09:15 +00:00
Owen Leonard 55bc6f01e0
Bug 41842: (follow-up) Ensure that tidy doesn't trim wanted whitespace
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:08:01 +00:00
Owen Leonard 1b00485b27
Bug 41842: (follow-up) Make sure this space doesn't get tidied
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:07:59 +00:00
Martin Renvoize 3cd648d52f
Bug 41842: Use space-dash-space separator between course name and section
The staff interface templates were using a bare hyphen with no spaces
when displaying course name and section together, while the OPAC templates
(Bug 42654) use ' - ' (space-dash-space). This brings the staff interface
into alignment with the OPAC convention for consistency and readability.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:07:58 +00:00
Owen Leonard 303ba57409
Bug 41842: Improve translation of course reserves headings
This patch adds some use of I18N functions to course reserves templates
in order to improve the process of translation by adding context and
placeholders. The patch also rewords some headings for clarity and
consistency.

To test, apply the patch and go to course reserves.

- Add a course if necessary.
- Click the course to view it.
- On the course details page, confirm that the page title, breadcrumbs,
  and heading look correct.
- Click "Edit" in the toolbar.
- Check the page title, breadcrumbs, and heading again.
- Return to the course details and click "Add reserves" and check that
  page.
- Submit a barcode or biblionumber and check that page.
- Test the "Batch add reserves" page.

To test the improved I18N, apply the patch and test that the correct
strings are translatable. In this example I'm testing fr-FR:

- Update a translation:

    > gulp po:update
    > cd misc/translator
    > perl translate update fr-FR

- Open the corresponding .po file for the modified strings, e.g.
  fr-FR-messages.po.
- Locate strings pulled from course reserves templates for
  translation, e.g.:

    #: koha-tmpl/intranet-tmpl/prog/en/modules/course_reserves/course.tt:10
    #: koha-tmpl/intranet-tmpl/prog/en/modules/course_reserves/course.tt:42
    #: koha-tmpl/intranet-tmpl/prog/en/modules/course_reserves/course.tt:56
    #, fuzzy, perl-brace-format
    msgid "Edit course {course_name}"
    msgstr "Modifier {course_name}"

- Remove the "fuzzy,"
- Edit the "msgstr" string however you want (it's just for testing)
- Install the updated translation:

  > perl translate install fr-FR

Switch to the translation you updated. Walk through the process of
editing a course and adding course reserves to confirm that your translated strings show up.

Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 16:07:55 +00:00
Katrin Fischer bb53e653f3
Bug 43239: (QA follow-up) Rephrase hint on subscription form
This is to clarify that the item's current item type will
not be changed, no matter what settings have been used in
the subscription.

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:50 +00:00
David Nind 5005019b5d
Bug 43239: (follow-up) Update wording for hint
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:50 +00:00
Emmi Takkinen 02515ebcc7
Bug 43239: Preserve item item type if previousitemtype column is undefined
It is possible to create serial item with wrong itemtype if syspreference
makePreviousSerialAvailable is enabled and field "item type for older issues"
isn't filled when creating a subscription for biblio record. This happens
when multiple items are created. In installations where itemtypes differ
between items and biblios, this causes data inconsistencies and leads to
errors in biblios Holdings table.

This patch changes behaviour of serials-edit.pl so that if
makePreviousSerialAvailable is enabled and subscriptions previousitemtype
column is NULL, previous serial items itype column is preserved. It also
adds a hint text to subscription form about this change.

To test:
1. Enable systempreference makePreviousSerialAvailable.
2. Create new biblio record.
3. Create a new subscription for biblio record you made, select option
"Create an item record", select different item type from "Item type"
selection than biblio record has but leave selection "item type for older
issues" empty.
4. Receive a serial item for subscription. Check from biblio records
Holdings table that its item type matches item type selected in step 3.
5. Now receive 3 serial items. After creating them check Holdings table again.
=> Note that first item created now has same item type as biblio record.
6. Apply this patch, restart services.
7. Create new subscription, fill needed fields as in step 3.
=> Note that there is a new hint text after field "item type for older issues".
8. Repeat steps 4. and 5.
=> Note that now all items have same item type.

Sponsored-by: Koha-Suomi Oy
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-12 15:49:49 +00:00
Martin Renvoize 8145e26a93
Bug 42471: (follow-up) prevent XSS in suggestion status
The custom/authorized-value status branch concatenated row.status
directly into a class="..." attribute string. escape_str() only
escapes &, <, > (not quotes), so a status code containing a double
quote could still break out of the attribute.

Build the status <span> via DOM APIs instead, the same way the
reason field was fixed: fixed statuses get a hardcoded class, and
the free-form status code goes into a data-status attribute via
dataset, which the DOM escapes safely regardless of content.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:35 +00:00
David Cook 222dac6c3c
Bug 42471: (follow-up) prevent XSS in suggestion reason
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:34 +00:00
Jonathan Druart acf1184436
Bug 42471: Prevent XSS in suggestion.tt
escape_str all the things

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-11 12:39:33 +00:00
Owen Leonard 3b5f16adc6
Bug 40498: Improve style of list transfer form
This patch makes some style changes to the list transfer form. Since it
needs the same CSS that is used on the circulation page, the CSS block
is moved from circulation.tt to staff-global.scss.

The patch also changes the behavior of the form so that the "New owner"
line doesn't appear until after a patron has been selected.

To test, apply the patch and rebuild the staff interface CSS.

- If necessary, create a public list.
- From the list of public lists, click the "Transfer" button.
- Verify that the form looks correct. The patron search field should
  match the search field shown when you navigate directly to
  circulation.pl
- Search for a patron who has permission to manage public lists.
  - After you select a patron, a new line should appear:
    "New owner: [name]"
- Click "Transfer" and confirm that the process works correctly.

Sponsored-by: Athens County Public Libraries
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:07:36 +00:00
Jennifer Sutton 4110bcf3bf
Bug 30759: Add hint about the data that is sent via the Google Books API to OPACSuggestionAutoFill
Add information about the data that is sent to Google if the
OPACSuggestionAutoFill system preference is enabled.

Test plan:
1. Go to Administration > System preferences.
2. Search for the OPACSuggestionAutoFill system preference.
3. Note that there is no note about the data that is sent to
   Google if the system prference is enabled.
4. Apply the patch.
5. Refresh the page.
6. There is now a note about the data that is sent to Google.
7. Check that it reads well and makes ense.

Sponsored-by: Catalyst IT
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:07:36 +00:00
Martin Renvoize df7e600587
Bug 41649: Add option to set magnetic flag for item itemtypes
This patch adds the ability to set an item type as magentic for SIP
response purposes.

Test plan:
1) Run included database updates
2) Navigate to admin > itemtypes
3) Edit/Add an itemtype and scroll to the 'Sip media types' input
4) A new 'Sip magnetic' checkbox should be available
5) Confirm setting/unsetting it works as expected
6) The SIP magnetic flag bit should respect the setting
7) To test SIP functionality:
   a) Start the SIP server (e.g., koha-sip service)
   b) Create an item with an itemtype that has sip_magnetic checked
   c) Use misc/sip_cli_emulator.pl to send a checkout request:
      perl misc/sip_cli_emulator.pl -a localhost -p 6001 -su <sip_username> -sp <sip_password> -l <location_code> --patron <patron_cardnumber> --password <patron_password> --item <item_barcode> -m checkout
   d) Check the SIP response to ensure it handles magnetic media correctly (e.g., no desensitization flag)

Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Marcus Michel <marcus.michel@rbkc.gov.uk>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:07:33 +00:00
Olivia Reynolds 51e3d5435a
Bug 40668: Don't depend on checkboxes existing in drawCallback
The checkboxes this callback listens to events on are conditionally
rendered, depending on whether the user has permission to edit each
item. When moving from a page with no checkboxes displayed to one with
checkboxes displayed, the checkbox elements may not exist at the time of
this callback, so the listener is not attached and the checkboxes are
inoperable.

This patch fixes this by using a delegated event handler on the row,
which doesn't depend on the checkbox existing at the time.

Test plan:
1.  Enable the system preference EnableItemGroups.
2.  Set up a non-super-librarian patron, with permission to:
    - view the catalogue (catalogue)
    - create update and delete item groups (manage_item_groups)
3.  Place this patron's library in a group by itself, with "limit item
    editing" enabled. The patron should only be able to edit items from
    their own library.
4.  Pick an item in the catalogue, and add at least 40 items to it from
    a library the patron cannot edit items from. Add at least one item
    from the patron's library that they can edit. The 40 items are to
    ensure there is a complete (20 item) page that the patron cannot
    edit anything on.
5.  Create an (empty) item group on this catalogue entry.
6.  Log in as the unprivileged patron and navigate to the holdings view
    for the relevant catalogue entry.
7.  Navigate through the holdings table pages until there is a page with
    no checkboxes.
8.  Navigate to a table page with a checkbox. Select one of the
    checkboxes, and verify no actions appear at the top of table, even
    though you should have permission to add this item to a group.
9.  Apply this patch, and hard refresh to load the new JavaScript.
10. Repeat steps 6-8, verifying the checkbox now appears correctly.
11. Verify you can add the item to an item group using the now-appearing
    action.

Sponsored-by: Open Fifth
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:28 +00:00
Pedro Amorim 60725ab4f1
Bug 43204: Fix ILL availability Source column ignoring deep link
ill-availability.js renders results from ILL availability plugins.
Each result can carry a `url` (deep link to the record) and an
`opac_url` (generic fallback). The Title column correctly prefers
`url`, but the Source column links to `opac_url` unconditionally and
never checks `url`, so results always link to the bare OPAC URL even
when a deep link is available.

Make Source prefer `url`, falling back to `opac_url`, same as Title.

To test:
1) Install the latest release of the plugin:
   https://github.com/openfifth/koha-plugin-ill-avail-z3950/releases
2) Enable ILLModule, ILLCheckAvailability.
3) Set AdditionalFieldsInZ3950ResultSearch = 856$a, 999$c, 001.
4) Add Z39.50 server: Name KTD, Hostname localhost, Port 2100,
   Database biblios, Syntax MARC21/USMARC.
5) Configure the ILL z3950 plugin: tick the 'KTD' box, set bib ID
   field 999$c, deep link
   http://localhost:8081/cgi-bin/koha/opac-detail.pl?biblionumber=source_record_id,
   OPAC URL http://localhost:8080, tick the last 3 display
   checkboxes, leave Partner ID blank.
6) Add a new ILL request: type book, ISBN 0879307447, cardnumber 42,
   destination library Centerville.
7) Go to availability search, confirm the result links to the
   correct deep-linked biblio, not a bare fallback.

Signed-off-by: Edith Speller <Edith.Speller@ukhsa.gov.uk>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:27 +00:00
Jonathan Druart c39aa5f6a7
Bug 42451: Remove duplicate success message
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:26 +00:00
Jonathan Druart fb0fb890e2
Bug 42451: Remove JS error when converting a report
Test plan:
Create a report with: SELECT marcxml from biblioitems
Hit /reports/guided_reports.pl?op=list
Notice the "Update SQL" button in the "Update" column, Click "Update"
=> JS error
"Uncaught TypeError: can't access property "backdrop", this._config is undefined" (in Firefox)
And nothing happens
Apply this patch, reload, click the button
=> Success, the report is updated

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:25 +00:00
Laura_Escamilla e9b9509461
Bug 42235: Add message type header to OPAC messaging table
The OPAC messaging table includes an empty first column header. This column
contains the message type, such as Item due, Advance notice, Hold filled, and
Auto renewal. Because the header only contains a non-breaking space, it is
flagged by accessibility tools as an empty <th> element.

Add a translated "Message type" label to the first column header so it has
meaningful accessible text.

Test plan:
1. Log in to the OPAC
2. Go to "Your messaging settings"
3. Inspect the messaging table header
4. Confirm the first column header contains no meaningful text

Apply the patch:
5. Reload the page
6. Confirm the first column header contains "Message type"
7. Confirm the messaging table still displays correctly
8. Run an accessibility checker and confirm the empty table header error is resolved
9. Sign off and have a wonderful day! :D

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:24 +00:00
Laura_Escamilla 444cad89c7
Bug 42235: Add accessible label to DataTables control column in OPAC messaging
The OPAC messaging table includes a DataTables responsive control column
with no header text. This results in an empty <th> element and an empty
aria-label, which is flagged by accessibility tools.

Add a translated "Expand" label to the control column header so it has
meaningful accessible text.

Test plan:
1. Log in to the OPAC
2. Go to "Your messaging settings"
3. Inspect the messaging table header
4. Confirm the control column header contains no text

Apply the patch:
5. Reload the page
6. Confirm the control column header contains "Expand"
7. Confirm responsive row expansion still works
8. Run an accessibility checker and confirm the error is resolved
9. Sign off and have a wonderful day!

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:23 +00:00
Martin Renvoize 4deb199163
Bug 42656: (QA follow-up) Make error status persistence consistent, with a full trace, across FTP, SFTP and Local
Two related inconsistencies remained across the three transport
backends' error-handling paths:

1) Only Koha::File::Transport::SFTP's _abort_operation() persisted an
   "errors" status snapshot to the status column on every failed
   operation. FTP never did, and Local had no _abort_operation() at
   all - so an SFTP transport's displayed status could reflect a
   single transient failure from real usage (e.g. an EDI cron job)
   while the exact same failure on FTP/Local left the stored status
   untouched (stale, possibly still showing the last explicit
   test_connection() result). This is exactly the kind of unclear
   status reporting bug 42656 is about.

2) FTP's _abort_operation() carried its extra detail under an
   operation_params key, while SFTP (and Local's plain add_message
   calls) used path. The change_directory() success payload had the
   same split: FTP used directory, SFTP and Local used path. The
   admin template's change_directory row display depended on FTP's
   mismatched key names, which meant it silently failed to show the
   tested directory for SFTP transports.

Adds a shared _record_error($operation, \%payload) to the
Koha::File::Transport base class - add_message() plus status
persistence - and routes all three backends' _abort_operation() (Local
gains one) through it. Renames FTP's operation_params/directory keys
to path throughout, matching SFTP and Local, and simplifies the
template to read operation.detail.path unconditionally instead of
ORing two differently-named keys.

_record_error() persists the full trace of operations recorded on the
transport object so far this session (every success leading up to the
failure), not just the failing operation in isolation - the same
"full trace" shape TestTransport::process() already builds for an
explicit test_connection() run. A long-lived transport used across a
multi-step operation (e.g. an EDI download loop touching several files
before one fails) will therefore show every successful step leading up
to the failure. It also logs the failure - including the built trace -
via Koha::Logger at warn level, so it's visible in the Koha logs
without needing to query the transport's status column.

Test plan:
1. prove -r t/db_dependent/Koha/File/ t/db_dependent/Koha/BackgroundJob/TestTransport.t t/db_dependent/Koha/Edifact/Transport.t t/db_dependent/api/v1/file_transports.t
   => All tests successful (48 tests total), including:
      - new "_abort_operation persists status consistently" subtests
        in FTP.t, SFTP.t and Local.t that reload the transport from
        the DB after a simulated failure and confirm the status
        column was updated with the correct operation code and path
        detail;
      - a new "_record_error() tests" subtest in Transport.t proving
        the persisted trace includes a prior success message plus the
        failure (not just the failure alone), and that a warn-level
        log line mentioning the operation and error was emitted.
2. koha-qa.pl -v 2 --more-tests
   => [PASS], no critic/pod warnings.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:21 +00:00
Martin Renvoize f8cf2aea42
Bug 42656: (QA follow-up) Fix dead status code in file_transport_test.inc
Two issues in the operation_description BLOCK's status text, both
flagged in review:

1) The IF/SET that computed the " passed."/" failed." status text sat
   between the SWITCH statement and its first CASE. Template Toolkit
   only executes CASE-labelled content inside a SWITCH block, so this
   was dead code - status was never actually set, and every operation
   row silently rendered with no passed/failed text at all. It also
   checked operation.error, a field that doesn't exist on the
   operation hash (the error message lives under operation.detail.error,
   and whether the operation failed is operation.status eq 'error');
   even if the code path were reachable it would always have taken the
   "passed" branch.

2) Relying on a leading space baked into the " passed."/" failed."
   string literals to separate them from the preceding </span> is
   fragile. Made the space explicit in the markup instead, and dropped
   the leading space from the string values.

Moves the status computation above the SWITCH (using operation.status),
and adds an explicit space before [% status | html %] on every CASE line.

Also adds t/db_dependent/Koha/BackgroundJob/TestTransport.t, which was
entirely missing: it exercises process() end-to-end (enqueue, then
process, then reload both the job and the transport) and confirms the
persisted trace records every operation in sequence - successes before
the failure that ended the run - rather than collapsing to just the
final error.

Test plan:
1. prove t/db_dependent/Koha/BackgroundJob/TestTransport.t
   => All tests successful, confirming process() persists the full
      operation sequence (order preserved, at least one success and
      one error present) on both the job and the transport's own
      status column.
2. Manually rendered the fixed operation_description BLOCK with
   Template Toolkit against mock operations (mixed success/error) and
   confirmed every row now shows "Connection passed.", "Change
   directory (/incoming) passed.", ..., "Change directory (/outgoing)
   failed.- error:No such directory" - status text present with
   correct spacing, where before the fix no status text rendered at
   all.
3. prove -r t/db_dependent/Koha/File/ t/db_dependent/Koha/Edifact/Transport.t t/db_dependent/api/v1/file_transports.t
   => All tests successful (47 tests total), no regressions.
4. koha-qa.pl -v 2 --more-tests
   => [PASS], no critic/pod warnings.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:20 +00:00
Nick Clemens 7d6dafef6d
Bug 42656: Improve file transport test display
This patch displays the directory tested in the background jobs results

It updates the language when test results are not stored for the transport and
links to the job when results are stored

To test:
1 - Setup an ftp file transport with good credentials
2 - Enter non-existent directories in incoming/outgoing
3 - Save
4 - Verify on save 'Never used' shows for status
5 - Refresh the page, status now:
     Connection ok
     Change directory ok
     Change directory failed
     Change directory ok
     Change directory failed
6 - Apply patch, restart all
7 - Edit/save the transport again, change nothing
8 - Confirm the page says 'No test results stored'
9 - Reload the page
10 - Confirm results are now:
     Connection ok
     Change directory ok
     Change directory failed
     Change directory ok
     Change directory failed
     Test job details
11 - Click on the job details link
12 - Confirm actual directory and errors are shown
13 - Edit the transport, use existing directories
14 - Save, reload
15 - Confirm the success results and link t background job

Signed-off-by: John Vinke <jvinke@austinseminary.edu>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-06 16:05:19 +00:00
Casey Conlin c267c679a1
Bug 16631: Fix: Remove TT tags from kohaTable() initialization in guided_reports_start.tt
Sponsored-by: Ramapo Catskill Library System

Bug 16631: Update saved reports table to use use named DataTables columns.

RM amended: Fix commit title

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-04 10:20:59 +00:00
Martin Renvoize 0d0ba262fe
Bug 42915: (QA follow-up) Defer coded_values declaration until document ready
holds.js declared `coded_values` as a bare top-level global, evaluated
immediately at script-parse time, reading `all_libraries` which is only
ever defined by the including template (request.tt, or
patron-detail-tabs.inc for circulation.tt/moremember.tt). This works
today only because those templates happen to emit their `all_libraries`
script block before Asset.js("js/holds.js") in the rendered HTML - a
fragile, easy-to-break ordering dependency between separate template
files, not something holds.js itself can guarantee.

Move the assignment into the existing $(document).ready() handler,
setting it explicitly on `window` so it remains visible as a global to
datatables.js's build_query(), which reads `coded_values` unqualified.
This defers evaluation until all synchronous inline scripts (including
whichever template defined all_libraries) have already run, regardless
of future include/ordering changes.

To test:
1. Place holds on a title for two different pickup libraries
2. Confirm the holds table on reserve/request.tt, the patron's Holds
   tab (circulation.pl and moremember.pl) all load with no console
   errors
3. Confirm filtering the holds table by pickup library name/branchcode
   still works on all three pages

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-04 10:20:58 +00:00
Martin Renvoize c7d13ee7a3
Bug 40445: (follow-up) Move TT values out of kohaTable script blocks
xt/tt_kohaTable_tidy.t forbids mixing Template::Toolkit tags with
.kohaTable() calls inside the same <script> block, since such blocks
are expected to be pure JS. The cashup modal init calls in
pos/register.tt and pos/registers.tt embedded TT-derived values
(bankable amount, register float, reconciliation note settings,
cashup progress) directly alongside kohaTable() initialisation,
tripping the check.

This moves those TT expressions into the existing TT-tag-only
<script> block that precedes the kohaTable block in each template,
exposing them as a plain JS object (cashupModalData) that the
kohaTable block then reads.

Test plan:
1. Apply the patch.
2. prove xt/tt_kohaTable_tidy.t -- register.tt and registers.tt
   should no longer be listed among the failures.
3. Load the POS register and registers pages, confirm the trigger
   and confirm cashup modals still receive the correct bankable
   amount, register float, and reconciliation note settings.

Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-04 10:20:56 +00:00
Nick Clemens 0905d6a89f
Bug 42766: (QA follow-up) Add 'SCRIPTS' to log viewer
Apply this patch and confirm you can limit to 'Scripts' and that 'Scripts' is not in
all caps in the results

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-04 10:20:54 +00:00
Martin Renvoize 57cceec6bc
Bug 42766: Add ScriptLog system preference
Adds a new YesNo system preference 'ScriptLog' in the Logging section
of system preferences, adjacent to CronjobLog. When enabled, the start
and end of non-cron Koha scripts (those using bare 'use Koha::Script'
rather than 'use Koha::Script -cron') will be recorded in the action
log under the SCRIPTS module.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-04 10:20:46 +00:00
Paul Derscheid 8ebc1d0f2b
Bug 43091: Stop emitting staff-only Vue islands into the OPAC dist
Both islands builds share modules/islands.ts, which hardcodes every
island. The OPAC compilation therefore emits staff-only lazy chunks
(acquisitions-menu, vendor-menu, admin-menu) into
koha-tmpl/opac-tmpl/bootstrap/js/vue/dist/, and the OPAC islands.esm.js
bundles the staff Pinia stores.

- split modules/islands.ts into shared machinery and per-application
  entry points (islands-intranet.ts, islands-opac.ts)
- declare each application's islands as a Map literal and feed it
  through registerIsland(), the same path plugin islands take
- pass store definitions into hydrate() instead of importing every
  store in the shared module
- keep the full plugin import surface (registerIsland, hydrate, Vue
  re-exports) on both entries via star re-exports
- point the rspack islands entries at the per-application modules

Test plan:
1. yarn build
2. ls koha-tmpl/opac-tmpl/bootstrap/js/vue/dist/
   => only islands.esm.js and a patron-self-renewal chunk are emitted
3. ls koha-tmpl/intranet-tmpl/prog/js/vue/dist/
   => acquisitions-menu, vendor-menu and admin-menu chunks are still
   present
4. In the staff interface, visit pages using the acquisitions, vendor
   and admin menu islands and verify they render
5. Enable self-renewal for a patron's category and put the patron
   inside the availability window, e.g.:
   UPDATE categories SET self_renewal_enabled = 1
     WHERE categorycode =
     (SELECT categorycode FROM borrowers WHERE userid = 'koha');
   UPDATE borrowers
     SET dateexpiry = DATE_ADD(CURDATE(), INTERVAL 7 DAY),
     debarred = NULL WHERE userid = 'koha';
6. Log into the OPAC as that patron and open 'your summary'
   => the patron-self-renewal chunk loads from
   /opac-tmpl/bootstrap/js/vue/dist/ and the self-renewal modal
   completes successfully

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-03 13:00:36 +00:00
Owen Leonard be1bc44511
Bug 43206: cn_browser plugin red background on exact match is hard to read
This patch updates the cn_browser plugin output so that table rows are
highlighted using row classes and in colors which have sufficient
contrast.

To test, apply the patch and set your 952$o tag to use the cn_browser
plugin:

- Administration -> MARC bibliographic frameworks -> BKS -> MARC
  Structure -> Tag 952 -> Edit subfields.
  - Under the "Full call number" tab (o), set the "Plugin" dropdown to
   "cn_browser.pl" and save your changes.
- Go to Cataloging and locate a bibliographic record using the
  cataloging search.
- Add or edit items. NOTE: In the testing data there is only one item
  with a callnumber and it is "FIC/kas"
  - In the "o - Full call number" field, type "FIC" and then click the
    plugin editor image.
    - You should see the record with the "FIC/kas" call number and a
      green row right above it (indicating where an item with
      the call number "FIC" would be in the results).
  - Revise your search using the form at the top, entering "FIC/kas".
    - The record row should now be highlighted in pale yellow.

Sponsored-by: Athens County Public Libraries
Signed-off-by: Gretchen <maxeinergl@gcc.edu>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-03 13:00:35 +00:00
Owen Leonard 76167f6cfe
Bug 43177: Use archived link for Bridge Material Type Icon Set
This patch updates the About page in the section for the Bridge Material
Type Icon Set. The link is updated to use the last valid saved version
on the Internet Archive.

Sponsored-by: Athens County Public Libraries
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-03 13:00:29 +00:00
Paul Derscheid 53524b4824
Bug 43174: (QA follow-up) Restore user choices on redraw independent of search state
To test:
- cypress run --spec t/cypress/integration/KohaTable/PatronSearch_spec.ts
- cypress run --spec t/cypress/integration/KohaTable/KohaTable_spec.ts

Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:30 +00:00
Jonathan Druart 684c6cb96a
Bug 43174: Restore defer loading for patron searches
On the hold request and the patron search pages, the search is not
deferred when a state exists.

Coming from
  commit 2a34413601
  Bug 41604: Save user decision per column when visibility changes
-        if (default_save_state_search) {
+        if (default_save_state || default_save_state_search) {
             $("#" + settings.nTable.id).data("loaded_from_state", true);
-        } else {
+        }

+        if (!default_save_state_search) {
             delete state.search;
             state.columns.forEach(c => delete c.search);

I think this was a leftover from another try to fix bug 41604. I don't
see how it could help in the context of saving the user decision.
In the different patches from bug 41604 we don't test loaded_from_state.

Test plan:
Go to /cgi-bin/koha/members/members-home.pl
=> The table is not displayed
Search for patrons
=> The table is displayed
Reload the page
=> Without this patch the table is displayed
=> With this patch the table is not displayed

If you have "Save search state on page change" enabled for this table,
the table should be displayed if a previous search was made.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:29 +00:00
Jonathan Druart 21e34086ca
Bug 43053: Simplify code, only 1 return statement
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:26 +00:00
Matt Blenkinsop 2ad5ba09cb
Bug 43053: Fix display of vendor payment methods
Test plan:
1) Add multiple vendor payment method authorised values
2) Create a vendor and add multiple payment methods
3) Click to edit, the payment method will be displaying one option of a "|" concatenated string
4) Apply patch and run yarn js:build
5) Hard refresh the browser, the payment methods should now display correctly
6) Edit the payment methods and save, the saved changes should be correctly displayed on the vendor details page
7) Add a new vendor with multiple payment methods, it should save correctly

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:25 +00:00
David Nind 4b7da59db5
Bug 43173: Update the terminology for the log viewer - "cardnumber" to "card number"
Update the log viewer to change "Modify cardnumber" to
"Modify card number", as per the terminology guidelines
https://wiki.koha-community.org/wiki/Terminology#C

Test plan:
1. Edit a patron and change their card number under the library
   management section.
2. Go to Tools > Additional tools > Log viewer.
3. Note under the actions section that there is an action:
   Modify cardnumber
4. Click "Submit" to see the log viewer results.
5. Note that there is an entry for the patron card number change
   with the action: "Modify cardnumber".
6. Apply the patch.
7. Refresh the log viewer page.
8. Note that "Modify cardnumber" is now "Modify card number"
   in both places.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Gretchen <maxeinergl@gcc.edu>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:23 +00:00
Kyle M Hall 73380b410c
Bug 42988: Default holds_get_captured to yes for new SIP accounts
The account editor preselects "No" for "Holds get captured" when
creating a new SIP account, but the SIP checkin default is to capture
holds. This patch makes the editor default the option to "Yes" so a
new account behaves the same as one that never set the option.

Test Plan:
1) Apply this patch
2) yarn js:build
3) Restart all the things!
4) Create a new account in the SIP2 administration module
5) Note "Holds get captured" defaults to "Yes"!

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:17 +00:00
Laura_Escamilla ad1d40f0b7
Bug 43134: Add missing colons to OPAC advanced search section headings
To test :
1. Apply the patch
2. Go to the OPAC advanced search page http://kohadev.mydnsname.org:8080/cgi-bin/koha/opac-search.pl
3. Click More options
4. Notice that all section titles now use colons
   - "Search for:" = colon
   - "Limit to any of the following:" = colon
   - "Location and availability:" = colon
   - "Sort by:" = colon
   - "Publication range" = colon
   - "Language" = colon
   - "Audience" = colon
   - "Content" = colon
   - "Format" = colon
   - "Additional content types..." = colon
5. Sign off and have an incredible day! :)

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:15 +00:00
Owen Leonard 32e16ca89a
Bug 43192: Cast escape_str(obj) arg to string to use escapeHtml func
The escape_str function in the OPAC requires the argument to be a string,
and will throw a fatal error if passed a Number. This is because
String.prototype.escapeHtml is created by Koha and is not a JS standard.
This patch converts the object to a string before applying escapeHtml.

To test, apply the patch and log in to the OPAC.

- If necessary, add a list.
- Search for records in the catalog and add one or more of the results
  to your new list.
- Go to Lists -> Your lists.
- In the list of your lists, click the "Delete" link for the list you
  added records to.
  - You should see a confirmation modal, "Are you sure you want to
   delete this list?" showing the name of the list and the number of
   items on it.
  - Clicking "Yes, delete" should delete the list.

Sponsored-by: Athens County Public Libraries
Signed-off-by: Roman Dolny <roman.dolny@jezuici.pl>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-31 13:40:08 +00:00
Martin Renvoize 4b23e5c5d1
Bug 41410: (follow-up) Decouple exclusivity from LocalHoldsPriority
LocalHoldsExclusivity and LocalHoldsPriority are adjacent but distinct
features: priority alters *which patron's hold* gets filled first, while
exclusivity restricts *which items* may fill a hold during a time window.
Each should be usable independently of the other.

Changes:
- Rename LocalHoldsPriorityExclusivityPeriod to LocalHoldsExclusivityPeriod
- Add LocalHoldsExclusivityPatronControl (PickupLibrary/HomeLibrary)
- Add LocalHoldsExclusivityItemControl (homebranch/holdingbranch)
- HoldsQueue: add _flag_local_holdgroup_matches() that flags
  local_holdgroup_match on allocated items using hold-group matching
  and the new exclusivity control prefs, regardless of LocalHoldsPriority
- Reserves: CheckReserves exclusivity check now computes its own
  "is this item local" using the new prefs and hold-group siblings,
  independent of the LocalHoldsPriority matching variables
- Atomicupdate handles both fresh install and rename-from-old-pref paths
- Pref UI note clarifies independence from LocalHoldsPriority

Test plan:
1. Apply patch, run updatedatabase.pl
2. Verify three new sysprefs exist in Administration > System preferences
   > Circulation: LocalHoldsExclusivityPeriod, LocalHoldsExclusivityPatronControl,
   LocalHoldsExclusivityItemControl
3. Set LocalHoldsPriority to "Don't give" (None)
4. Create a library hold group with at least two libraries (e.g. Lib-A, Lib-B)
5. Create a third library (Lib-C) NOT in the hold group
6. Create an item at Lib-B
7. Place a hold for a patron at Lib-A (pickup at Lib-A)
8. Set LocalHoldsExclusivityPeriod to 7, PatronControl to HomeLibrary,
   ItemControl to homebranch
9. Run the holds queue builder (misc/cronjobs/holds/build_holds_queue.pl)
10. Verify hold_fill_targets.local_holdgroup_match = 1 for that hold
    (item at Lib-B is in the same hold group as patron at Lib-A)
11. Check in the item at Lib-C — it should NOT fill the hold (exclusivity
    blocks the non-local item within the 7-day window)
12. Check in the item at Lib-B — it SHOULD fill the hold (local match)
13. Reset: delete the hold, create a new one with a patron at Lib-C
    (pickup at Lib-C). Run the queue again.
14. Verify hold_fill_targets.local_holdgroup_match = 0 for this hold
15. The item at Lib-B should now fill this hold at Lib-C checkin
    (non-local patron, no exclusivity protection)
16. Set LocalHoldsExclusivityPeriod to 0 — verify non-local items can
    fill holds normally regardless of hold_fill_targets flag
17. prove t/db_dependent/Holds/LocalHoldsPriority.t — passes
18. prove t/db_dependent/HoldsQueue.t — passes
19. prove t/db_dependent/Reserves.t — passes

Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:12 +00:00
Martin Renvoize a2ef73fe95
Bug 41410: Add local holds priority exclusivity period
When LocalHoldsPriority is enabled, the holds queue picks a local-group
item for eligible holds.  Until now there was nothing to reserve that
priority at checkin time: if a non-local item was returned first, it
would happily fill the hold and the local-priority decision was lost.

This patch adds a time-bounded exclusivity window so that, for a
configurable number of days after a hold is placed, a hold whose queue
target is a local-group item will not be filled by a non-local item.

Changes:
 - C4/HoldsQueue.pm: in MapItemsToHoldRequests, flag %item_map entries
   that matched on local library (GiveLibrary/GiveLibraryAndGroup) or
   local hold group (GiveLibraryGroup/GiveLibraryAndGroup) with
   local_holdgroup_match => 1, and propagate that into both the
   tmp_holdsqueue and hold_fill_targets INSERTs.
 - C4/Reserves.pm: in the CheckReserves loop, when
   LocalHoldsPriorityExclusivityPeriod is set, the hold is still within
   that window, and the item being evaluated is not itself a local
   match, skip the reserve if its hold_fill_targets row has
   local_holdgroup_match = 1.  Missing hold_fill_targets row means "no
   information" -- fall through so holds are never trapped between
   queue runs.
 - circulation.pref: expose the new LocalHoldsPriorityExclusivityPeriod
   preference next to the existing LocalHoldsPriority* entries.

The feature is a no-op unless both LocalHoldsPriority is set to
something other than "Don't give" AND
LocalHoldsPriorityExclusivityPeriod is > 0.

Test plan:
 1) Apply the patches and run the atomicupdate.
 2) Set up a library group flagged as a local hold group containing
    two libraries (call them A and B).  Add a third library C that is
    NOT in the group.
 3) Add one item to each library (itemA, itemB, itemC) on the same
    biblio.
 4) Administration -> System preferences -> Circulation:
    - Set LocalHoldsPriority to "Give library group".
    - Set LocalHoldsPriorityPatronControl to "home library".
    - Set LocalHoldsPriorityItemControl to "home library".
    - Set LocalHoldsPriorityExclusivityPeriod to 7.
 5) As a patron whose home library is A, place a title-level hold with
    pickup at A.
 6) Run the holds queue (misc/cronjobs/holds/build_holds_queue.pl).
    -> The queue should target itemA (or itemB) for this hold.
    -> Confirm in the database:
         SELECT reserve_id, itemnumber, local_holdgroup_match
           FROM hold_fill_targets;
       The targeted row must have local_holdgroup_match = 1.
    -> Holds to pull / holds queue report should also show the flag
       (tmp_holdsqueue.local_holdgroup_match = 1).
 7) At library C, check in itemC (the non-local item).
    -> The hold must NOT be captured -- itemC simply goes back on the
       shelf.
 8) At library A, check in itemA (the local item).
    -> The hold IS captured for the patron.
 9) Cancel and re-place the hold, run the queue again.  Manually age
    the hold past the window:
         UPDATE reserves
            SET reservedate = DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
          WHERE reserve_id = <id>;
    Now check in itemC again.
    -> The hold IS captured (exclusivity window has expired).
10) Re-place the hold but do NOT run the queue.  With no
    hold_fill_targets row for the reserve, check in itemC.
    -> The hold IS captured (we never trap holds between queue runs).
11) Flip LocalHoldsPriorityExclusivityPeriod back to 0 and repeat
    step 7.
    -> The hold IS captured; the feature is fully disabled.
12) Run:
      prove t/db_dependent/Holds/LocalHoldsPriority.t \
            t/db_dependent/HoldsQueue.t \
            t/db_dependent/Reserves.t \
            t/db_dependent/Koha/Hold.t
    -> All tests pass.

Sponsored-by: Main Library Alliance <https://www.mainlib.org/>

Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:09 +00:00
Jan Kissig 2fe11906a7
Bug 42292: (QA follow-up) replace remaining OD_password_required with Koha.prefs.OverDrivePasswordRequired
As in opac-user.tt OD_password_required was replaced by Koha.prefs.OverDrivePasswordRequired. The script overdrive.js checks already for the Koha.prefs variable.

1) Set sysprefs: OPACOverDrive, OverDriveCirculation, OverDrivePasswordRequired
= Enable/Yes; OverDriveClientKey, OverDriveClientSecret, OverDriveLibraryID =
any non-empty value (e.g. 123).
2) Go to <opac_url>/cgi-bin/koha/opac-user.pl, click "Log in to your OverDrive
account" - password modal appears (correct).
3) Go to <opac_url>/cgi-bin/koha/opac-overdrive-search.pl?q=music, click the
same link, it fails with "No password provided" instead, no modal.

4) apply patch and repeat 3) The modal appears now.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:07 +00:00
Jan Kissig c2514018b4
Bug 42292: (QA follow-up) remove unused reference OverDriveEnabled in opac-shelves
As OverDriveEnabled is declared via SET in the template and not a system preference and after all not used in that script it is removed.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:06 +00:00
Jan Kissig 87d4eac98e
Bug 42292: (QA follow-up) Fix evaluation of OpacHighlightedWords to be numeric in opac-results
OpacHighlightedWords was set in quotation marks and resulted in either "1" or "0".
As "0" and "1" always evaluates to true in JS the following error was thrown when OpacHighlightedWords was set to Don't highlight: Uncaught TypeError: $(...).highlight is not a function

To test:
a) Set system preference OpacHighlightedWords to Don't highlight
b) search a title in the opac with open dev console and check that no error (like above) is thrown.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:05 +00:00
Paul Derscheid 71b121bb6f
Bug 42292: (follow-up) Fix OverDrive/OpenLibrary references in opac-results.tt
Three issues introduced by the OPAC port of opac-results.tt:

- The tt-allowed block sets OverDriveEnabled via
  `Koha.Preference("OverDriveEnabled")`, but OverDriveEnabled is a
  TT-side SET variable (computed from OverDriveLibraryID +
  OverDriveClientKey + OverDriveClientSecret), not a system
  preference, so Koha.prefs.OverDriveEnabled is always "".
  The code at line 621 then reads an unprefixed `OverDriveEnabled`
  identifier which is not declared -- the OverDrive result block
  never fires.
- The neighbouring block `if (OpenLibrarySearch) { ... }` reads an
  unprefixed identifier for a value that is only exposed on
  Koha.prefs, so the OpenLibrary result block also never fires.
- Both blocks build a throbber <img> with
  `src=\`${interface}/${theme}/images/spinner-small.gif\`` inside a
  single-quoted JS string; the backticks are literal characters
  there, so the rendered src ends up as that literal template
  text, not a usable URL.

Replace the OverDriveEnabled addPrefs entry with a plain
`const OverDriveEnabled = [% OverDriveEnabled ? 1 : 0 | html %];`
that reads the TT SET variable, prefix OpenLibrarySearch with
Koha.prefs, and rebuild the throbber src via normal string
concatenation.

To test:
- With OverDrive configured (OPACOverDrive, OverDriveLibraryID,
  OverDriveClientKey, OverDriveClientSecret), run a search in the
  OPAC: the OverDrive results panel shows the spinner and then
  the API results.
- With OpenLibrarySearch enabled, the OpenLibrary panel does the
  same.
- In both cases the spinner image loads (no broken-image icon).
- Disable both prefs -> neither panel is rendered, no console errors.

Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Jan Kissig <bibliothek@th-wildau.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:04 +00:00
Paul Derscheid b4035c5a0c
Bug 42292: (follow-up) Fix duplicate NovelistSelectProfile declaration
In the new tt-allowed block, the NovelistSelect fallback declarations
redeclare `NovelistSelectProfile` instead of also exposing
`NovelistSelectPassword`:

    var NovelistSelectProfile = "[% NovelistSelectProfile | html %]";
    var NovelistSelectProfile = "[% NovelistSelectPassword | html %]";

So `NovelistSelectProfile` ends up holding the password, and
`NovelistSelectPassword` is never declared. The later
`novSelect.loadContentForQuery(..., NovelistSelectProfile,
NovelistSelectPassword, ...)` call then throws ReferenceError and
NovelistSelect content never loads on biblio detail pages.

Rename the second declaration to `NovelistSelectPassword` to match
the original template behaviour.

To test:
- Configure the NovelistSelect sysprefs (NovelistSelectEnabled,
  NovelistSelectProfile, NovelistSelectPassword) in the OPAC. Real
  NovelistSelect content only loads with valid EBSCO subscription
  credentials -- with dummy values the JS path still runs but the
  tab stays empty; that is still sufficient to verify this fix.
- Open an OPAC biblio detail page with a known ISBN.
- In the browser console, run
  console.log(NovelistSelectProfile, NovelistSelectPassword)
  and confirm both values are printed (before the fix,
  NovelistSelectPassword is undefined).
- With valid subscription credentials, NovelistSelect content loads
  in its tab/panel instead of throwing a ReferenceError in the
  console.

Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Jan Kissig <bibliothek@th-wildau.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:03 +00:00
Paul Derscheid a8da9a5f14
Bug 42292: (follow-up) Rename opac-shelves print flag to avoid shadowing window.print
The port declares `var print = [% print ? 1 : 0 | html %];` at the
top of the tt-allowed block, then later calls `window.print()` inside
`if (print) { ... }`. Declaring `var print` at top-level overwrites
the built-in `window.print` with 0 or 1, so the subsequent
`window.print()` call throws "print is not a function" and the print
view never fires its actual print dialog.

Rename the flag to `should_print` and update the single `if (print)`
check accordingly.

To test:
- Open a public list with items in the OPAC.
- Click "Print this list" (or load the page with op=print).
- The browser print dialog opens and the window closes afterwards.
- No "print is not a function" error in the console.

Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Jan Kissig <bibliothek@th-wildau.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:02 +00:00
Paul Derscheid ed7fef7dd7
Bug 42292: (follow-up) Replace removed dateformat_pref var in OPAC calendar.inc
The OPAC port moved the dateformat pref into Koha.addPrefs and dropped
the local `var dateformat_pref = ...;` declaration, but four usages of
`dateformat_pref` remain in the same file (the debug alert, two
`switch` statements, and the get_dateformat_str call in validate_date).
At runtime the switches throw ReferenceError, so flatpickr ends up
with the default 'Y-m-d' format and date validation via validate_date
crashes before showing the invalid-date alert.

Replace all remaining occurrences with Koha.prefs.dateformat, which is
populated by the new addPrefs block at the top of the include.

To test:
- Set dateformat syspref to each of us / metric / dmydot / iso.
- Open any OPAC page using a flatpickr input (e.g. hold date, patron
  dob on the registration form).
- Confirm the widget renders dates in the expected format and
  entering an invalid string triggers the validate_date alert.
- No ReferenceError in the browser console on page load.

Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Jan Kissig <bibliothek@th-wildau.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-07-29 15:50:01 +00:00