Commit Graph

60640 Commits

Author SHA1 Message Date
Jan Kissig 3e3c57afb8
Bug 42398: Reimplement form validation to news
This patch reimplements form validation on news (additional contents). The form.validate() call which adds a submitHandler is moved outside the document ready block in order to work again.
Markup like class=required is added to meet JS10 guidelines. JS alerts (when default title or default content was empty) were replaced by setting focus the required field.

Test plan:

a) go to /cgi-bin/koha/tools/additional-contents.pl?category=news (Tools -> News)
b) click either 'New entry' or 'New entry using text editor'
c) enter a required publication date
d) save the form. You will not be required to enter a default title or content.
e) apply patch followed by a restart_all
f) go to /cgi-bin/koha/tools/additional-contents.pl?category=news (Tools -> News)
g) click either 'New entry' or 'New entry using text editor'
h) check that title and content in the 'Default' tab are marked as required
i) try to send form f.e. when only title and content in 'English' tab are set
j) check if default title or content is missing the default tab is shown and the field gets focused

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

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit f4678e5b23)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:50 +01:00
Andrew Fuerste Henry cce8bf77f6
Bug 42570: Use count_holds for OPAC patron summary pending holds
To test:
1 - enable DisplayAddHoldGroups
2 - place two ungrouped holds for a patron
3 - log into the opac as your patron, see 2 pending holds
3 - group the two holds
4 - reload OPAC, still see 2 pending holds
5 - Apply patch, restart_all
6 - reload OPAc, see 1 pending holds
7 - ungroup holds
8 - reload OPAC, see 2 pending holds

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 186ec335db)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:50 +01:00
Pedro Amorim 5ca8f35a10
Bug 42255: Add tests
prove t/db_dependent/Reserves.t

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit e931157dc7)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:50 +01:00
Pedro Amorim 53b6f704ad
Bug 42255: Maximum total holds allowed (count)
Make 'Maximum total holds allowed (count)' (aka max_holds) consider hold groups

Test plan:
Same as the previous test plan, but set 'Maximum total holds allowed (count)' as 2 and instead set 'Holds allowed (total)' as unlimited.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit e56c9cc9bb)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:50 +01:00
Pedro Amorim 108f7d56d2
Bug 42255: Holds allowed (total)
Make 'Holds allowed (total)' (aka reservesallowed) consider each hold group as an individual hold

Test plan:
1) Enable DisplayAddHoldGroups sys pref
2) Set Holds allowed (total) to 2, visit:
http://localhost:8081/cgi-bin/koha/admin/smart-rules.pl
3) Scroll to the right, click the 'Edit' button under 'Actions' column.
4) On the 'Holds allowed (total)' column cell, enter '2' and click 'Save' under the 'Actions' column to the right.
5) Search  for 'test':
http://localhost:8081/cgi-bin/koha/catalogue/search.pl?q=test
6) Tick the checkbox next the first and second results, click 'Place hold' button at the top toolbar
7) Search for 'koha' user and pick Koha (42)
8) Set a pickup location for each hold and tick the 'Treat as hold group' checkbox. Click 'Place holds'.
9) Try to place another single hold for the same patron. Should succeed, because the 2 grouped holds count as 1. Patron now should have 1 group + 1 ungrouped hold = effective count of 2.
10) Try to place yet another hold, should be blocked with a tooManyHolds error.
11) Prior to this patch, step 9 would've failed because the 2 grouped holds counted as 2.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit d5f130da5a)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:50 +01:00
wainuiwitikapark acab81737a
Bug 38009: Add a generate next button in serials receive page
Adds a generate next button to the serials receive page (serials-edit.pl) that works similar to the button on the serials collection page.

To test:

1. Go to Staff Client > Serials
2. Find an existing subscription or create a new one
3. Go to the Serials collection page for your serial e.g. /cgi-bin/koha/serials/serials-collection.pl?subscriptionid=1
4. Click on the "Generate next" button and notice that the table adds
   another row
5. Click on the "Receive" button at the top of the page
6. Notice that the page also shows the issues like the rows in the
   previous page
7. Apply patch
8. Repeat steps 1-5
9. Notice that the page also has a "Generate next" button at the top
10. Check that the button generates a new issue row on the page

Sponsored-by: Pymble Ladies' College
Signed-off-by: esther <esther@bywatersolutions.com>
Signed-off-by: Brendan Gallagher <brendan@bywatersolutions.com>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 7b1a348ac9)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:50 +01:00
Owen Leonard 8362e6b7c5
Bug 42439: Remove event attributes from label-edit-batch.tt
This patch removes an "onload" event attribute from the label batch edit
template. An "onload" event attribute on the body tag can be easily
moved to the $(document).ready block.

To test, apply the patch and go to Cataloging -> Label creator -> Label
batches -> New label batch. As soon as the page loads the "Add by
barcodes" textarea should get focus.

Sponsored-by: Athens County Public Libraries
Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit b8832e7d7e)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:49 +01:00
Owen Leonard f3482ddb93
Bug 42438: Remove event attributes from icon selection include file
This patch removes an "onmousedown" event attribute from the include
file used by item types and authorized values administration in icon
selection. The event handling is copied to each page's JS block.

To test, apply the patch and go to Administraion -> Item types.

In the "Choose an icon" section, click the "Remote image" tab. Click
the text input field. The corresponding radio button should be
checked.

Perform the same check on Administration -> Authorized values.

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: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 3160983a6d)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:49 +01:00
Nick Clemens 3ca9f8d2c4
Bug 42424: Javascript error prevents saving when an instance of an 'important' or 'required' subfield is deleted
In the loop to check fields, we enter a conditional when the element is null - but then we try to adjust the element.
This patch removes the condition and prevents accessing NULL fields

To test:
 1 - Go to Administration->MARC Bibliographic framework
 2 - Under Default click Action->MARC Structure
 3 - Search for 020
 4 - Click Actions->Edit subfields
 5 - Click on tab 'a'
 6 - Check important, save
 7 - Cataloging->New from Z39
 8 - Search for ISBN: 9798225048921 (or any record you want)
 9 - Ensure the result has more than one ISBN and click Actions->Import
10 - Delete one of the ISBN fields
11 - Click 'Save'
12 - Check the console (F12)
     Uncaught TypeError: Cannot read properties of null (reading 'nodeName')
13 - Apply patch
14 - Repeat 8-10
15 - Click save (and clear any other fields that need edited)
16 - Confirm record can be saved

Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit c85f9a02a9)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:49 +01:00
Jonathan Druart ff20b92727
Bug 41769: Translate "%s, by %s"
Instead of translating ", by" we add more flexibility for languages that
need to invert author and title for instance.

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit f1c3c2d89a)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:49 +01:00
Ayoub Glizi-Vicioso ef28b9dedd
Bug 41769: Make ', by' string translatable in suggestions
This fixes a translation issue in the purchase suggestions
table in the staff interface - a ", by" is added between the
title and the author in the suggestion column, the "by" is
not translated when the language for the staff interface
is a language other than English.

Test plan:

1. Add another language to Koha:
   ./misc/translator/translate install fr-CA

2. Enable the new language in StaffInterfaceLanguages:
   2.1. Go to Administration > System preferences
   2.2. Search for StaffInterfaceLanguages
   2.3. Check the new language
   2.4. Click Save all I18N/L10N preferences

3. Create a new purchase suggestion:
   3.1. Go to More > Suggestions
   3.2. Click New purchase suggestion
   3.3. Fill out the title AND the author at least
   3.4. Click Submit your suggestion

4. View the suggestion in the table
   --> It says title, by author

5. Switch language
   --> The ", by" is still in English

6. Apply patch.

7. Run these commands to update the translation:
   7.1 ./misc/translator/translate update fr-CA
   7.2 ./misc/translator/translate install fr-CA

8. Reload page.

9. Notice that ", by" is now translated.
   --> in this instance, you will see ", par"

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

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 97b4b2f1db)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:49 +01:00
Jacob O'Mara 9d60ad2a37
DBRev 25.11.04.012
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:49 +01:00
Emily Lamancusa 76345c7eba
Bug 39107: (QA follow-up) Use existing foreign_key_exists function
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 4a57c1f779)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:49 +01:00
Saiful Amin 205a9c27d5
Bug 39107: Remove illrequests_safk FK constraint on illrequests.status_alias as required by MySQL 8.4+
MySQL 8.4 requires foreign keys to reference PRIMARY KEY or UNIQUE keys.
Since authorised_values.authorised_value is only unique in combination
with category (composite UNIQUE key av_uniq), the FK constraint is not
compatible with MySQL 8.4+.

Data integrity for illrequests.status_alias is maintained at the application layer:
- Koha::ILL::Request->status_alias() validates values against
  authorised_values (category='ILL_STATUS_ALIAS') before storing
- All ILL request operations in Koha use this object layer
- CASCADE behaviors (ON DELETE SET NULL, ON UPDATE CASCADE) are already
  handled by the application layer when modifying/deleting authorised values.

Test Plan, using KTD:
1. Prepare KTD for MySQL 8.4
    - In koha-testing-docker, edit 'compose/db-mysql.yml'
    - Comment out the line 5:
    `# command: --default-authentication-plugin=mysql_native_password`

    Note: This is required because MySQL 8.4 doesn't support the native password plugin.

2. Start a new instance with MySQL 8.4
    - `DB_IMAGE=mysql:8.4 ktd up`
    - Observe that it fails to start with the errors such as 'DBD::mysql::st execute failed'

3. Apply the patch
    - `git bz apply 39107`

4. Start the instance again
    - `DB_IMAGE=mysql:8.4 ktd up`
    - Observe that it starts successfully

5. Update the database (Optional, only for existing instances)
    - `perl installer/data/mysql/updatedatabase.pl`

6. Access Koha Staff and OPAC interfaces and verify that everything works as expected

7. Sign off

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit fe24b5030e)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:44 +01:00
Lucas Gass b58cf6df96
Bug 29016 [25.11.x]: (RM follow-up) Add action_logs tag to swagger def
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:44 +01:00
Martin Renvoize 99ffc00e62
Bug 29016 [25.11.x]: (QA follow-up) Document the action_logs list controller
Replace the empty =head3 stub with a proper synopsis explaining the URL,
the supported filtering / ordering / embed surface, and the permission
requirement. Aligns the controller with the documentation density of
other Koha REST controllers and removes the "Missing POD" QA noise.

Test plan:
  1. perl -MKoha::REST::V1::ActionLogs -e ''  (still loads)
  2. perl -c Koha/REST/V1/ActionLogs.pm        (still parses)
  3. perldoc Koha/REST/V1/ActionLogs.pm        (renders the new POD)

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:44 +01:00
Martin Renvoize 3089c74f6f
Bug 29016 [25.11.x]: (QA follow-up) Restore biblio<->item log expansion
The catalog detail page links to the modification log with
modules=CATALOGUING&object_type=biblio&object=<biblionumber>. The old
server-rendered viewer matched both biblio-level entries (object =
biblionumber, info LIKE 'biblio%') and item-level entries (object IN
(itemnumbers of this biblio), info LIKE 'item%'). Converting to the
AJAX DataTable kept that expansion only in the CSV export branch, so
the on-screen view silently dropped item-level history.

Recreate the expansion in the AJAX path:

  * tools/viewlog.pl: when (single CATALOGUING module + object_type
    =biblio + non-empty object) collect the biblio's itemnumbers and
    expose them, along with object_type, to the template.
  * viewlog.tt: include object_type and biblio_itemnumbers in the
    search_params JSON the inline script builds for the JS.
  * viewlog.js: when those params are present, build the same -or
    clause the old SQL produced and skip the regular per-object filter.
    The info substring filter is also suppressed in that branch (the
    old code did the same: it dropped %info% in favour of the -or).

Test plan:
  1. Enable CataloguingLog.
  2. Edit the biblio and a couple of its items.
  3. From the biblio detail page, open "Modification log".
  4. Verify the table shows both the biblio MODIFY rows and the item
     MODIFY rows for that biblio (and only those).
  5. From Tools -> Log viewer, plain Cataloguing filter still returns
     the unfiltered log set as before.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:44 +01:00
Martin Renvoize 2b165d347e
Bug 29016 [25.11.x]: (QA follow-up) Translate circulation overrides in info column
CIRCULATION rows whose info payload is a JSON object can carry `forced`
and `confirmations` arrays listing the override codes a librarian
acknowledged when checking out, renewing or otherwise circulating an
item (e.g. DEBT, AGE_RESTRICTION, BIBLIO_ALREADY_ISSUED). The old
server-rendered template ran these through the translate_log_override
SWITCH block in action-logs.inc; in the new AJAX-driven viewer the JS
default branch was just escapeHtml()-ing the raw JSON, leaving the
codes unlocalised and unreadable.

Port the override -> human-readable label map into str/viewlog.inc as
override_labels, mirroring the module/action/interface label maps
already there. Add a renderCircInfo() helper that recognises the JSON
shape and emits the same div.forced / div.confirmed blocks the old
template did, so the existing CSS continues to apply.

renderInfo() now falls through CIRCULATION -> renderCircInfo, the
generic record-info renderer (CATALOGUING / AUTHORITIES from bug 42032)
and finally escapeHtml(), so non-JSON payloads (item barcodes,
ID-only info, ...) keep displaying as before.

Test plan:
  1. Enable IssueLog.
  2. Trigger an override checkout (e.g. patron with debt, item not for
     loan) and confirm.
  3. Tools -> Log viewer, filter by module=Circulation.
  4. The override row's Info column should show one or more localised
     "Patron had debt", "Item was not for loan", ... lines instead of
     a raw JSON blob.
  5. Plain ISSUE / RETURN rows (no overrides) keep showing the raw
     itemnumber / barcode payload as before.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:44 +01:00
Martin Renvoize 78a9da8e33
Bug 29016 [25.11.x]: (QA follow-up) Render embedded patron, fix JS i18n drift
QA review pointed out three regressions and a label gap in the new
DataTable-driven log viewer:

  1. The Librarian column showed a bare borrowernumber linked to the
     patron page; the old server-side template showed the librarian's
     full name with the borrowernumber in parentheses.

  2. The Object column for MEMBERS / CIRCULATION / FINES / APIKEYS rows
     showed only the borrowernumber; the old template showed the
     patron's full name and used "API keys for <name> (<id>)" wording.

  3. Several user-visible strings in renderObject() were hard-coded
     English ("Bibliographic record ", "Subscription ", "Authority ",
     "Basket ") and would never have been picked up by the translator.

  4. The form's Actions list still includes RESTORE but the new
     str/viewlog.inc action_labels map missed the corresponding entry,
     so the rendered Action cell fell through to escapeHtml("RESTORE")
     instead of the localised "Restore".

This patch:

  * Asks the API to embed both `librarian` and `patron` and uses those
    objects when rendering the Librarian and Object columns. When the
    embed is absent (e.g. because the relation does not match for a
    non-MEMBERS row) the renderers fall back to the bare id, preserving
    backwards compatibility.

  * Wraps the four hardcoded strings in __() with %s placeholders so
    the translator extracts them. The Basket markup is also assembled
    via __("Basket %s").format(...) rather than string concatenation
    so that translators can re-order the link text.

  * Adds RESTORE: _("Restore") to str/viewlog.inc.

Test plan:
  1. Tools -> Log viewer with various modules selected.
  2. Verify the Librarian column shows "Firstname Surname (id)" and
     links to the moremember page.
  3. Filter to MEMBERS / CIRCULATION / FINES; verify the Object column
     shows the patron's full name, and the API keys row uses the
     "API keys for <name> (<id>)" wording.
  4. Filter to CATALOGUING / SERIAL / AUTHORITIES / ACQUISITIONS; verify
     "Bibliographic record N", "Subscription N", "Authority N" and
     "Basket N" still link correctly.
  5. Restore a deleted biblio (CataloguingLog must be on); verify the
     Action column shows "Restore" rather than "RESTORE".

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:44 +01:00
Martin Renvoize 3a05b239db
Bug 29016 [25.11.x]: (QA follow-up) Expand action_logs API and test coverage
Build on the new ActionLog DBIC relations to expose them as opt-in
embeds, and shore up gaps in the test coverage that QA flagged.

Swagger
  * paths/action_logs.yaml declares an x-koha-embed header parameter
    constrained to the supported relations (librarian, patron).
  * definitions/action_log.yaml adds the corresponding optional
    `librarian` and `patron` object fields.

Tests
  * Convert the single 24-test subtest into focused subtests:
    - authorization (403 vs 200)
    - simple typed filters
    - q-DSL: multi-value module, info LIKE, combined filter
    - embeds: librarian and patron, with and without x-koha-embed
    - pagination + X-Total-Count and order_by
  * Mock AuthSuccessLog/AuthFailureLog/BorrowersLog to 0 to remove the
    flakiness where the API GET itself appended an AUTH log row between
    delete and assertion.
  * Build the test librarian with both `tools` and `borrowers` flags so
    embedded patron fields are not redacted by Koha::Patron->is_accessible.
  * Use a small build_fixtures() helper to avoid copy-pasting setup
    across subtests.

Test plan:
  1. yarn build && restart_all  (refresh swagger bundle)
  2. prove t/db_dependent/api/v1/action_logs.t  (all subtests green)
  3. curl -H 'x-koha-embed: librarian,patron' \
       /api/v1/action_logs?module=MEMBERS  -- patron and librarian
       objects appear in the response.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:26 +01:00
Martin Renvoize 52fe8c72b2
Bug 29016 [25.11.x]: (QA follow-up) Add librarian/patron relations to ActionLog
QA review noted that the new /api/v1/action_logs endpoint exposed only
column data, so the log viewer ended up showing bare borrowernumbers in
the Librarian and Object columns where the old server-side rendering
showed firstname/surname (borrowernumber). Add the DBIC plumbing needed
to support x-koha-embed for those relationships.

Two belongs_to relationships are declared below the auto-generated
marker on Koha::Schema::Result::ActionLog:

  * librarian -> borrowers.borrowernumber via action_logs.user
  * patron    -> borrowers.borrowernumber via action_logs.object

The patron relation is intentionally polymorphic; the action_logs.object
column holds different identifiers per module (biblionumber for
CATALOGUING, subscriptionid for SERIAL, ...) so callers must filter by
module before trusting the joined patron - this is documented in both
schema and Koha::ActionLog comments.

Koha::ActionLog gains explicit librarian() and patron() accessor methods
following the Koha::Hold pattern, returning Koha::Patron objects (or
undef when the relation does not match). The accessors deliberately
avoid `use Koha::Patrons` at compile time: Koha::ActionLog is loaded
very early via C4::Log and Koha::Patron is not yet defined at that
point - the accessors reach for it lazily at call time.

koha_object_class / koha_objects_class overrides are also added to bring
the result class in line with the rest of the codebase.

Test plan:
  1. prove t/db_dependent/api/v1/action_logs.t  (still green)
  2. perl -MKoha::ActionLog -e 'print "ok"' (no circular import)

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:26 +01:00
Kyle M Hall fb067372a2
Bug 29016 [25.11.x]: Move strings from js file to tt file
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:26 +01:00
Kyle M Hall 14744a8e3a
Bug 29016 [25.11.x]: Convert log viewer to ajax datatable
The script viewlog.pl it's very slow because it retrieves all action logs at the same time.
It should use KohaTables with pagination/number max of returning entries like other Koha tables (API + AJAX wrapper).

Test Plan:
1) Apply this patch
2) Rebuild swagger file
3) Restart all the things!
4) Browse to /cgi-bin/koha/tools/viewlog.pl
5) Test functionality, functionality should be no different!
   * Limit by librarian
   * Limit by modules
   * Limit by actions
   * Object search string
   * Info search string
   * Limit by interface
   * Limit by from date
   * Limit by to date
   * Limit by from and to date
   * Test "Compare" checkboxes ( only two should be selectable at once )
   * Test column sorting
   * Test sharable link
   * Test output to a file
   * Test columns show/hide

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:26 +01:00
Kyle M Hall e2250b04b1
Bug 29016 [25.11.x]: Add unit tests
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Kyle M Hall 637139d782
Bug 29016 [25.11.x]: Add REST API for action logs
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
David Cook 4c119b95fa
Bug 41846: Fix routing-preview-slip.tt too
Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit b7e67b5c1d)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
David Cook f055eb5c4e
Bug 41846: Fix nl2br to happen after html escaping
This patch removes the newline to <br/> (nl2br) handling in the .pl script,
and instead moves it after the Template::Toolkit "html" filter. In this way,
we get the security of the "html" filter while also converting new lines into
safe <br/> elements. We also fix a little style problem. Hurray!

Test plan:
0. Apply the patch and koha-plack --restart kohadev
1. Ensure the RoutingSerials system preference is enabled
2. Create a "Subscription" for a known biblionumber (e.g. 29) with whatever details
3. On the subscription-detail.pl page for that subscription, click on "Create routing list"
4. Add whatever recipients you want and put the following into Notes:
Testing out notes
1-26-26 more notes
2-5-26 = more notes, 3 copies
<p>Awesome... still safe</p>

5. Click "Save"
6. Observe that your notes are output exactly the same way you put them in. The newlines
appear to be newlines to the human eye, while that pesky <p></p> markup is escaped.
7. Observe that the notes are also neatly lined up with the rest of the routing list
display for an attractive user experience
8. Celebrate again. Hurray!

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

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit faa94eac6f)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Jacob O'Mara ae19c41f30
DBRev 25.11.04.011
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Nick Clemens 1f9a4e190a
Bug 40658: Use local-number__sort and not local-number directly
This patch makes sure we inject the __sort form of local-number, rather
than the field directly - this ensurs searching works even if mappings mayu
be different and local-number itself is not numeric

To test:
1 - Edit mappings.yaml and set local-number from 'number' to 'string'
    NOTE: There are two copies of local-number - one in auth and one in biblio - the latter is the important one here
2 - perl misc/search_tools/rebuild_elasticsearch.pl -r -v
3 - Confirm in staff interface Admin -> Search Engine Configuration that local-number is now a string
4 - Search and get an error
    Error: Unable to perform your search. Please try again.
    In the logs:
[illegal_argument_exception] Text fields are not optimised for operations that require per-document field data like aggregations and sorting, so these operations are disabled by default. Please use a keyword field instead. Alternatively, set fielddata=true on [local-number] in order to load field data by uninverting the inverted index. Note that this can use significant memory.
5 - Apply patch, restart all
6 - Search again
7 - Success!

Signed-off-by: Bernard Scaife <bernard.scaife@openfifth.co.uk>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Thomas Klausner <domm@plix.at>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 649fbbf452)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Nick Clemens 89b27ebd36
Bug 40658: Atomic update to ensure local-number is sortable
I don't know if this is appropriate for master as it requires Koha objects,
but this is helpful for upgrading sites to avoid any problems from old mappings
for local-number

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Thomas Klausner <domm@plix.at>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 258a947b64)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Lucas Gass 8770311a4a
Bug 42103: (follow-up) Fix failing test
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 04a3371ee9)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Simon 9fdec10213
Bug 42103: Capitalize MARC acronym in templates and DataInconsistency
This fixes the spelling of "marc" in two places:
- an error message from running the database audit
- the description for the marc_modification_templates permission

Test plan:
1. The easiest way to test this change is to check the diff for the
   patch and note that "marc" is changed to "MARC" in two places.
2. Database audit output (More > About Koha > Database audit):
   - Check the diff (otherwise would need to alter the database
     structure somehow so that the audit would generate the error
     message).
3. Check the description for the marc_modification_templates permission:
   - Go to any patron record
   - Select More > Set permissions
   - In the filter, enter: marc modification
   - Note that the description is:
       Manage marc modification templates (marc_modification_templates)
4. Apply the patch.
5. Repeat step 3 and note that the description is now:
     Manage MARC modification templates (marc_modification_templates)

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 39c1917b21)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Nick Clemens 6196fa4424
Bug 41343: Further improvements
Remove unused patron attribute values sent to the template

Send preferred name

Use SQL to do date comparison to see if an item is overdue

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

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 6a12116dd2)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Nick Clemens 0375ae33c8
Bug 41343: Don't fetch patron objects per overdue
We use SQL here to get all the needed info - the query says it is slow, but isn't so bad.
Worse is fetching the patron for each borrower with overdues (and more than once if they have several)

It appears we started grabbing the patron so we could use patron title, but we can just pass the info already fetched.

I additionally fetch the patron category types and update patron-title to allow for hide_patron_infos_if_needed to work
without a patron object - we can just use the branchcode as ultimately that's all we need

To test:
1 - Add many items to your catalog (can use my handy repo randitems.pl)
    https://github.com/kidclamp/handy-koha-script
2 - Add many issues (can use randissues.pl from above)
3 - I tested with about 1000
4 - Browse to Circulation->Overdues
5 - Note load time
6 - Apply patch
7 - Restart all
8 - Note load time is faster

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

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit e3862dc81b)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Bernard Scaife 0f3852eec4
Bug 41073: Fix default expiry date which is being ignored
Fixes regression in which default expiry date is ignored due to regression introduced by fix for bug 34483. If default expiry date is completed in patron import tool, the value is ignored and expiry date unaltered. This patch fixes this error.

Test plan:
1. User should exist and have expiry date in future (say 2099-12-31)
2. Save above as file
3. Tools > Import users
4. Choose file saved in 2
5. Field to use for record matching: cardnumber
6. In default values set expiration date to a date in past (say 2025-10-19) using date picker
7. Select overwrite the existing one with this
8. Leave renew existing patrons as "use the expiration date in the file if present"
9. Run
10. Observe user expiry date is still 2099-12-31
11. Apply patch / restart_all
12. Repeat 4 - 9 above
13. Observe user expiry date is now 2025-10-19

Signed-off-by: Eric Phetteplace <ephetteplace@cca.edu>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 950c9f8188)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Hammat Wele b29d000c28
Bug 41690: (follow-up) Add test
Signed-off-by: David Nind <david@davidnind.com>

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit a0b92c0bb6)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Hammat Wele 126df2dd52
Bug 41690: Add MARC21 245 (subtitle) to Cite option
The "Cite" option in the OPAC is missing the subtitle (245) in MARC21.

To recreate:
1. Add a record or find a record with a subtitle (in KTD, biblionumber 58 has a 245 http://localhost:8081/cgi-bin/koha/catalogue/MARCdetail.pl?biblionumber=58
2. In the OPAC, go to the record
   http://localhost:8080/cgi-bin/koha/opac-detail.pl?biblionumber=58
3. Click "Cite"
   --> The subtitle is not in any of the citations
4. Apply the patch
5. Repeat step 2 and 3
    --> The subtitle is now shown

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 412e4e4d95)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Marcel de Rooy 1321bbc5c1
Bug 41962: Add comment to SearchAuthorities, change POD
Test plan:
Read the patch.
Search for both parameters to verify that they are not used.

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit f5a38efff1)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:25 +01:00
Andreas Roussos 6b0593e772
Bug 41795: (follow-up) add a phrase Zebra index for 'authtype'
As per https://software.indexdata.com/zebra/doc/querymodel-rpn.html#querymodel-bib1-completeness:
"[...] Complete field (3) triggers search and scan in index type="p"."

The UNIMARC Zebra index definitions for authorities *do* include
a 'p' (short for 'phrase') type index for authtype -- however, the
MARC21 Zebra index definitions don't and this is causing these two
tests to fail:

t/db_dependent/Biblio.t
t/db_dependent/FrameworkPlugin.t

This patch fixes that.

Test plan for KTD:

1) Apply the patch, then:

   k$ sudo cp etc/zebradb/marc_defs/marc21/authorities/authority-koha-indexdefs.xml /etc/koha/zebradb/marc_defs/marc21/authorities/
   k$ sudo cp etc/zebradb/marc_defs/marc21/authorities/authority-zebra-indexdefs.xsl /etc/koha/zebradb/marc_defs/marc21/authorities/
   k$ koha-rebuild-zebra --authorities --full --force --verbose kohadev

2) Run these tests -- they should both complete without warnings/errors:

   k$ prove -v t/db_dependent/Biblio.t
   k$ prove -v t/db_dependent/FrameworkPlugin.t

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 6fe0b70020)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Marcel de Rooy ae8e1adb74
Bug 41795: (QA follow-up) Improve comment
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit db6287aa21)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Andreas Roussos 1576c9e7ad
Bug 41795: Fix failing test in UNIMARC instances
Previously, t/AuthoritiesMarc_MARC21.t would fail if
you tried to run it from within a UNIMARC instance.

This patch fixes that.

Test plan:

1) Inside a UNIMARC instance, run the test and
   notice the subtest failure:

   $ prove -v t/AuthoritiesMarc_MARC21.t

2) Apply this patch.

3) Re-run the test and notice that it now completes
   without any failures.

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

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 2b691bd4dd)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Andreas Roussos 15391588d8
Bug 41795: Include the completeness attribute when matching on authtype
UNIMARC instances include the following two authority types
by default (among others): Corporate Body Name (code: 'CO')
and Collective Title (code: 'CO_UNI_TI').

The problem is that when searching for Corporate Body Name
authorities (in the OPAC or in the Staff interface), the
results will include Collective Title authorities as well.
It has to do with Corporate Body Name authorities using
an authtypecode (CO) that happens to be the prefix of the
authtypecode (CO_UNI_TI) used by Collective Titles.

NOTE: Elasticsearch is not affected by this.

The fix is to additionally pass the completeness attribute
to the RPN query sent to Zebra so that it will try to match
on what is literally found in the entire field's phrase
index (i.e. the value of UNIMARC 152$b), instead of performing
a partial match.

More information can be found at the official documentation:
https://software.indexdata.com/zebra/doc/querymodel-rpn.html#querymodel-bib1-completeness

Test plan (tailored for KTD):

0) Launch a UNIMARC Koha instance using Zebra:

   ktd --marcflavour unimarc --search-engine zebra up

1) Import the Sample MARC record attached to this Bug,
   containing a single Collective Title authority
   (adding one manually would take a long time due to
   the many mandatory subfields).

2) Perform a generic authority search (without entering
   anything in the search box) for all 'Corporate Body
   Name' authorities. Note the number of results returned
   (83), and also notice that in page 4 of the results you
   get a stray 'Collective Title' authority ("Selected
   works", the one you imported in Step 1).

3) Apply this patch (and `restart_all`).

4) Repeat the same search as in Step 2. This time, the
   number of results returned should be one less than
   before (82), and you should only see 'Corporate Body
   Name' authorities in the results.

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

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit e43d32a123)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Fridolin Somers 94726ed1d7
Bug 41942: Fix lang hidding in opac patron modification
Bug 34438 added lang in opac registration/modification form.
But it is linked to primary contact method hidden or not.

Looks like this is not on purpose.
This patch removes this link.

Test plan:
1) Verify system preference
   'PatronSelfModificationBorrowerUnwantedField' is empty
2) Go to OPAC user account > Personal details
3) You see 'Preferred language for notices'
4) In system preference 'PatronSelfModificationBorrowerUnwantedField'
   check 'primary_contact_method'
5) Go to OPAC user account > Personal details
   => Without patch lang is also hidden
   => With patch lang is not hidden

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

Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 3d8e069a4d)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Jonathan Druart d867e26002
Bug 42374: Restore require Koha::Plugins (instead of use)
See comment 4 for a detail explanation of the problem.

Test plan:
hit /cgi-bin/koha/installer/install.pl
login with the DB credentials
upgrade
=> Without this patch you get
```
ISBN_RANGE_MESSAGE is set to [] but that file does not exist!
Trying to use the default locations
```
=> With this patch applied: "Everything went okay. Update done."

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit d0bd802da6)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
David Cook cf32a3c9b7
Bug 42374: Remove buggy ISBN_RANGE_MESSAGE env variable value
This patch removes an ISBN_RANGE_MESSAGE env variable that is
accidentally set by Business::ISBN::Data.

Test plan:
- git checkout v25.11.03-2
- reset_all
- git checkout -b 42374 origin/main
- Apply the patch
- restart_all
- Go to staff interface (e.g. http://localhost:8081/)
- Log into web installer
- Click "Update your database"
- Note it works

- Repeat the process but instead of using the web installer
use updatedatabase.pl directly (say through koha-upgrade-schema)

Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit bf867d08c2)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Lucas Gass 750f7170b6
Bug 38414: (follow-up) Fix OR operator
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit ee01f1746c)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Nick Clemens 0a7e112b4e
Bug 38414: (QA follow-up) Adjust templates
Now that we can explicitly list reports with any one of the permissions we need
to adjust some displays to ensure we can get to the list view.

Additionally I change 'Use saved' to 'View saved' since we may not be able to run.

I also fix the action buttons to show 'View' instead of 'Run' if user cannot execute.

I adjust reports home to check if the user can use report plugins before showing that link as well

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit cdd7438ef6)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
David Cook 5ca9c44b0e
Bug 38414: (follow-up) comprehensively cover ops with required permissions
Test plan:
0. Apply the patch and restart_all

1. Using a user with only "create_reports", "execute_reports", or "delete_reports",
try to perform operations not covered by that permission.
That is, if you have "create_reports", try to run, export, and delete reports.
If you have "execute_reports", try to create, modify, and delete reports
If you have "delete_reports", try to create, modify, and run reports

2. Note that a user with each of these permissions can list and view SQL.

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 56d32231b2)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Jonathan Druart f28b4f73ef
Bug 38414: Fix permission controller-side
This bug refactors the preview sql buttons to pass the permissions granted for each report to
the javascript that clones and updates the modal.

That allows us to check for the appropriate permissions when preparing the buttons for the modal
and to remove any that are not allowed.

This allows for different permissions per report for future devs
(see bugs 42406, 16631)

To test:
1. Create some reports
2. Create a user with only execute_reports permissions
3. Login as that user and go to Reports > use saved
4. In the actions column click the ^ and select 'Preview sql'
5. Notice delete button renders and works to delete
6. Apply patch and restart_all
7. Repeat step 4, now only the Run report button renders and works
8. Add permissions for create_reports
9. Repeat step for, now Edit, Duplicate, Schedule and run buttons render and work
10. Add permissions for delete_reports
11. Repeat step 4, confirm the delete button renders and works
12. Confirm the preview sql button works to preview different reports

We also fix some error in the script, several wrong things there:
* delete was not replaced with cud-delete
* missing op for the creation of new reports
* update and run requires two permssions

Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>

Signed-off-by: Scott Barter <sbarter@aacpl.net>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit e472a7607f)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00
Martin Renvoize 5500656127
Bug 41751: Allow anonymous_refund permission to access cashups API
The cash register transaction history page (pos/register.pl) allows
access with either cashup OR anonymous_refund permission, but the
API endpoints for fetching cashups only checked for cashup permission.

This caused a 403 error when users with only anonymous_refund permission
tried to view the transaction history page, as the cashups table failed
to load.

This patch updates the API permissions for:
- GET /cash_registers/{id}/cashups
- GET /cashups/{id}

to accept either cashup or anonymous_refund permission, matching the
page access logic.

Test plan:
1. Create a staff user with only cash_management > anonymous_refund
   permission (not cashup)
2. Navigate to Point of Sale > Transaction history for any cash register
3. Verify the cashups table loads successfully (previously returned 403)
4. Run: prove t/db_dependent/api/v1/cashups.t

Signed-off-by: Jackie Usher <jackie.usher@westsussex.gov.uk>
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit c484b66fc4)
Signed-off-by: Jacob O'Mara <Jacob.omara@openfifth.co.uk>
2026-05-24 13:42:24 +01:00