Commit Graph

9163 Commits

Author SHA1 Message Date
Thibaud Guillot 92cbbd59d5
Bug 32748: (QA follow-up) Fix duplicate AV when limited to several libraries at once
When an authorised value is limited to more than one library, the
no_limit query in GetAuthorisedValues joins authorised_values_branches
and returns one row per associated library, so the value was listed
several times in the item edition dropdown.

Group by the authorised value so each one is only returned once, and
aggregate the restricted flag with MIN() so the value stays
unrestricted as soon as one of its libraries matches the current one.

Sponsored-by: BibLibre
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-15 14:45:06 +00:00
Thibaud Guillot d7f1426d58
Bug 32748: (QA follow-up) Tidy test file
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-15 14:45:05 +00:00
Thibaud Guillot 0794f75adc
Bug 32748: (QA follow-up) Fix cache key and add tests
Sponsored-by: BibLibre
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-15 14:45:03 +00:00
Katrin Fischer a5e8fdccbd
Bug 31391: (QA follow-up) Adjust for changes made by bug 42443
This fixes a test to use 'opac' in transfers.t

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-14 14:15:59 +00:00
Katrin Fischer 77f3567b59
Bug 31391: (QA follow-up) Fix mocked value in Holds.t
The pref was mocked to '1' (the old value) in Holds.t
Test now uses 'opac_and_staff'

Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-14 14:15:58 +00:00
Aleisha Amohia 98c8add185
Bug 31391: Request recalls and convert reserves on staff interface
This enhancement adds the ability to place recalls via the staff
interface by changing the UseRecalls system preference to have choices which
describe where recalls can be placed. Recalls can either be placed via
the OPAC, or the staff interface, or both. To be set to OPAC would be
consistent with current 'on' behaviour. UseRecalls is turned off by default.

This enhancement also adds the ability to convert existing holds to
recalls easily via the staff interface. The hold will be cancelled
and a recall placed using the hold's information.

To test:
1) Update database and restart services
2) Set UseRecalls to OPAC and set the relevant recalls circulation rules
OPAC only by default
3) Check out Item A to Patron B.
4) Log into the OPAC as Patron A. Confirm you can place, view and cancel
recalls as normal.
5) In the staff interface, set UseRecalls to Staff interface only.
6) In the OPAC, confirm you can still view and cancel recalls, but can
no longer place recalls.
7) In the staff interface, search for Item A and go to the Holds tab.
Place a hold for Patron C.
8) Check the checkbox for your hold and confirm the counts in the buttons above the Holds table are incremented as expected.
9) Click the button to Convert selected holds to recalls, a modal should pop up. Confirm all of the information is correct.
10) Confirm the conversion and once the page refreshes, your hold should be correctly cancelled using the new RECALLED reason.
11) Go to the Recalls tab. Confirm your hold has been converted to a
recall, and details like the patron, expiration, and pickup location have
carried across to the recall.
12) On this Recalls page, use the patron search to find Patron D. Test
placing a record-level recall by choosing to recall the next available item.
13) When the page refreshes, confirm the recall was successfully placed
with the correct details stored.
14) Repeat steps 12 and 13 with Patron E, this time place an item-level
recall by choosing an item in the 'place a recall on a specific item'
table. When selecting one of these items, the 'recall next available
item' section should become disabled.
15) Set UseRecalls back to OPAC only. Go back to the record and
view the Recalls tab.
16) Confirm you cannot search for a patron to place a recall, but can
still view and cancel recalls. Confirm you also cannot convert holds
to recalls.
17) Set UseRecalls to both staff interface and OPAC. Confirm you
can place recalls on both interfaces.
18) On the staff interface, test placing recalls that your circulation
rules do not allow. For example, if 'recalls per record' is 1, ensure
you're blocked from placing a second recall on a record for a patron. Another example, testing converting a hold to a recall when there are NO checked out items, as recalls can only be placed if something is checked out.
19) Place a hold for one of the patron's that already has a recall.
Once complete, try to convert this hold into a recall. Confirm you
are blocked and shown a message that the hold cannot be converted to a
recall.
20) Confirm patron messaging preferences for recalls notices can still be configured as expected.
21) Ensure tests pass:

* t/db_dependent/Circulation.t
* t/db_dependent/Circulation/transferbook.t
* t/db_dependent/Holds.t
* t/db_dependent/Koha/Biblio.t
* t/db_dependent/Koha/Item.t
* t/db_dependent/SIP/Transaction.t
* t/db_dependent/Search.t
* t/db_dependent/XSLT.t

Sponsored-by: Auckland University of Technology
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-09-14 14:15:54 +00:00
Aleisha Amohia b9b80b9471
Bug 31391: Implement UseRecalls choices in tests
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-09-14 14:15:51 +00:00
Pedro Amorim c6bf858253
Bug 34632: (QA follow-up) Use Koha::Uploader for patron import files
Large files were failing to enqueue/process because the whole CSV was
embedded in the job's JSON args, hitting DB/broker size limits. This
now uploads the file via Koha::Uploader first (same pattern as MARC
staging) and only passes a small uploaded_file_id through the job,
and fixes the enqueue-failure message to not claim nothing happened
when a job was in fact created.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-11 16:06:05 +00:00
Pedro Amorim c8c24445af
Bug 34632: Add tests for Koha::BackgroundJob::PatronImport
Tests cover enqueue() (status, queue, job_size, job_type) and six
process() scenarios: happy path, import errors (with validation that
the 25-error cap has been removed), already_in_db and overwritten,
patron list creation, and cancelled job handling.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-11 16:06:02 +00:00
Kyle M Hall 115d26ecae
Bug 42679: (QA follow-up) Add tests for missing permissions and non-overdue checkouts
The existing tests pass even if the endpoint counts all checkouts
instead of overdues only. This patch adds a checkout due in the future
and tests the count is unchanged. It also tests that a patron without
the borrowers flag gets a 403.

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-11 16:05:58 +00:00
Tomás Cohen Arazi f7caec076f
Bug 42679: Add GET /patrons/{patron_id}/overdues_count endpoint
Returns the count of overdue checkouts for a patron as a plain integer.
Computed live from the database (date_due < NOW()) to ensure accuracy,
as overdue status is time-based with no discrete event to trigger updates.

This endpoint is intended for async loading in the patron search table,
allowing the main search results to render immediately while overdues
are fetched separately per visible page.

Test plan:
1. Apply patch
2. Run:
   $ ktd --shell
   k$ prove t/db_dependent/api/v1/patrons_overdues_count.t
=> SUCCESS: Tests pass!
3. Sign off :-D

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

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-11 16:05:56 +00:00
Jonathan Druart fe8a9a5529
Bug 43330: Simplify tests
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-11 15:07:04 +00:00
Laura_Escamilla d5f522e526
Bug 43330: Add regression test for TagsExternalDictionary
To test:

1. Set the TagsExternalDictionary system preference to a non-empty value, for example:

       /usr/bin/ispell

2. Restart Plack if necessary.

3. Visit a staff interface page which loads C4::Tags, such as the staff home page or a bibliographic detail page.

4. Observe:

       Undefined subroutine &C4::Tags::check_install called at C4/Tags.pm line 44.
       BEGIN failed--compilation aborted at C4/Tags.pm line 53.
       Compilation failed in require.
       BEGIN failed--compilation aborted.

5. Clear TagsExternalDictionary and clear/update the system preference cache.

6. Apply the patch.

7. Set TagsExternalDictionary to an empty value.

8. Verify that you can access the home page and other pages.

9. Set TagsExternalDictionary to a valid non-empty path such as
	/usr/bin/ispell

10. Verify the staff home page, catalog detail page, and Tools page load without HTTP 500 errors.

11. Prove t/db_dependent/TagsExternalDictionary.t
12. Sign off and have a great day! :D

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-09-11 15:07:03 +00:00
Andreas Jonsson 7dbc37e187
Bug 43346: Unit test for payment without userenv
MarkIssueReturned needlessly fails when called from a session with no
logged in user such as a script or anonymous callback.  A specific
application where this is a problem when completing a payment
transaction in a plugin for opac online payment wich may be done via
polling or callback.

This unit test verifies that a payment can be completed when paying a
fee for a lost item with MarkLostItemsAsReturned set to onpayment and
no userenv set.

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-11 15:06:58 +00:00
Jonathan Druart 18134d8343
Bug 41318: Rename AmazonLocale to AmazonLocaleTld
To be more flexible we could allow the top-level domain instead of
having a predefined list.
However this patch still list the different available options (and adds
Brazilian) for easy selection.

Note that this system preference is not used to retrieve the image but
only to link to from the image. Contrary to what the reporter of the bug
report thought. And actually what I thought as well until I finished to
write the patch and started testing it!
Anyway now the patch is written, there should not be any changes in
behaviour. Most of the time the links are actually broken when not using
.com. So I think we either broke the whole feature at some point, or it
never really worked. On a separate bug we could eventually have a look
at fetching from the locale tld.

Test plan:
Turn on OPACAmazonCoverImages and AmazonCoverImages
http://localhost:8081/cgi-bin/koha/catalogue/detail.pl?biblionumber=5
http://localhost:8080/cgi-bin/koha/opac-detail.pl?biblionumber=5
=> You see the PBP cover
click on it, it opens the lightbox, click "(see the original image)" at
the bottom
=> This is where the syspref AmazonLocale/AmazonLocaleTld acts

Modify the syspref's value and confirm that the link is modified and
point to the correct domain (leading to 404 or broken pages most of the time,
at least in my tests).

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:25:34 +00:00
Nick Clemens a571b00a31
Bug 10190: (QA follow-up) Add new permission to tests
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:25:22 +00:00
Chloe Zermatten 763dc46e31
Bug 10190: (follow-up): test: cypress tests update
New tests:
- regression: mtt cells render as .fallback (bold italics)
- bg-success-subtle highlight on completed steps in the add flow
- disabled-Delete states:
  - patron category filter set
  - item type filter set
  - default library, if any library has a trigger higher that default's highest
- redirect to admin home if not permitted to access the page
- in the edit/add stepper form
  - check row actions are enabled at the 'selectOrAdd' step
  - check row actions are disabled once add mode is entered
- check the action column is always available on the main page

Clean up / general updates:
- replace the /api/v1/** catch-all intercept with per-endpoint intercepts so @get-rules waits resolve reliably
- remove now-redundant cy.wait("@get-rules") calls
- drop unused mount / dayjs / dates imports
- ensure expected strings match UI where strings have changed

Assisted-by: Claude Opus 4.7 (Anthropic)

AI used to draft enhancements tests. Changes were reviewed, tweaked, and commited manually and gradually (with a pre-submission commit squash). Tests were run multiple times and adjusted iteratively to match code changes, cover regressions as those were found, and handle vue page load.

Sponsored-by: Glasgow Colleges Library Group <https://library.cityofglasgowcollege.ac.uk>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:25:19 +00:00
Chloe Zermatten 0fa640b387
Bug 10190: (QA follow-up) UI/UX improvements and fixes
- Refactor (prepation): Extract form sub-components for better maintainability
  - Template stucture improvements (eg. consistent fieldset use)
  - Ensure triggerNumber is always cast to integer from query params
  - Add/Edit trigger form UI/UX improvements/fixes:
      - Restore add/edit button functionality on trigger tables in the form
      - Update Context section title to dynamically change depending on whether editing or displaying
      - Display trigger context as informational when not in confirmContext mode
      - Hide required labels and validation on view-only context fields
      - Always display trigger context at the top of the form
      - Add renewal/autorenewal summary (renewals allowed, automatic renewal) to circulation rules summary panel
      - Sort notice letter dropdowns by name rather than code
      - Update Circulation rules summary title to be more descriptive
  - Scroll behaviour improvements:
      - Extract scrollToElementById to store with polling and null guard
      - Block page scroll when modal is open
      - Disambiguate duplicate trigger-table element ids (trigger-table-main
        vs trigger-table-form) to fix unpredictable scroll-to behaviour

Assisted-by: Claude Sonnet 4.6 (Anthropic)

Experimenting a little here - not quite certain where we draw the line for substantial use so I thought I would add a description in case it's useful, especially since the AI code guidelines are quite fresh:

AI was used primarily to help parse longer Vue templates (CirculationTriggersFormAdd.vue) and help isolate elements for extractions as well as highlight template formatting inconsistencies and propose improvements. The refactoring itself was achieved starting from AI-proposed changes which were then thoroughly re-worked manually towards the code changes submitted.
I also trialled using it (currently experimenting with this) for minor coding tasks where there is a clear precedent (for example, to add renewal/autorenewal information and do so in a way that follows exactly what we had written).
In those cases, each code change made by AI was the outcome of multiple iterations with direct feedback (which it did require a fair amount of) from me to ensure the output matched what I would have written myself.

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:25:14 +00:00
Martin Renvoize 88b16e6445
Bug 10190: Enforce manage_circ_rules_from_any_libraries permission
- Add OR-type x-koha-authorization to /circulation_rules, /circulation_rules/kinds,
  and /circulation_rules/config endpoints so users with either
  circulate:circulate_remaining_permissions OR parameters:manage_circ_rules
  can access them
- Enforce manage_circ_rules_from_any_libraries in the set_rules controller:
  users without this permission may only set rules for their own library and
  cannot set default (*) rules
- Add explicit use C4::Auth qw(haspermission) import to CirculationRules.pm
- Lock the library selector in the Vue UI for users who lack
  manage_circ_rules_from_any_libraries, defaulting them to their own library
- Update set_rules() tests to cover the new permission restrictions

Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:25:02 +00:00
Martin Renvoize c53a2ead10
Bug 10190: fix failing Permissions.t and overhaul CirculationTriggers Cypress spec
Permissions.t:
- Remove edit_notice_status_triggers from userpermissions.sql so fresh installs
  no longer seed this deprecated permission (existing installs are handled by
  the atomic update)
- Add a defensive DELETE in the test to cover DBs that pre-date the atomic update

CirculationTriggers_spec.ts:
- Fix getMockCirculationRule: the helper was returning the old {rule_name,
  rule_value, branchcode, ...} format; update to the current API format
  {context: {...}, overdue_N_delay: ..., ...}
- Remove assertions for UI elements that do not exist (success/error flash
  messages, "Existing triggers" heading, "rule set will be removed" text)
- Fix reset confirmation text to match actual component output
- Fix duplicate patron_category_id "ST" in mock patron categories
- Remove aspirational tests that checked non-implemented behaviour
- Add describe block for the no-default-triggers warning (no rules anywhere,
  rules only at specific libraries, library link switches the filter)
- Add regression test for NaN trigger number when adding first rule for a library

Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:58 +00:00
Martin Renvoize f631df5afd
Bug 10190: Fix test count in overdues.t
Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:57 +00:00
Chloe Zermatten 8c8160761d
Bug 10190: Deprecate permission
user_permissions rows do not need manual cleanup because the FK on
user_permissions(module_bit, code) references permissions(module_bit, code)
ON DELETE CASCADE, so deleting from permissions automatically removes
per-patron rows.

Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:48 +00:00
Chloe Zermatten b8f8175539
Bug 10190: (QA follow-up) typo
Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:41 +00:00
Martin Renvoize 1dc42db13b
Bug 10190: Comprehensive Cypress tests for Circulation Triggers UI
This patch significantly enhances the Cypress test coverage for the new
Circulation Triggers administration interface, expanding from basic
breadcrumb checks to comprehensive end-to-end testing.

Test Coverage:
- Initial page load and API error handling
- Context filtering (library, patron category, item type)
- View toggling between explicit and all applicable rules
- Tab navigation between multiple triggers
- Full CRUD operations (Create, Read, Update, Delete)
- Rule set reset functionality
- Letter template filtering by library context
- Form validation and constraint checking
- Loading states and empty states
- Error handling for all operations
- Browser navigation (back/forward buttons)
- Complex scenarios with inheritance hierarchies

New Features:
- Mock data helper functions for test fixtures
- Comprehensive API interception for all endpoints
- Tests for both success and error paths
- Placeholder value testing for fallback rules
- Increment/decrement button testing
- Multi-step form workflow validation
- Confirmation dialog testing for destructive operations

The tests follow Koha's Cypress testing patterns established in the
ERM module, using proper API mocking, clear test descriptions, and
organized test suites.

Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:31 +00:00
Martin Renvoize 8d5d976ff0
Bug 10190: Remove old overduerules interface
This patch updates the link from the tools homepage to open the new
circulation triggers administration page.

We then remove the old overduerules controller and template, and finally
we drop the no longer referenced
C4::Overdues::GetOverdueMessageTransportTypes method and associated unit
tests.

Sponsored-by: Glasgow Colleges Library Group <https://library.cityofglasgowcollege.ac.uk>
Signed-off-by: George Harkins <George.Harkins@cityofglasgowcollege.ac.uk>
Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:29 +00:00
Martin Renvoize 4eb521ba18
Bug 10190: Migrate MarkIssueReturned test to circulation rules
Sponsored-by: Glasgow Colleges Library Group <https://library.cityofglasgowcollege.ac.uk>
Signed-off-by: George Harkins <George.Harkins@cityofglasgowcollege.ac.uk>
Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:28 +00:00
Martin Renvoize d4e951b3d8
Bug 10190: Update GetBranchcodesWithOverdueRules to use CirculationRules
This patch updates the C4::Overdues method
GetBranchecodesWithOverdueRules to refer to the new location of these
rules in the circulation rules table. We also update the unit tests to
move the mocked data into the right location.

We could perhaps migrate this method in Koha::CirculationRules at a
later date?

Sponsored-by: Glasgow Colleges Library Group <https://library.cityofglasgowcollege.ac.uk>
Signed-off-by: George Harkins <George.Harkins@cityofglasgowcollege.ac.uk>
Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:22 +00:00
Martin Renvoize ca8fc3d8e9
Bug 10190: Fix unit test to exclude _X_ rules
Sponsored-by: Glasgow Colleges Library Group <https://library.cityofglasgowcollege.ac.uk>
Signed-off-by: George Harkins <George.Harkins@cityofglasgowcollege.ac.uk>
Signed-off-by: Michaela <michaela.sieber@kit.edu>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-10 14:24:20 +00:00
Andrii Nugged d64d02761d
Bug 43344: Use the current source alias in filter_by_active
Bug 36018 qualified the quantity column with the default "me" alias to
avoid ambiguity when joined tables also have a quantity column.

DBIx::Class does not always use "me" for related resultsets. The
many-to-many item_orders relationship uses "ordernumber", so evaluating
item.orders.filter_by_active from the OPAC refers to a non-existent
me.quantity column.

Use current_source_alias to qualify quantity with the alias of the actual
resultset. Add regression coverage for filtering active orders through the
item relationship.

Test plan:
Before applying the patch:
1. Set OPACAcquisitionDetails to Show.
2. Set AcqCreateItem to create an item when placing an order.
3. Create a basket and add an order for a bibliographic record, including an
   item.
4. Close the basket so the order is active and outstanding.
5. Open the bibliographic record in the OPAC.
6. Confirm the item is not shown as On order and the log contains an Unknown
   column 'me.quantity' error.

Apply the patch.

After applying the patch:
1. Open the same bibliographic record in the OPAC again.
2. Confirm the item is shown as On order and the SQL error is gone.

Co-Authored-By: Loontik <loontik@nugged.team>
Signed-off-by: Olivia Reynolds <olivia.reynolds@openfifth.co.uk>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-09 15:49:59 +00:00
Jacob O'Mara 77057b3628
Bug 39658: Tests: Add API tests for patron account links endpoints
Test GET/POST/DELETE /api/v1/patrons/{id}/account_links.
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:36 +00:00
Jacob O'Mara 1cb693317e
Bug 39658: Tests: Add unit tests for Koha::Patron::AccountLink
Test linking, group management, and linked_accounts methods.
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:35 +00:00
Martin Renvoize b210605ef7
Bug 30144: (QA follow-up) Fix t/Ediorder.t for JSON servicing_instruction format
Bug 30144 changed Koha::Edifact::Order::gir_segments() to expect
servicing_instruction as a JSON-encoded array of instruction groups
(added by Bug 41709 while working with the older plain-string format
that predated Bug 30144's change was never adapted to match).

As a plain string no longer decodes as JSON, gir_segments() silently
skipped the servicing instruction elements, leaving the GIR split and
special-character tests comparing against undef.

Test plan:
1. prove t/Ediorder.t
   => 4 tests failed before this patch, all pass after
2. prove t/db_dependent/Koha/Edifact/Order.t
   => still passes

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:21 +00:00
Pedro Amorim 52e6e3ad53
Bug 41728: (RM follow-up): Add AddReturn marks ISO18626 request as LoanCompleted
Regression test from the RM's QA review (attachment 204865, comment
104/105 on the bug): drives a real ISO18626 request through AddReturn
and confirms it gets marked LoanCompleted and receives a
supplyingAgencyMessage, rather than only checking that the $messages
hashref no longer contains a stray NotIssued key. This closes the gap
the "Remove leftover duplicate data-consistency block" follow-up left
- that fix restored the $iso18626_request assignment, but nothing
previously exercised the ISO18626 progress-reporting path end to end.

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>

Test plan:
1. prove t/db_dependent/Circulation.t
=> SUCCESS: 91 tests pass.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:07 +00:00
Martin Renvoize e0d32e073a
Bug 41728: (QA follow-up) Add coverage for the Wrongbranch blocker
No test in the suite asserted on $messages->{Wrongbranch} content
despite this being one of the blockers AddReturn's rewired
availability check produces (AllowReturnToBranch enforcement, moved
into Koha::Item->can_be_returned_at / Koha::Item::Availability::Checkin
by this bug). Add coverage for it.

Test plan:
1. prove t/db_dependent/Circulation.t
=> SUCCESS: 88 tests pass.

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:06 +00:00
Martin Renvoize fbe7c7a60f
Bug 41728: (QA follow-up) Move Item::Checkin::Availability to Item::Availability::Checkin
Introduce a dedicated Koha::Item::Availability::* namespace for checkers
that return a Koha::Result::Availability. Keeping these under the Item
subject prefix keeps them co-located with the Item they describe, while
the Availability sub-namespace gives future parallel checkers
(Checkout, Hold, Book, ...) an obvious home rather than scattering them
as single-file directories alongside Koha/Item/Transfer/ etc.

The $item->checkin_availability convenience method on Koha::Item is
preserved; only its internal delegation target changes.

Renames:
  Koha::Item::Checkin::Availability -> Koha::Item::Availability::Checkin
  Koha/Item/Checkin/Availability.pm -> Koha/Item/Availability/Checkin.pm
  t/db_dependent/Koha/Item/Checkin/Availability.t
    -> t/db_dependent/Koha/Item/Availability/Checkin.t

Test plan:
  prove t/db_dependent/Koha/Item/Availability/Checkin.t
  prove t/db_dependent/Circulation/Returns.t

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:02 +00:00
Martin Renvoize be74523028
Bug 41728: (QA follow-up) Move Availability::Result to Result::Availability
Consolidate result base classes under the Koha::Result::* namespace
alongside the existing Koha::Result::Boolean. This keeps return-value
wrappers discoverable in one place and avoids a lone Koha::Availability::
namespace that would otherwise host a single base class.

Renames:
  Koha::Availability::Result -> Koha::Result::Availability
  Koha/Availability/Result.pm -> Koha/Result/Availability.pm
  t/Koha/Availability/Result.t -> t/Koha/Result/Availability.t

Call sites in Koha::Item, Koha::Item::Checkin::Availability, and the
test files are updated accordingly.

Test plan:
  prove t/Koha/Result/Availability.t
  prove t/db_dependent/Koha/Item/Checkin/Availability.t

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:24:01 +00:00
Tomás Cohen Arazi dece71cb3e
Bug 41728: (follow-up) Add no_short_circuit option to checkin availability
This follow-up replaces the unconditional removal of short-circuit logic
with a caller-controlled no_short_circuit parameter, following the same
pattern established by Koha::Patron->can_place_holds.

By default, check() short-circuits on the first blocker. This is the
correct behavior for AddReturn, which processes blockers sequentially
and only acts on the first one it finds (BlockedWithdrawn => early return,
Wrongbranch => early return, BlockedLost => sets doreturn=0). Running all
policy checks only to discard the results is wasteful, specially when
some of them (e.g. can_be_returned_at) hit the database.

When no_short_circuit => 1 is passed, all checks run and all blockers
are collected. This is the behavior API consumers will need: present the
full set of issues in a single response instead of requiring
fix-one-recheck cycles.

Test plan:
1. Apply patch
2. Run:
   $ ktd --shell
  k$ prove t/db_dependent/Koha/Item/Checkin/Availability.t
=> SUCCESS: Tests pass!
  k$ prove t/db_dependent/Circul*
=> SUCCESS: Tests pass!
3. Sign off :-D

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:59 +00:00
Martin Renvoize 84bcca727a
Bug 41728: (QA follow-up) Collect all blockers instead of short-circuiting
Remove early returns from Koha::Item::Checkin::Availability::check() so
that all blockers, confirmations, and warnings are collected in a single
pass. Previously, the first blocker triggered an early return, meaning
callers could only discover one problem at a time.

This is particularly useful for API consumers who want to present the
full set of issues to the user in a single response rather than
requiring fix-one-recheck cycles.

The change is safe for AddReturn because it already handles blocker
priority through its sequential if/return structure:
  1. BlockedWithdrawn → early return before status updates
  2. Wrongbranch → early return after status updates
  3. BlockedLost → sets doreturn=0

Even when multiple blockers are present, AddReturn processes them in
the correct priority order.

Also makes existing tests deterministic by explicitly setting withdrawn
and itemlost values on test items, preventing random TestBuilder values
from triggering unrelated blockers now that all checks always run.

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:58 +00:00
Martin Renvoize 8391917bab
Bug 41728: (QA follow-up) Restore withdrawn warning and use from availability
Restore the withdrawn warning in Koha::Item::Checkin::Availability that
was incorrectly removed. This warning is set when an item is withdrawn
but BlockReturnOfWithdrawnItems is off, making it useful for API
consumers in subsequent work.

Update AddReturn to read the withdrawn state from the availability
result's warnings rather than re-checking $item->withdrawn directly,
avoiding duplication of logic.

Add test for the withdrawn warning (non-blocked) path.

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:57 +00:00
Kyle M Hall dad9fd4a30
Bug 41728: (QA follow-up) Fix test accessing wrong key for checkout
The test was checking $result->{issue} which doesn't exist on the
Result object. The correct accessor is $result->context->{checkout},
so the assertion was always trivially true.

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:51 +00:00
Kyle M Hall e822660311
Bug 41728: (QA follow-up) Populate checkout context before blocker checks
The availability check is returning early on blockers (BlockedWithdrawn,
BlockedLost, Wrongbranch) before checking if the item had an active
checkout. This causes AddReturn to lose checkout/patron context for
checked-out items that hit a blocker, resulting in incorrect NotIssued
messages, unintended onloan clearing, and incorrect local use recording.

Move the checkout check to run first so context is always populated
regardless of blockers.

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:48 +00:00
Tomás Cohen Arazi cb3deeadcc
Bug 41728: (follow-up) Add transfer limit check and clean param names
- Rename params: branch => library, add to_library for destination
- Move $returnbranch computation before the availability check in
  AddReturn so it can be passed as to_library
- Add transfer limit check (bug 7376) to the Availability class
- Rename internal _can_book_be_returned to _check_return_policy
- Remove duplicate $returnbranch block and standalone transfer
  limit check from AddReturn
- Update tests for new param names

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:47 +00:00
Tomás Cohen Arazi 9b8328c3f5
Bug 41728: Add Koha::Item::Checkin::Availability class
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:44 +00:00
Tomás Cohen Arazi b5041ae361
Bug 41728: Add Koha::Availability::Result base class
This patch introduces a standardized result class for availability checks,
providing a clean API with proper methods instead of raw hashrefs.

The Koha::Availability::Result class provides:
- add_blocker() - Add conditions that prevent the action
- add_confirmation() - Add conditions requiring user confirmation
- add_warning() - Add informational messages
- set_context() - Store related objects (item, checkout, patron, etc.)
- available() - Check if action can proceed (no blockers)
- needs_confirmation() - Check if confirmations are required
- Accessor methods for all categories
- to_hashref() for backward compatibility

This design:
- Provides a consistent interface across all availability checks
- Makes the API more discoverable and self-documenting
- Enables future enhancements without breaking changes
- Follows OO principles with proper encapsulation
- Can be used as base for checkout, hold, renewal availability

Test plan:
1. Apply patch
2. Run:
   $ ktd --shell
  k$ prove t/Koha/Availability/Result.t
=> SUCCESS: Tests pass!
3. Verify all methods work correctly
4. Sign off :-D

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-04 11:23:43 +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 e5a07ccd25
Bug 42443: (QA follow-up) Test from_library_id query filter
The OpenAPI spec documents from_library_id as a supported filter
parameter but the test suite only exercised to_library_id. Add a test
to verify filtering by source library returns the correct transfer.

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:36 +00:00
Martin Renvoize 02a02c7209
Bug 42443: (QA follow-up) Test UseRecalls integration in transfer cancel
The delete() controller reverts any in-transit recall tied to the item
when UseRecalls is enabled. Add a subtest to verify the recall status
is set back to 'requested' after the transfer is cancelled.

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:35 +00:00
Martin Renvoize f8d59a7b50
Bug 42443: (QA follow-up) Prevent cancelling completed transfers
The delete endpoint was passing force => 1 to cancel() with no state
guards, allowing already-received and already-cancelled transfers to
be re-cancelled, corrupting datearrived/datecancelled audit fields.

Add explicit 400 responses for both cases and tests to cover them.

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:30 +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 4fc5617615
Bug 42443: Add unit tests
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:26 +00:00
Paul Derscheid 90281d5a1f
Bug 42997: (QA follow-up) Don't invert the booking period when syncing end dates
Collecting a booking early (within the bookings lead period) with a
due date override before the booking start syncs end_date to a date
that precedes start_date. Koha::Booking->store has no interval
validation and the clash checks' date windows never see the inverted
period, so the broken row is stored silently - reproduced via AddIssue
on this patchset.

- pull start_date back to the checkout date whenever the synced due
  date precedes it, in both AddIssue and AddRenewal, so the booking
  window follows the loan instead of inverting
- cover both paths in Circulation.t; the AddRenewal case needs the
  Biblio::check_booking exemption from the previous patch, as the
  synced window no longer overlaps the stored one

Test plan:
1. prove t/db_dependent/Circulation.t
2. Set bookings_lead_period to e.g. 5 for an itemtype and enable
   SpecifyDueDate
3. Book an item of that itemtype for a patron starting in 3 days
4. Check it out to them today with an explicit due date of tomorrow
5. Without this patch the booking is stored with end_date before
   start_date; with it both dates follow the checkout period

Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 15:53:58 +00:00
Paul Derscheid 8bd9790e47
Bug 42997: (QA follow-up) Don't let a booking's own checkout block it in Biblio::check_booking
Koha::Biblio->check_booking counts current checkouts on bookable items
against the pool of available items. Like Item::check_booking before
this patchset, it made no exception for the checkout that belongs to
the very booking being validated, so updating an issued booking's
period could clash against its own loan whenever the new period no
longer overlaps the stored one (the item_id exemption for booked items
only catches bookings that overlap the window under test).

This is masked in the end_date syncs earlier in this patchset because
the synced window always contains the stored start_date; it surfaces
as soon as a sync moves the whole period, and would equally bite the
extension pathway on bug 42790.

- skip checkouts whose booking_id matches the booking being validated
  when counting occupied bookable items, mirroring the
  Item::check_booking exemption
- cover the blocking and non-blocking checkout cases in Biblio.t

Test plan:
1. prove t/db_dependent/Koha/Biblio.t

Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 15:53:57 +00:00
Martin Renvoize 50115d8322
Bug 42997: Sync booking end_date with the due date at renewal
When a checkout satisfying a booking is renewed, the booking previously
kept its original end_date, blocking the booked period from other
patrons for the wrong window and leaving the two records out of sync.

This patch updates C4::Circulation::AddRenewal to pull the linked
booking's end_date along with the renewed due date, mirroring the
behaviour introduced for AddIssue earlier in this patchset. As at
issue time, if the new due date would clash with a subsequent booking
(possible when the renewal was explicitly allowed past a clash), the
booking keeps its original end_date.

Together with the previous patch this makes a renewal the natural way
to extend an issued booking: CanBookBeRenewed refuses renewals that
would run into the next booking, and AddRenewal keeps the booking in
step with the loan.

Test plan:
1) Run t/db_dependent/Circulation.t and confirm the new
   'AddRenewal | booking end_date sync' subtest passes
2) Check out a booked item, renew it from the checkouts screen and
   confirm the booking end date follows the new due date

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:55 +00:00
Martin Renvoize 2da3248b41
Bug 42997: Prevent renewals running into the next booking
CanBookBeRenewed checked bookings by asking Koha::Item->find_booking
for the first booking that clashes with the renewal period. When the
renewing patron's own booking satisfies this checkout, that booking is
returned first and renewal is allowed - subsequent bookings for the
item were never considered. A patron could therefore renew a booked
item straight through the start of the next patron's booking.

Additionally, when staff renew with an explicit due date (the renewal
due date input on the checkouts screen, or the hard due date on
circ/renew.pl), CanBookBeRenewed validated a *calculated* due date
whilst AddRenewal then applied the *requested* one, so the requested
date was never checked against bookings at all.

This patch:

* repeats the booking lookup with the patron's own booking excluded,
  refusing the renewal ('booked') when it would run into the next
  booking for the item
* adds an optional $date_due parameter to CanBookBeRenewed, used in
  place of the calculated due date for the bookings check, and threads
  the requested date through from svc/renew and circ/renew.pl

Test plan:
1) Run t/db_dependent/Circulation.t - the extended
   'CanBookBeRenewed | bookings' subtest covers both the calculated
   and requested due date cases
2) Check out a booked item to its patron, add a subsequent booking for
   another patron, and attempt to renew past the second booking's
   start date from the checkouts screen; confirm the renewal is
   refused as 'booked'

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:53 +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
Martin Renvoize 41c453eff9
Bug 42997: Don't let a booking's own checkout block it in check_booking
Koha::Item->check_booking refuses any booking period that starts before
the item's current checkout is due back. That is correct when assessing
a new booking against someone else's loan, but it also fired when the
checkout in question is the booking's own linked loan - making it
impossible to ever move an issued booking's end_date, as any update
would 'clash' with its own checkout.

This patch skips the checkout guard when the checkout's booking_id
matches the booking_id passed for exclusion, i.e. when the checkout
belongs to the very booking being updated. This is a prerequisite for
keeping booking end dates in sync with checkout due dates in this
patchset, and for the booking extension pathway on bug 42790.

Test plan:
1) Run t/db_dependent/Koha/Item.t and confirm the check_booking
   subtest passes, including the two new checkout-related tests

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:51 +00:00
Martin Renvoize 67e0051e1f
Bug 42997: Sync booking end_date with due date override at checkout
When a booked item is checked out, the due date defaults to the booking
end_date. Staff may override the due date at checkout time, which
previously left the booking end_date out of sync with the checkout,
blocking the booked period for longer or shorter than the actual loan.

This patch updates C4::Circulation::AddIssue to sync any due date
override back to booking.end_date the moment the booking transitions to
'issued', keeping the booking and the checkout aligned from the point
of issue. The existing Koha::Booking->store clash detection is used to
guard the update: if the overridden due date would clash with a
subsequent booking for the same item, the checkout proceeds with the
booking's original end_date instead.

Test plan:
1) Run t/db_dependent/Circulation.t and confirm the new
   'AddIssue | booking end_date sync with due date override' subtest
   passes
2) Create a booking for a patron on a specific item
3) Check the item out to the patron, overriding the suggested due date
4) Confirm the booking's end_date now matches the overridden due date

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:50 +00:00
Paul Derscheid a70df61623
Bug 39829: (QA follow-up) Fix test plan count
Signed-off-by: Paul Derscheid <paul.derscheid@lmscloud.de>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:56:54 +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
Tomás Cohen Arazi b31751a6cd
Bug 42565: Fix uninitialized value warning in GetIssuingCharges
GetIssuingCharges overwrites its initial $charge = 0 with the value of
itemtypes.rentalcharge, which is NULL when no rental charge is configured.
This causes 'uninitialized value' warnings in every caller that compares
$charge > 0 (automatic renewals, SIP checkout/renew, OPAC).

The fix normalizes NULL to 0 at the source. All callers already treat
the return value as numeric, so this is safe. Also removes a now-redundant
$charge && guard in AddIssue that was working around this.

Test plan:
1. Apply patch
2. Run:
   $ ktd --shell
   k$ prove t/db_dependent/Circulation.t
   => SUCCESS: Tests pass!
3. Sign off :-D

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Chris Mathevet <chris.mathevet@inLibro.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-03 10:56:49 +00:00
Pedro Amorim 9d0b71511b
Bug 42653: Add tests
prove t/db_dependent/Koha/ILL/Request.t
prove t/db_dependent/Koha/Plugins/ILL/Backends.t

NOTE: These must be run without having any ILL backend plugin installed

Signed-off-by: Hannah Prince <helm.consortium.nhs.net>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-09-01 15:42:18 +00:00
Jonathan Druart 3934a2bcc0
Bug 43117: Restore use Test::NoWarnings
From
  commit 6cc683b518
  Bug 34776: Unit tests

-use Test::NoWarnings;
-use Test::More tests => 2;
+use Test::More tests => 1;
+use Test::MockModule;
+#use Test::NoWarnings;

Test plan:
Apply the first patch
 prove xt/use-test-no-warnings.t
=> FAIL
Apply this patch
 prove xt/use-test-no-warnings.t
=> PASS
 prove t/Form_MessagingPreferences.t
=> PASS

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:02 +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 0f7145e4af
Bug 42727: Add tests
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:42 +00:00
Jonathan Druart 0c952e9e09
Bug 43241: Add tests for timezone support in RFC3339 q= queries
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>

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:38 +00:00
Tomás Cohen Arazi fd87c5f195
Bug 43241: (follow-up) Use form => for q= params in tests
The + character in RFC3339 timezone offsets (e.g. +00:00) is decoded
as a space when interpolated directly into a URL query string. Use
Test::Mojo form => { q => ... } which properly URL-encodes the
parameter value.

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
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:37 +00:00
Tomás Cohen Arazi 811e57c441
Bug 43241: Add tests for datetime/boolean fixup inside DBIC operators
This patch adds regression tests proving that RFC3339 datetime values
and boolean values nested inside DBIC operators (-and, -or, -between)
in q= queries are not converted to their DB-native format.

Unit tests (Query.t):
- Datetime: >=, <=, range, -or, -between, nested -and/-or, me. prefix
- Boolean: true/false inside -and, -or, nested -and within -or
- Non-datetime values pass through unchanged

Integration tests (Objects.t):
- Full API stack tests using action_logs with controlled data
- Same operator/nesting coverage as unit tests

Test plan:
1. Apply patch
2. Run:
   $ prove t/Koha/REST/Plugin/Query.t
   $ prove t/db_dependent/Koha/REST/Plugin/Objects.t
=> FAIL: Tests fail! Values inside -and are not converted
3. Sign off :-D

Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
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:35 +00:00
Andrii Nugged b719532f24
Bug 42605: Add automated tests
Store scalar preference values when saving the acquisition preferences
and clean up the invoice explicitly.

Exercise the rendered receiving behavior for a basket that inherits
AcqCreateItem, one that explicitly overrides it with "ordering", and a
basket that creates items on receiving. Keep the explicit "ordering"
case as a control for behavior that already works without the production
fix.

This changes tests only.

Automated tests:

yarn cypress run --spec \
  t/cypress/integration/Acquisitions/OrderReceivePreferences_spec.ts

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:33 +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 42ae1e0bf0
Bug 30144: (QA follow-up) Add EDIFACT_SI authorised values to installer data
Tests were failing on upgrade route because they tried to create
EDIFACT_SI authorised values that already existed from the atomicupdate
script, causing unique constraint violations.

This patch:
- Removes test code that created EDIFACT_SI values (tests should assume
  database defaults exist)
- Adds EDIFACT_SI category to auth_val_cat.sql for fresh installs
- Adds all 32 EDItEUR List 3B servicing instruction codes to
  auth_values.yml for fresh installs

Now the authorised values exist in both installation paths:
- Upgrade route: Created by atomicupdate script
- Fresh install: Created by installer SQL/YAML files

Test plan:
1. prove t/db_dependent/Koha/EDI.t
2. prove t/db_dependent/Koha/Edifact/Order.t
3. Verify both tests pass without warnings

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:25 +00:00
Martin Renvoize 711bb2dd76
Bug 30144: Add tests for EDIFACT servicing instruction handling
This commit adds comprehensive tests for servicing instruction
processing in both incoming quotes and outgoing orders:

1. Integration tests for incoming quote processing (Koha/EDI.pm)
   - Tests LVC (coded) and LVT (freetext) extraction
   - Tests multiple GIR occurrences with different servicing instructions
   - Tests all combinations: LVC only, LVT only, and LVC+LVT together

2. Test EDIFACT quote file (QUOTES_SERVICING.CEQ)
   - Contains 3 line items with 4 total orders
   - Demonstrates different servicing instruction patterns

3. Fix for multi-occurrence servicing instruction extraction
   - Modified quote_item() to extract servicing instructions
     per GIR occurrence instead of across all occurrences
   - Ensures each order gets only its own servicing instructions
   - Aligns with existing multi-item processing for funds and stock rotation

Test coverage:
- t/db_dependent/Koha/EDI.t: 29 tests for incoming quote processing
- t/db_dependent/Koha/Edifact/Order.t: 18 tests for outgoing order generation
  (previously added)

All tests pass successfully.

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:24 +00:00
Martin Renvoize b02cd5e1fe
Bug 30144: Add unit tests for servicing instructions
This patch adds comprehensive unit tests for the servicing instruction
functionality in t/db_dependent/Koha/Edifact/Order.t.

Changes:
- Updated test count from 6 to 7
- Added servicing_instruction => undef to test orders to prevent
  TestBuilder from generating random invalid JSON
- Added servicing instruction subtest with 18 tests covering:
  * Single LVC instruction
  * Single LVT instruction
  * Multiple LVC in one group (tests GIR segment overflow)
  * Mixed LVC/LVT in one group
  * Multiple groups
  * Empty servicing instruction
  * Invalid JSON handling (logged to EDI log)
- Tests correctly handle GIR segment 5-element limit and overflow
  to additional segments

Test plan:
1. Run: prove t/db_dependent/Koha/Edifact/Order.t
2. Verify all tests pass

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:23 +00:00
Jonathan Druart e8137a2c94
Bug 42322: Add Cypress tests
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:46 +00:00
Matt Blenkinsop 2ce97a58e2
Bug 12278: (follow-up) Use invoice quantity to sum total
Prevents additional orders from subscriptions from being swallowed into the invoice total calculation

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:31 +00:00
Matt Blenkinsop f7bbdd4976
Bug 12278: Add unit tests
Signed-off-by: Coleen Lilly <clilly@aacpl.net>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Sponsored-by: Anne Arundel County Public Library <https://www.aacpl.net/>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:30 +00:00
Olivia Reynolds 4dd0bfc107
Bug 39337: Add is_opac_suppressed helper to C4::Context
Previously, OPAC suppression was applied inconsistently, with only some
callers taking OpacSuppressionByIPRange into account. This patch adds a
new helper to C4::Context to determine whether OPAC suppression should
be active for this request, and switches to using it everywhere that was
previously manually checking the system preferences.

Test plan (specific URLs given for KTD, with thanks to David Cook):

1.  Apply patch.
2.  Navigate to http://localhost:8081/cgi-bin/koha/cataloguing/addbiblio.pl?biblionumber=2
3.  Set 942$n to "Yes" and save the record.
4.  Disable the system preference "OpacSuppression", and ensure
    "OpacSuppressionByIPRange" is blank.

5a. Verify you can successfully access
    http://localhost:8080/cgi-bin/koha/opac-detail.pl?biblionumber=2
5b. Verify you can successfully access
    http://localhost:8080/cgi-bin/koha/opac-MARCdetail.pl?biblionumber=2
5c. Verify you can successfully access
    http://localhost:8080/cgi-bin/koha/opac-ISBDdetail.pl?biblionumber=2
5d. Verify you can successfully access
    http://localhost:8080/cgi-bin/koha/opac-search.pl?idx=&q=The+ideas+behind&weight_search=1
5e. Verify you can successfully access
    http://localhost:8080/api/v1/public/biblios/2
5f. Verify you can successfully access
    http://localhost:8080/cgi-bin/koha/oai.pl?verb=GetRecord&metadataPrefix=oai_dc&identifier=KOHA-OAI-TEST:2
5g. Verify KOHA-OAI-TEST-2 appears on
    http://localhost:8080/cgi-bin/koha/oai.pl?verb=ListRecords&metadataPrefix=oai_dc

6.  Enable the system preference "OpacSuppression", and ensure
    "OpacSuppressionByIPRange" is blank.
7.  Repeat steps 5a-5g, verifying that:
    - the OPAC details pages return "Record blocked".
    - the OPAC search page returns "No results found".
    - the API returns "Bibliographic record not found".
    - the OAI GetRecord and ListRecords show "Record Status: deleted"
      for KOHA-OAI-TEST-2.
8.  Keep "OpacSuppression" enabled, but set "OpacSuppressionByIPRange"
    to "." (to allow all IPs to bypass suppression).
9.  Repeat steps 5a-5g, verifying that every page is successful again.
10. Run `prove t/Context.t`, and verify all tests are successful.

Sponsored-by: Open Fifth
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:25 +00:00
Jonathan Druart 8316c01bac
Bug 41706: Add a test
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>

Amended:
-    $marc->append_fields( MARC::Field->new( '100', ' ', ' ', a => 'Aristotle.' ) );
-    marc2cites($marc);
+    $marc_record->append_fields( MARC::Field->new( '100', ' ', ' ', a => 'Aristotle.' ) );
+    marc2cites($marc_record);

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-25 08:56:24 +00:00
Paul Derscheid 138d2b64ed
Bug 42207: Allow library embed on GET /patrons/{patron_id}
- Add 'library' to the allowed x-koha-embed values for the
  GET /patrons/{patron_id} endpoint
- Add unit test verifying the library embed returns library_id
  and name

Test plan:
1. Apply patch
2. yarn api:bundle
3. prove t/db_dependent/api/v1/patrons.t
4. Verify all tests pass, including the new 'library embed'
   subtest under get() which verifies that requesting
   x-koha-embed: library returns the patron's library object

Sponsored-by: Büchereizentrale Schleswig-Holstein <https://www.bz-sh.de/>
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-21 15:58:25 +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
Olivia Reynolds ff2b951c4d
Bug 41648: Validate plugin date metadata
If a plugin reports a date_authored or date_updated we can't parse,
remove the invalid property from the metadata hashref and emit a
warning.

To test this, introduce a separate test plugin directory and test file.
Having a plugin that produces warnings in the main test directory would
require accounting for this warning in every existing test that loads
plugins. Correspondingly, this patch also fixes an invalid date in an
existing test plugin.

Test plan:
1. Apply patch.
2. Run `prove -r t/db_dependent/Koha/Plugins/` and verify there are no
   test failures.

Sponsored-by: Open Fifth
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:48 +00:00
Olivia Reynolds fd24968eb2
Bug 41648: Handle parse errors in KohaDates
If dt_from_string throws an exception whilst trying to parse the input,
catch it and return an empty result.

Test plan:
1. Apply patch.
2. Prove t/db_dependent/Template/Plugin/KohaDates.t

Sponsored-by: Open Fifth
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-21 14:31:47 +00:00
Matt Blenkinsop dca7313511
Bug 43203: Correctly rollback test data
Test plan:
1) In the database, verify how many biblios exist (select count(*) from biblio;)
2) Run prove t/db_dependent/Koha/Item.t
3) Check the count again, there should now be 3 extra bib records left from the test run
4) Apply patch
5) Repeat the process, the biblio count should never grow after test runs

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:46 +00:00
Fridolin Somers 634193fc6a
Bug 43339: automatic_item_modification_by_age_configuration is not a real system preference
It should not fail the unit test t/db_dependent/check_sysprefs.t.

Test plan :
1.0) Without patch
1.1) Run : prove t/db_dependent/check_sysprefs.t
=> 'All tests successful'
1.2) Go to Cataloging > Automatic item modifications by age
1.3) Create some entries and save
1.4) Run : prove t/db_dependent/check_sysprefs.t
=>
    #   Failed test at t/db_dependent/check_sysprefs.t line 96.
    #          got: '1'
    #     expected: '0'
    # Too many sysprefs in DB: automatic_item_modification_by_age_configuration
2.0) Apply patch
2.1) Run : prove t/db_dependent/check_sysprefs.t
=> 'All tests successful'

Signed-off-by: Owen Leonard <oleonard@myacpl.org>
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-21 14:31:43 +00:00
Tomás Cohen Arazi 3522dc2bca
Bug 42567: Remove C4::Koha::GetNormalizedEAN in favor of MetadataExtractor
Adds get_normalized_ean to the flavor-specific extractors:
- MARC21: 024$a with indicator 1 = 3
- UNIMARC: 073$a

Exposes it as $biblio->normalized_ean and migrates all callers.

Assisted-by: Sonnet 4.6 (Anthropic)

Test plan:
1. Apply patch
2. Run:
   $ ktd --shell
   k$ prove t/db_dependent/Koha.t \
          t/db_dependent/Koha/Biblio.t \
          t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/MARC21.t \
          t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/UNIMARC.t
=> SUCCESS: Tests pass
3. Verify EAN numbers still display in OPAC and staff detail pages
4. Sign off :-D

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-20 15:34:10 +00:00
Tomás Cohen Arazi 3d3f625b56
Bug 42566: Remove C4::Koha::GetNormalizedUPC in favor of MetadataExtractor
GetNormalizedUPC duplicated logic already available via the
MetadataExtractor (Bug 34828) and exposed as $biblio->normalized_upc.

All callers migrated:
- Scripts with $biblio available: use $biblio->normalized_upc
- C4::Search (only MARC::Record): reuses the extractor instance
  already created for OCLC

Assisted-by: Sonnet 4.6 (Anthropic)

Test plan:
1. Apply patch
2. Run:
   $ ktd --shell
   k$ prove t/db_dependent/Koha.t \
          t/db_dependent/Koha/Biblio.t
=> SUCCESS: Tests pass
3. Verify UPC numbers still display in OPAC and staff detail pages
   (Syndetics cover images)
4. Sign off :-D

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-20 15:34:08 +00:00
Tomás Cohen Arazi 5fb7fd5f2d
Bug 35142: Remove GetNormalizedOCLCNumber, oclc_number, strip_orgcode
All callers migrated. Removes dead code:

- C4::Koha::GetNormalizedOCLCNumber
- Koha::Util::MARC::oclc_number
- Koha::Util::MARC::strip_orgcode
- Koha::Util::MARC::OCLC_REGEX constant

Test plan:
   $ prove t/Koha/Util/MARC.t t/db_dependent/Koha.t

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Assisted-by: Sonnet 4.6 (Anthropic)
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-20 15:34:07 +00:00
Tomás Cohen Arazi 263a1bd536
Bug 35142: Migrate callers to use metadata extractor
Replaces all calls to GetNormalizedOCLCNumber() and
Koha::Util::MARC::oclc_number() with the extractor pattern.

OPAC scripts pass their already ViewPolicy-filtered $record directly
to the extractor. This preserves the existing filtering behavior
without introducing new abstraction layers:

    Koha::Biblio::Metadata::Extractor->new( { metadata => $record } )->get_normalized_oclc

Intranet scripts and the Koha::Biblio convenience method use the
raw cached extractor (035 visibility is not affected by ViewPolicy
in practice, and intranet doesn't filter):

    $biblio->normalized_oclc

Test plan:
1. Verify OCLC numbers display on OPAC detail, ISBD, MARC detail
2. Verify staff catalogue detail and search results
3. prove t/db_dependent/Koha/Biblio.t

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Assisted-by: Sonnet 4.6 (Anthropic)
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-20 15:34:06 +00:00
Tomás Cohen Arazi 6b77f28dd7
Bug 35142: Move get_normalized_oclc to base MARC extractor
Moves get_normalized_oclc from the MARC21-specific extractor to the
base ::MARC class (035$a is flavor-independent) with improved matching:

- Case-insensitive OCoLC detection (matches ocolc, OCOLC, etc.)
- Generic orgcode prefix stripping (any parenthesized prefix, not
  just literal "(OCoLC)") for resilience against cataloging typos

Test plan:
   $ prove t/db_dependent/Koha/Biblio/Metadata/Extractor/MARC/MARC21.t

Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Assisted-by: Sonnet 4.6 (Anthropic)
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-20 15:34:02 +00:00
Kyle M Hall 3e87d13e67
Bug 41197: Add unit tests
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-19 14:33:52 +00:00
Pedro Amorim 22fad96c0d
Bug 35104: (RM follow-up) Fix regressions.t for Metadata's new auto-repair
Koha::Biblio::Metadata->store() now repairs recoverable MARCXML faults
before saving, so this test's invalid data no longer reaches the DB
and detail.pl never hits a decoding error.

Write the metadata directly via the DBIC row instead, bypassing
store()'s repair, so the test still exercises detail.pl's own
defensive handling of corrupt metadata.

Test plan:
prove t/db_dependent/selenium/regressions.t

Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-19 11:03:34 +00:00
Kyle M Hall d576dbadcb
Bug 41996: (QA follow-up) Test that invoicenumber is recorded on EDI invoice errors
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-18 11:21:36 +00:00
Kyle M Hall 7e445f1ce6
Bug 41996: (QA follow-up) Update EDI.t for improved invoice error messages
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-18 11:21:35 +00:00
Kyle M Hall 9e8075eaaf
Bug 42789: (QA follow-up) Add test for cancelling an order with a held item
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-18 11:21:29 +00:00
Martin Renvoize 45a60d487c
Bug 42789: Add tests for process_ordrsp() cancellation handling
Tests verify that EDI ORDRSP cancellations now use
Koha::Acquisition::Order->cancel() rather than a raw ModOrder call:

- Order status, cancellation reason and date are set correctly
- On-order items linked via aqorders_items are deleted
- Purchase suggestions linked to the biblio are reverted from
  ORDERED back to ACCEPTED
- Non-cancellation actions update suppliers_report only
- Missing ordernumbers are handled gracefully without dying

Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Sharon Dugdale <sharon.dugdale@cumberland.gov.uk>

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-18 11:21:27 +00:00
Kyle M Hall d8cf6da3a2
Bug 42700: Add unit tests
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Aleisha Amohia <aleisha@catalyst.net.nz>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
2026-08-18 11:21:21 +00:00
Matt Blenkinsop dbd680caec
Bug 42018: Add unit test
Test plan:
1) Apply just the unit test patch
2) Run t/db_dependent/Koha/Patrons.t
3) Test should fail
4) Apply remaining patch
5) Repeat step 3
6) Test should pass

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:36 +00:00
Aleisha Amohia 37ef59a9c8
Bug 35729: Normalize ISBNs as ISBN-13 if cannot fallback to ISBN-10
ISBNs beginning with 979 do not have an ISBN-10 version, and need to be normalized to an ISBN-13 format. All others, if valid, can safely be normalized to ISBN-10 format (current behaviour).

To set up

1. Download the attached sample records with 979 ISBNs
2. Log into the staff interface and go to Cataloguing
3. Go to Stage MARC records for import and upload the sample MARC file
4. Stage and import the biblio records
5. Once imported, open the detail pages for some of the records
6. In another tab, do a catalogue search and open the detail pages for ISBN-10 records, for example biblionumbers 6 and 54

To test

1. Apply the patch and restart services
2. Log into the staff interface and go to Koha Administration, Global system preferences, Enhanced Content tab
3. Cycle through each cover image service, enabled by the system preferences
4. With each cover image service is enabled, refresh the record detail pages you have open. The ISBN-10 records should CONTINUE to show their cover images. The newly imported ISBN-13 records should NOW show their cover images.
5. Confirm tests pass: t/db_dependent/Koha.t

testing with ISBN 9798885795692 should return this image from Amazon: https://images-na.ssl-images-amazon.com/images/P/9798885795692.01.LZZZZZZZ.jpg
testing with ISBN 9798876536914 should return this image from Amazon: https://images-na.ssl-images-amazon.com/images/P/9798876536914.01.LZZZZZZZ.jpg

Sponsored-by: Horowhenua Libraries Trust
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:35 +00:00
Shi Yao Wang b590f1a0a3
Bug 35797: Syspref, schema path file and tests changes
1- Corrected tests according to the comments
2- Removed unused import
3- Added syspref check of 'patronimages'
4- Tweaked swagger path schema

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:25 +00:00
Shi Yao Wang ad190dcc5d
Bug 35797: REST API Add GET route for patronimage and tests
Api changes adding GET route for patronimage

Test plan:
1- Apply the patch
2- Run `npm run api:bundle`
2- Go to administration -> sys.pref. -> set patronimages to allow
3- Log in koha using a user with "list_borrowers" or "edit_borrowers" privileges
4- Have a patron with a profile image (add an image if necessary by
searching for a patron and then clicking on the default profile image on
the top left)
5- Open a an API testing tool (such as postman), write
{intranet_url}/api/v1/patrons/{borrowernumber}/default_image
where {intranet_url} is the base intranet url of koha and {borrowernumber}
is the borrowernumber of a borrower that has an image
6- Add OAuth 2.0 credentials coming from koha (patron -> more -> manage
api keys) and generate a token
7- Send the request and notice the image of the patron is returned
8- Do step 5-7 with a borrowernumber of a patron without an image and a
borrowernumber of a patron that doesn't exist (and other edge cases
where there should be an error message displayed such as "Access
forbidden", "Authentication required", etc.)
9- Notice an appropriate error message is displayed

Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: David Nind <david@davidnind.com>

Bug 35797: Rename test file from 'image.t' to 'patron_images.t'

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:24 +00:00
Lari Taskula b094346030
Bug 40736: Add test
To test:
1. prove t/db_dependent/api/v1/idp.t

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-14 12:09:22 +00:00