Commit Graph

26853 Commits

Author SHA1 Message Date
Pedro Amorim db7854682e
Bug 37762: Circulation: Hook to checkouts/checkins
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:43 -06:00
Pedro Amorim 950c9ccb96
Bug 37762: Circulation: Hook to holds
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:43 -06:00
Pedro Amorim 87961beb4d
Bug 37762: Bugfix: Display relationshipSelect
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:42 -06:00
Pedro Amorim 2a1fa8d091
Bug 37762: Vuejs sysprefs store: Allow fetching multiple sys pref values
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:39 -06:00
Pedro Amorim 6dab32ee02
Bug 37762: VueJS ILL Module
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:38 -06:00
Pedro Amorim b307692fb1
Bug 37762: PatronAutoComplete: VueJS framework: Add patronAutoComplete attribute type
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:38 -06:00
Pedro Amorim df37e571d0
Bug 37762: PatronAutoComplete prep: Abstract rendering of selected patron
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:37 -06:00
Pedro Amorim 48783f8477
Bug 37762: PatronAutoComplete prep: Add on remove callback to patron_autocomplete
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:36 -06:00
Pedro Amorim 7374325216
Bug 37762: PatronAutoComplete prep: Allow additional filters in patron_autocomplete
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:36 -06:00
Pedro Amorim 30161380a9
Bug 37762: Fix confirmation button CSS class in confirmation modal
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:35 -06:00
Pedro Amorim bc0ae34098
Bug 37762: VueJS framework: Add attribute.format check in empty groups check
This keeps the same functionality as before, i.e. hide the whole group
if all attributes within are empty. However it now also checks for
'format' as some resources may want to format the display of empty attributes.

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:35 -06:00
Pedro Amorim 66d7845764
Bug 37762: VueJS framework: Add possibility of external navigation item
e.g.:

{
    path: "/cgi-bin/koha/ill/ill-requests.pl",
    title: $__("Requests"),
    icon: "fa fa-download",
    is_external: true,
    is_navigation_item: true,
},

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:34 -06:00
Pedro Amorim b4fe2b92dd
Bug 37762: VueJS framework: Add 'name' to moduleDashboard
This is required to differentiate between selected widgets on different module dashboards i.e. ERM vs ILL

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:34 -06:00
Pedro Amorim a2c13377ed
Bug 37762: VueJS framework: Toolbarbutton spacing to consider different css classes
There's no spacing currently, but it's not obvious as the current style
has the same background color as the body.
This adds spacing so even if some buttons have different colors (e.g.
primary or danger) all buttons are spaced correctly.

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:33 -06:00
Pedro Amorim a40fa90d6a
Bug 37762: VueJS framework: updateConfirmationDialogInputs
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:33 -06:00
Pedro Amorim 91b4780074
Bug 37762: VueJS framework: Add update event to v-select FormElement
The existing 'selected' event only fires when something is selected, it does not fire when a selection is unselected. onUpdated fires for both.

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:32 -06:00
Pedro Amorim 903da26fe4
Bug 37762: VueJS framework: Fix tooltip within modal dialog
Without this, the tooltip is behind the modal thus invisible

Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:32 -06:00
Pedro Amorim bd9dc920de
Bug 37762: VueJS framework: Allow styling v-select dropdown
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:31 -06:00
Pedro Amorim 3e756390cb
Bug 37762: VueJS framework: Update width of inputs inside modal dialog
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:31 -06:00
Pedro Amorim 38b38bdce6
Bug 37762: VueJS framework: Add cssClass consideration to link buttons
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:30 -06:00
Pedro Amorim 675dd1cac0
Bug 37762: VueJS framework: Add patch to http-client.js
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:29 -06:00
Matt Blenkinsop 9e420632e7
Bug 37762: Allow FormElement to accept hidden inputs
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-08 12:25:23 -06:00
Martin Renvoize 6f62a8fe30
Bug 41919: Limit number of current reports a single user can run simultaneously
Building on bug 41918, it would be good to limit the number of reports
a given user can run at a time. This control is config-file based as
it is tied to the server resources provided by the administrator.

Adds a new koha-conf.xml option total_running_reports_per_user_limit
(0 = disabled). When the configured limit is reached, the user is told
"You have too many reports running at the moment. Please wait for some
of them to finish before running this report again."

Note on implementation: the original patch on bz (attachment 198034)
performed a second pre-flight Koha::Reports->running call in
reports/guided_reports.pl. The bug 41918 QA follow-ups already pushed
the duplicate-running guard into Koha::Report::prep_report so it would
fire across the staff UI, svc/report and opac/svc/report. This patch
extends that same model-layer architecture rather than reintroducing
controller-layer enforcement:

- New Koha::Exceptions::Report::TotalRunning subclass of
  Koha::Exceptions::Report.
- prep_report now performs a second check after the duplicate one and
  throws TotalRunning when the user has total_running_reports_per_user_limit
  reports of any kind already in flight.
- All three callers (guided_reports.pl, svc/report, opac/svc/report)
  catch the new exception alongside DuplicateRunning, mapping it to a
  new template error key total_running_reports_limit_exceeded for the
  staff UI and a JSON {error: total_running_reports_limit_exceeded}
  with HTTP 429 for the JSON endpoints.

Test Plan:
1) Set total_running_reports_per_user_limit to 3 in your koha-conf.xml.
2) Create 3 long-running reports like:
   SELECT COUNT(*) FROM items i1 JOIN items i2 JOIN items i3 JOIN items i4 JOIN items i5 JOIN items i6
3) Run each report in turn by opening a new tab, browsing to the
   reports module, and choosing to run that report.
4) Note the first three continue to run, but a fourth attempt gives
   the new "too many reports running" alert in the staff UI.
5) Repeat against /cgi-bin/koha/svc/report?id=N and confirm an HTTP
   429 response with JSON {error: total_running_reports_limit_exceeded}.
6) Set total_running_reports_per_user_limit back to 0 and confirm
   normal behaviour resumes.
7) prove t/db_dependent/Koha/Reports.t -> 13 tests pass, including a
   new subtest for TotalRunning.

Signed-off-by: Alex Carver [Acerock7] <alex@rcls.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:21 -06:00
Martin Renvoize 1162d2d67c
Bug 41918: (QA follow-up) Refactor Koha::Reports->running
- Fix POD synopsis: invalid syntax and wrong field (userid vs
  borrowernumber) replaced with a correct example and parameter list.
- Build the WHERE clause with parameterised bindings via
  $schema->storage->dbh, removing string interpolation of
  $user_id / $report_id into LIKE patterns and the regex match.
  IDs are formatted with %d so non-integer input becomes 0 and cannot
  inject regex/LIKE metacharacters.
- Return a Koha::Reports resultset instead of a list of MySQL process
  ids. The method name now matches what it returns and callers can use
  the standard ->count / iteration interface. The single in-tree caller
  in reports/guided_reports.pl is updated; the template error key is
  simplified from duplicate_running_report_ids to a boolean
  duplicate_running_report (the ids were never displayed).

Test plan:
1) Apply the previous Bug 41918 patches and this follow-up.
2) Set duplicate_running_reports_per_user_limit to 1 in koha-conf.xml.
3) Restart all the things.
4) Open a long-running saved report in two tabs and run it from both.
5) Verify the second tab shows "This report is already running..."
6) Set the limit to 0 and confirm both tabs run normally.
7) prove t/db_dependent/Reports.t still passes.

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:17 -06:00
Kyle M Hall 7bd64b0f6f
Bug 41918: Prevent a given librarian from running the same report multiple times simultaneously
Test Plan:
1) create a long running report such as:
   SELECT COUNT(*) FROM items i1 JOIN items i2 JOIN items i3 JOIN items i4 JOIN items i5 JOIN items i6
2) Run this report multiple times
3) Note the processes are running via SHOW FULL PROCESSLIST from koha-mysql
4) Kill those processes
5) Apply this patch
6) Restart all the things!
7) Try to run the report in two tabs, note the second tab opened says
   the report is already running!

Signed-off-by: Alex Carver [Acerock7] <alex@rcls.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-07 07:56:16 -06:00
Pedro Amorim 209796ec0b
Bug 41956: Display hold_group_id
Test plan:
1) Enable DisplayAddHoldGroups sys pref
2) Place two title-level holds for the same patron on two different biblios.
3) Group them via the patron's holds page. Note the hold_group_id shown in the table and the URL when you click through to the group page (e.g. hold_group_id=42).
4) Create a second hold group for the same patron with two more holds. Confirm the hold_group_id is shown instead of the previous visual_hold_group_id.
5) Go to Circulation > Holds to pull (/cgi-bin/koha/circ/pendingreserves.pl). Confirm each grouped hold shows 'Hold group 42' as a clickable link, not
   the old 'part of a hold group' text.
6) Go to Circulation > Holds queue (/cgi-bin/koha/circ/view_holdsqueue.pl). Confirm the same — 'Hold group 42' link visible beneath the title.
7) Log in to the OPAC as that patron, go to 'Your summary' > 'Holds' tab. Confirm the 'Hold group' column shows 42.
8) Cancel one hold from the group. Confirm the group still appears on the patron's 'Holds' tab (one hold remains).
9) Cancel the last hold in the group. Confirm the no holds of the group and the group no longer appear on the patron's 'Holds' tab. Check holds history on the Staff UI:
(/cgi-bin/koha/members/holdshistory.pl?borrowernumber=NNN) — both cancelled holds should still show 42 in the 'Hold group ID' column.

Run tests:
prove t/db_dependent/Reserves/HoldGroup.t
prove t/db_dependent/Koha/Hold.t
prove t/db_dependent/Koha/Patron.t
prove t/db_dependent/api/v1/patrons_hold_groups.t
prove t/db_dependent/api/v1/holds.t
prove t/db_dependent/api/v1/patrons_holds.t

Signed-off-by: Bob Bennhoff <bbennhoff@clicweb.org>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-06 15:21:00 -06:00
Pedro Amorim af95e03c08
Bug 41983: Display in UI
Test plan:
0) Update the database (ktd, ignore if sandbox):
$ updatedatabase
1) Enable DisplayAddHoldGroups sys prefs
2) Go to 'Henry' and click 'Search to hold':
<staff_url>/cgi-bin/koha/members/moremember.pl?borrowernumber=19
3) Search for 'test' and click the top 'Select all' link
4) Click the downward arrow in the 'Place hold' button and pick 'Place hold for Henry'
5) Set a pickup location for each hold and tick the 'Treat as hold group' checkbox
6) Click 'Place holds'.
7) Run build_holds_queue.pl:
perl misc/cronjobs/holds/build_holds_queue.pl --force
8) Visit the Holds queue page:
<staff_url>/cgi-bin/koha/circ/view_holdsqueue.pl?branchlimit=&itemtypeslimit=&run_report=1
9) Confirm the 'part of a hold group' bit shows and display the modal like 'Holds to pull'

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>
2026-05-06 15:20:57 -06:00
Owen Leonard b8832e7d7e
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>
2026-05-06 15:20:56 -06:00
Owen Leonard 3160983a6d
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>
2026-05-06 15:20:55 -06:00
Nick Clemens c85f9a02a9
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>
2026-05-06 15:20:55 -06:00
Lucas Gass 2aec8ef17e
Bug 41768: Tidy suggestion.tt
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-06 15:20:54 -06:00
Jonathan Druart f1c3c2d89a
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>
2026-05-06 15:20:54 -06:00
Ayoub Glizi-Vicioso 97b4b2f1db
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>
2026-05-06 15:20:53 -06:00
Martin Renvoize c6a8634ff5
Bug 29016: (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>
2026-05-05 13:42:10 -06:00
Martin Renvoize 19df8f3dfc
Bug 29016: (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>
2026-05-05 13:42:10 -06:00
Martin Renvoize 4710257c21
Bug 29016: (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>
2026-05-05 13:42:09 -06:00
Kyle M Hall 5525953c01
Bug 29016: 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>
2026-05-05 13:42:08 -06:00
Kyle M Hall c861e2dafe
Bug 29016: 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>
2026-05-05 13:42:07 -06:00
Martin Renvoize 9836498611
Bug 42032: (follow-up) Pretty-render authority info column in log viewer
Mirrors bug 42188's biblio log-viewer rendering. Generalise the
biblio-only renderCatalogInfo() helper in viewlog.js to also match
the "authority <JSON>" prefix introduced by the previous follow-up,
and rename it to renderRecordInfo() to reflect its wider scope. The
existing fmtJsonValue() helper already handles MiJ's nested arrays
of subfield objects, so no rendering changes are needed beyond the
regex and name.

Test plan:
1. Enable AuthoritiesLog.
2. Create, edit, and delete an authority via the staff UI.
3. Go to Tools -> Log viewer, filter by module=Authorities.
4. Verify:
   - ADD    row's info cell shows just "authority".
   - MODIFY and DELETE rows' info cells render as a nested list
     (auth_header columns plus _marc leader + fields array).
   - Diff column still renders the before/after struct-diff table.
5. Re-check a biblio (CataloguingLog) entry: still renders as before.
6. Re-check a MEMBERS entry: untouched.

Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-05 13:42:05 -06:00
Martin Renvoize 4bd9e7836b
Bug 42188: (follow-up) Pretty-render biblio info column in log viewer
The CATALOGUING info column for MODIFY/DELETE logs stores "biblio "
followed by a pretty-printed JSON dump of the biblio hashref, which
includes a MARC-in-JSON _marc structure. Raw, this is noisy and hard
for librarians to read in the log viewer.

Extract the nested-object formatter already used by the struct-diff
renderer into a shared fmtJsonValue() helper, and use it from a new
renderCatalogInfo() that runs over each div.loginfo on page load. If
the cell text matches "biblio {JSON}" it is replaced with the pretty
rendering; otherwise the cell is left untouched so non-catalog info
payloads (and the bare "biblio" logged on ADD) are unaffected.

Falling back silently on a parse failure means the old non-JSON
Dumper-format item payloads continue to display as-is.

Test plan:
1. Enable CataloguingLog.
2. Create, edit, and delete a biblio record via the staff UI.
3. Go to Tools -> Log viewer, filter by module=Cataloguing.
4. Verify:
   - ADD row's info cell shows just "biblio".
   - MODIFY and DELETE rows' info cells render as a nested list
     (leader, fields array of tag/indicator/subfield objects, plus
     frameworkcode/opac_suppressed/serial).
   - Diff column still renders the before/after struct-diff table.
5. Check another module's log entries (e.g. MEMBERS) are untouched.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-05 13:42:02 -06:00
Martin Renvoize 873fcbb51f
Bug 42188: Use MARC-in-JSON for biblio action log diffs
Replace the custom _marc_record_to_diffable helper with MARC::Record::MiJ's
to_mij_structure method, which produces standard MARC-in-JSON. This fixes
three problems with the old approach:

- Dollar signs used as subfield delimiters in the formatted string were
  ambiguous when subfield content itself contained " $x " sequences.
- Grouping fields by tag into a hash lost inter-field ordering, making
  lossless reconstruction of the MARC record impossible.
- Non-ASCII characters were subject to Perl string context encoding
  issues; JSON serialisation of the MiJ structure handles UTF-8 cleanly.

_unblessed_for_log in Koha::Biblio is updated to return only the three
biblio columns that are genuinely independent of the MARC record
(frameworkcode, opac_suppressed, serial). The remaining columns
(author, title, subtitle, notes, etc.) are denormalised copies of MARC
data already captured in the _marc key, so including them produced
redundant and noisy diffs.

The fmt() helper in viewlog.js is updated to render JavaScript arrays
as ordered lists rather than objects with numeric keys, improving the
display of MARC subfield arrays in the diff table.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-05 13:42:00 -06:00
David Cook b7e67b5c1d
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>
2026-05-05 13:42:00 -06:00
David Cook faa94eac6f
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>
2026-05-05 13:41:59 -06:00
Simon 39c1917b21
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>
2026-05-05 13:41:48 -06:00
Nick Clemens e3862dc81b
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>
2026-05-01 11:04:36 -06:00
Fridolin Somers 3d8e069a4d
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>
2026-05-01 11:04:32 -06:00
David Cook 8dc79ed415
Bug 42406: (QA follow-up) fix QA tool failure
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-01 11:04:30 -06:00
David Cook ea3b9d9c14
Bug 42406: (QA follow-up) fix little inconsistencies and errors
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-01 11:04:30 -06:00
Nick Clemens 3107cdc368
Bug 42406: Split delete_reports into delete_own_reports and delete_all_reports
This patch splits delete_reports into delete_own_reports and delete_all_reports

While delete_all_reports supercedes delete_own_reports it seems to make more sense than
delete_own_reports and delete_others_reports.

With delete_all_reports we can have a user who can delete all, without specific permission to delete their own
The other way we would have delete others, and you could not delete your own, which seems more odd

To test:
 1 - Have 2 users - 1 with delete_reports, 1 without
 2 - Apply patches, update database
 3 - Confirm user with permission now has 'delete_all_reports' and other user still has no reports deletion permission
 4 - Give the second user 'delete_own_reports' permission
 5 - Create 4 reports as each user
 6 - Confirm view/edit pages show the delete button for each user, and confirm they both work
 7 - You shoudl have 2 reports left for each user
 8 - Confirm each user can delete their own report from the saved SQL list:
     http://localhost:8081/cgi-bin/koha/reports/guided_reports.pl?op=list
 9 - There should be 1 report from each
10 - Give the second user 'delete_all_reports' permission in one tab and reload the saved reports in another tab
11 - Select both reports in the second tab
12 - Remove 'delete_all_reports' from the second user, leaving 'delete_own_reports' in the first tab
13 - Click 'Delete selected' in the reports tab
14 - Confirm you get 'You do not have permission to continue'
15 - Hit back, deselect other users report, confirm you can delete your own with 'Delete selected'
16 - Sign off

Signed-off-by: Judy Poyer <jpoyer@aacpl.net>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
2026-05-01 11:04:29 -06:00
Nick Clemens cdd7438ef6
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>
2026-05-01 11:04:29 -06:00