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>
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>
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>
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>
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>
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>
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=5http://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>
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>
- 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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>