Koha::Calendar is, by construction, a per-library object — it croaks
without a branchcode argument and every method is branch-scoped. The
top-level namespace hides that. Move the whole tree under
Koha::Library::Calendar to match the actual semantics, the existing
/libraries/{library_id}/calendar REST routes, and the established
Koha::Library::* convention (Group, Hour, FloatLimit, OverDriveInfo).
This commit:
- renames the Koha::Calendar(::*) tree to Koha::Library::Calendar(::*)
- updates package declarations, POD and internal 'use' statements
within the moved tree
- updates the four DBIC Schema Result overrides (koha_object_class /
koha_objects_class) to the new namespace
- updates callers inside C4::* modules (Calendar, Circulation,
Reserves, Overdues, HoldsQueue), Koha::{Patron,Hold,Checkouts,
CurbsidePickup}, circ/returns.pl, the installer and cronjobs
- updates the 42310-owned tests (Calendar tests, HoldsQueue.t,
Holds/WaitingReserves.t, Holidays.t, Koha/CurbsidePickups.t,
Reserves/CancelExpiredReserves.t and the libraries.t CRUD block)
Koha::Library->calendar, the REST controllers and the 42311 tests
are updated in separate follow-up commits under their respective
bugs.
Test plan:
- prove t/db_dependent/Koha/Library/Calendar.t
- prove t/db_dependent/Calendar.t
- prove t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t
- prove t/db_dependent/Holds/WaitingReserves.t
- prove t/db_dependent/Reserves/CancelExpiredReserves.t
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
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>
Since it is not clear what checkin_library signifies when marking an
issue on a lost item as returned we might as well fallback on setting
it to the issuing library when there is no userenv.
Test plan
* Run the unit test t/db_dependent/Koha/Account/Line.t
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>
This patch updates the Koha::Patron->has_restriction_overdues method to
refer to the migrated overdue rules.
We also correct an oversight in the method prior to this patch that
meant that not all overdues were being correctly checked for a
restriction.. we were incorrectly filtering to only overdues at the
current checkin branch.
Finally, we also take account of the itemtype level addition here too.
NOTE: There weren't any unit tests for this Koha::Patron method.. we
should add some here!
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>
Linked account hold pickup check now applies to all hold
statuses (Reserved, Transferred, Processing), not just Waiting.
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>
d43945e7279 moved the issued/patron data-consistency check earlier in
AddReturn (before blocker handling), as its commit message describes,
but only copied the block instead of deleting the original. The
leftover block ran unconditionally afterwards: since $patron is
already guaranteed set whenever $issue is true by that point, its
"else" branch fired on every normal checkin of an already-issued item,
incorrectly setting $messages->{NotIssued} and clearing item.onloan.
This corrupted the not_issued message surfaced to circ/returns.pl, SIP,
and the checkin audit record on every ordinary return.
The same leftover block also buried $iso18626_request's assignment
after a die (making it dead code), so ISO18626 progress-reporting on
checkin was never triggered. Restore the assignment at the point
$issue/$patron are extracted from the availability context, where it
belongs.
Test plan:
1. Return an item that is currently checked out.
2. Confirm the returned $messages hashref no longer contains a
NotIssued key, and that item.onloan is only cleared for items that
were genuinely not checked out.
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>
Move the AllowReturnToBranch and branch transfer limit checks from both
C4::Circulation::CanBookBeReturned and
Koha::Item::Checkin::Availability::_check_return_policy into a single
authoritative method on Koha::Item: can_be_returned_at().
This eliminates the duplicate implementations and follows the Koha
convention of placing item-related logic on the Koha::Item object.
Changes:
- Add Koha::Item->can_be_returned_at() with AllowReturnToBranch policy
and transfer limit checks
- Make CanBookBeReturned a thin wrapper delegating to the new method
- Update Checkin::Availability to call $item->can_be_returned_at()
- Remove _check_return_policy and unused withdrawn warning from
the Availability class
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 refactoring changed the relative order of the Wrongbranch early
return and several status-update operations. In the original AddReturn,
the execution order was:
1. checkout/patron lookup
2. not-issued handling + RecordLocalUseOnReturn
3. withdrawn check (early return)
4. location_update_trigger
5. UpdateNotForLoanStatusOnCheckin
6. CanBookBeReturned / Wrongbranch check (early return)
7. BlockReturnOfLostItems
After the refactoring, the Wrongbranch blocker returned early before
steps 2, 4 and 5, causing three regressions:
- RecordLocalUseOnReturn was not recorded for non-issued items
scanned at the wrong branch
- location_update_trigger was skipped for Wrongbranch returns
- UpdateNotForLoanStatusOnCheckin was skipped for Wrongbranch returns
Fix by splitting blocker handling into two phases:
1. BlockedWithdrawn: earliest early return, before status updates
(matches original withdrawn check position)
2. Wrongbranch and BlockedLost: after RecordLocalUseOnReturn,
location_update_trigger, and UpdateNotForLoanStatusOnCheckin
(matches original CanBookBeReturned position)
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 data inconsistency die (checkout exists but patron does not) was
placed after the blocker handling block. This meant that if an item had
corrupt data AND triggered a blocker (e.g. withdrawn+blocked), the
blocker handler would return early with patron as undef instead of dying
on the inconsistency, silently masking database corruption.
Move the check to immediately after extracting context from the
availability result, before any blocker handling, matching the original
AddReturn behavior where the die fired during checkout lookup.
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>
There seems to be no reason to declare $patron near the start of the sub
while $issue is declared where they are both populated.
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>
This patch refactors AddReturn to use the new Koha::Item::Checkin::Availability
class for validation logic, eliminating code duplication and centralizing
check-in validation.
Changes:
- Add use statement for Koha::Item::Checkin::Availability
- Look up item first, return BadBarcode if not found
- Call $item->checkin_availability() for validation
- Use Result object methods (available(), blockers, context)
- Replace inline withdrawn/lost/branch validation with blocker handling
- Remove duplicate CanBookBeReturned() call (now in Availability class)
- Preserve all existing behavior and error messages
- Maintain backward compatibility
The refactoring extracts ~40 lines of validation logic while maintaining
identical functionality. All validation results are obtained from a single
availability check that returns a Result object.
Note: The withdrawn message is set in two places depending on context:
- When BlockReturnOfWithdrawnItems is ON: set in blocker handler before early return
- When BlockReturnOfWithdrawnItems is OFF: set by existing check later in the flow
This preserves the original behavior where withdrawn items always get the
message, but are only blocked when the syspref is enabled.
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. Verify check-in operations work correctly:
- Items not found return BadBarcode
- Withdrawn items blocked when syspref enabled
- Lost items blocked when syspref enabled
- Wrong branch returns blocked per AllowReturnToBranch
- Not issued items handled correctly
- Normal check-ins complete successfully
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>
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>
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>
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>
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>
GetAgeRestriction is no longer used by any caller. This patch removes
it from the exports list and deletes the old test file.
Test plan:
1. Run tests without this patch:
$ ktd --shell
k$ prove t/db_dependent/Circulation.t \
t/db_dependent/Reserves.t \
t/Circulation/AgeRestrictionMarkers.t
=> SUCCESS: Tests pass!
2. Apply this patch
3. Run:
k$ prove t/db_dependent/Circulation.t \
t/db_dependent/Reserves.t \
t/db_dependent/Koha/Policy/Biblio/AgeRestriction.t
=> SUCCESS: Tests pass!
4. Sign off :-D
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Amended-by: Jonathan Druart
Removed this from the commit message:
"The function body is kept for now as it is not harmful and could be
used by third-party code. It is no longer exported."
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
This patch updates CanBookBeIssued and CanItemBeReserved to use the
new policy class instead of calling GetAgeRestriction directly.
Test plan:
1. Run tests without this patch:
$ ktd --shell
k$ prove t/db_dependent/Circulation.t \
t/db_dependent/Reserves.t
=> SUCCESS: Tests pass!
2. Apply this patch
3. Repeat step 1
=> SUCCESS: Tests pass!
4. Sign off :-D
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
Implements a 4-state booking lifecycle: new → issued (on checkout) →
completed (on return), plus cancelled at any point.
Backend changes:
- AddIssue sets booking status to 'issued' (was incorrectly 'completed')
- AddReturn transitions 'issued' → 'completed' via booking_id on the issue
- filter_by_active updated to status-based: status IN ('new', 'issued');
previously it filtered by date range — active/inactive now reflect booking
lifecycle rather than the current date relative to start/end dates
- _is_final_status_transition reverted to only skip clash detection for
terminal statuses 'cancelled' and 'completed'; 'issued' is active and does
not bypass clash detection
- GET /api/v1/bookings no longer pre-filters to active bookings server-side;
callers must supply an explicit status filter if they need active-only
Display changes:
- Patron bookings tab: replaces the date-based expired/active toggle with
per-status filters (completed, cancelled) using the AdditionalFilters
framework; active bookings (new/issued) are shown by default
- Biblio bookings list: same status-based filters; removes the date-based
expired filter that was still present
- Status column is always visible on both views (was previously hidden on
the patron tab unless expired bookings were shown)
- Status badges: new=bg-success, issued=bg-info, completed/cancelled=bg-secondary
- Timeline isActive check corrected to ['new','issued']
- patron-detail-tabs.inc: rename expired_bookings_count → closed_bookings_count
to reflect status-based (not date-based) counting
- Filter button colour fixed to use $link-color so both views are consistent
Test plan:
1. Enable the EnableBookings system preference.
2. Create a biblio with at least one bookable item.
3. Place a booking for a patron via the biblio's Bookings tab.
- The booking should appear with status badge "New" (green).
4. Check out the booked item to that patron (Circulation → Check out).
- Reload the Bookings tab; the booking should now show "Issued" (blue).
5. Return the item (Circulation → Check in).
- Reload the Bookings tab; the booking should now show "Completed" (grey).
6. Place a second booking and cancel it from the Bookings tab Actions menu.
- The booking should show "Cancelled" (grey), with the reason if provided.
7. On the biblio Bookings tab:
- Completed and cancelled bookings are hidden by default.
- Clicking "Include completed" shows completed bookings.
- Clicking "Include cancelled" shows cancelled bookings.
- Both can be toggled independently.
- The Status column is always visible.
8. Navigate to the patron's detail page → Bookings tab.
- Active bookings (new/issued) are shown by default.
- Completed and cancelled can be toggled independently using the same
filter buttons.
- The Status column is always visible.
9. Confirm via the REST API that GET /api/v1/bookings (no filters) returns
bookings of all statuses, not just active ones.
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>
Always include the plural version, not the singular one (the plural
imports the singular)
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
This patch replaces all calls to C4::Stats::UpdateStats with the wrapped
function from the Koha namespace. As this is the last function in C4::Stats, the
module is also deleted.
Several tests depended on transitive includes to Koha::Statistics through
C4::Stats. I've identified uses of that module by searching, and added the
necessary use in each case. I've run `prove -r t xt` with this patch applied and
didn't hit any relevant errors.
Test plan:
1. Inspect the patch, and verify each changed call maintains the same parameters.
2. Apply patch.
3. Prove the following files:
- t/db_dependent/Accounts.t
- t/db_dependent/Circulation.t
- t/db_dependent/Koha/Account.t
- t/db_dependent/Koha/ILL/Request.t
- t/db_dependent/Koha/Item.t
- t/db_dependent/Koha/Pseudonymization.t
- t/db_dependent/Koha/Recalls.t
Sponsored-by: Open Fifth
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Laura_Escamilla <laura.escamilla@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
Previously, CIRCULATION ISSUE logs would store just the itemnumber when
there were no confirmations or forced overrides, but would store a full
JSON structure when overrides were present. This inconsistency makes
reporting difficult as queries need to handle both formats.
This patch changes AddIssue to always store logs in JSON format,
matching the pattern already used in AddRenewal. The JSON structure
now consistently includes:
- issue: issue_id
- branchcode: branchcode
- itemnumber: itemnumber
- confirmations: array of confirmation codes (empty array if none)
- forced: array of forced override codes (empty array if none)
Benefits:
- Consistent data format simplifies reporting and analysis
- Matches existing RENEWAL logging pattern
- Display code (tools/viewlog.pl) already handles both formats,
so backward compatibility is maintained
Test plan:
1. prove t/db_dependent/Circulation.t
2. Perform a normal checkout - verify action log contains JSON
3. Perform a checkout with overrides - verify confirmations/forced
are populated in the JSON
4. Check Tools > Log viewer - both types should display correctly
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
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>
This will now find the corresponding ISO18626 request and update it accordingly when a check-out happens.
Use-case this is addressing:
1. Place an item-level hold for Henry
2. Check-in that item e.g. 39999000003130 (make it waiting)
3. Create a new ISO18626 request and 'Search to hold', place a bib-level hold on the same bib as above (for patron Walker)
4. Check-out the item from 2. 39999000003130 to Walker
5. Confirm an ISO18626 message input is shown and that the respective ISO18626 request is updated to 'Loaned' once the check-out happens (i.e. override Henry's hold).
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Lisette Scheer <lisette@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This commit improves upon the original fix by making the intent more
explicit when handling empty string date parameters in AddRenewal and
AddIssue functions.
WHY THIS IS BETTER:
The original fix (changing `defined $datedue` to just `$datedue`)
works correctly but relies on Perl's implicit truthy/falsy semantics:
if ( $datedue && ref $datedue ne 'DateTime' )
This is subtle because:
- Empty string "" is falsy, so parsing is skipped ✓
- But it's not immediately obvious that empty strings are being
handled specially
- The code doesn't explicitly show its intent
THIS APPROACH:
if ( defined $datedue && $datedue ne '' && ref $datedue ne 'DateTime' )
Benefits:
1. EXPLICIT: Clearly states "only parse if defined AND not empty
AND not already a DateTime"
2. SELF-DOCUMENTING: Intent is obvious to future developers
3. NO RELIANCE on truthy/falsy semantics
4. CONSISTENT: Same pattern applied across all date parameter handling
COMPREHENSIVE CHANGES:
1. AddRenewal (C4/Circulation.pm:3449)
- Made datedue empty string check explicit
2. AddIssue (C4/Circulation.pm:1611)
- Made datedue empty string check explicit
- Also updated issuedate handling (line 1616) to explicitly handle
empty strings
3. Test Coverage (t/db_dependent/Circulation/issue.t)
- Added test for AddIssue with empty string datedue
- Added test for AddIssue with empty string issuedate
- Ensures both functions properly calculate dates from circulation
rules instead of using "now"
The existing test for AddRenewal already covered empty string datedue
(added in the original Bug 37966 commit). These new tests ensure the
same correct behavior for AddIssue.
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
When renewing a book on hold with the RenewalOnHoldOverride sys pref set
to "Allow", if the due date is not specified then it becomes "now". By
checking the input is set rather than just defined the due date is set as
expected based on circulation rules.
Also change the description of the RenewalOnHoldOverride sys pref as the
due date would no longer be required to be entered with this change.
Test plan:
1. make sure RenewalOnHoldOverride is set to 'Allow'
2. check out a book, then place a title-level hold on it
3. renew the book, see the hold override dialog
4. leave the due date empty and hit the override button
5. observe the new due date is "now"
6. apply patch and restart plack
7. renew the book again, overriding the hold, and see the expected due date
as per circulation rules.
Signed-off-by: Marion Durand <marion.durand@biblibre.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Roman Dolny <roman.dolny@jezuici.pl>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Amended-by: Jonathan Druart
Tidy C4/Search.pm
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This follow-up patch addresses feedback from the QA process:
1. System preference naming consistency
Renamed the following preferences to remove "OPAC" prefix and align
with the FineNoRenewals naming convention:
- OPACFineNoRenewalsIncludeCredits → FineNoRenewalsIncludeCredits
- OPACFineNoRenewalsBlockAutoRenew → FineNoRenewalsBlockAutoRenew
2. Self-checkout backward compatibility
Added new system preference FineNoRenewalsBlockSelfCheckRenew to
control whether fine limits block renewals via web-based self-checkout.
Previously, OPACFineNoRenewals did not block self-checkout renewals.
With the rename to FineNoRenewals, this behavior changed. The new
preference defaults to "0" (don't block) to maintain backward
compatibility, allowing sites to opt-in to blocking self-checkout
renewals when patrons exceed the fine threshold.
Test plan:
1. Run prove t/db_dependent/Circulation.t - all tests should pass
2. Run prove t/db_dependent/api/v1/checkouts.t - all tests should pass
3. Verify system preferences are correctly renamed in the admin interface
4. Test self-checkout renewals with FineNoRenewalsBlockSelfCheckRenew
set to 0 (default) - renewals should work even when fines exceed limit
5. Test self-checkout renewals with FineNoRenewalsBlockSelfCheckRenew
set to 1 - renewals should be blocked when fines exceed limit
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
This patch fixes a regression introduced in the previous commits where
we changed FineNoRenewals checking to use non_issues_charges instead
of balance. While this change was correct for focusing on blocking
charges, we inadvertently removed the handling of the
OPACFineNoRenewalsIncludeCredits preference.
The OPACFineNoRenewalsIncludeCredits preference controls whether
unapplied account credits should be included when calculating if a
patron exceeds the FineNoRenewals threshold. When this preference is
enabled, the patron's net balance (debits minus credits) should be
used instead of just their outstanding debits.
This patch restores the preference handling for both:
1. Manual renewals in CanBookBeRenewed()
2. Auto renewals in _CanBookBeAutoRenewed()
When OPACFineNoRenewalsIncludeCredits = 1:
Use balance (all charges net of credits)
When OPACFineNoRenewalsIncludeCredits = 0:
Use non_issues_charges (only blocking charges, no credits)
This ensures that patrons with sufficient credits can renew their
items when the preference is enabled, while still maintaining the
focus on non-issuing charges introduced in the previous commits.
Test plan:
1. Run prove t/db_dependent/Circulation.t
2. All tests should pass, particularly the
"auto_too_much_owing | OPACFineNoRenewalsBlockAutoRenew &
OPACFineNoRenewalsIncludeCredits" subtest
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
This commit addresses two issues:
1. Fixes FineNoRenewals logic to properly use non_issues_charges
Both CanBookBeRenewed() and _CanBookBeAutoRenewed() were incorrectly
using the patron's total balance when checking against FineNoRenewals.
They now use non_issues_charges, which returns only charges that
should restrict checkouts (e.g., overdues, lost items) as defined by
debit types with restricts_checkouts=1. This ensures charges like
rental fees don't inappropriately block renewals.
2. Improves renewal template for AllowFineOverrideRenewing
- Adds special handling for auto_too_much_owing error to check
AllowFineOverrideRenewing preference instead of
AllowRenewalLimitOverride
- Adds missing id="barcode" attribute to input field for Cypress tests
- Adds .dialog CSS class to error/success divs for consistent styling
- Fixes HTML structure with proper <ul><li> wrapping
- Adds btn btn-default classes to override button
3. Fixes Cypress test issues
- Corrects data structure access: items[0] instead of item
- Uses external_id instead of barcode (API field name)
- Improves form submission selector specificity
- Uses REPLACE INTO for system preference setup
Test plan:
1. Run t/cypress/integration/Circulation/FineNoRenewals_spec.ts
2. Verify 4 out of 5 tests pass (one remaining template comparison issue)
3. Manually test that patrons with non-issue charges (rental fees) can
renew when those charges alone don't exceed FineNoRenewals
4. Verify that patrons with issue-blocking charges (overdues) are
properly blocked from renewal when exceeding FineNoRenewals
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Standardizes error code spelling across the codebase:
- Changes 'too_much_oweing' to 'too_much_owing'
- Changes 'auto_too_much_oweing' to 'auto_too_much_owing'
The word "owing" is the correct spelling in English.
Files updated:
- C4/Circulation.pm
- C4/SIP/Sip/MsgType.pm
- circ/renew.pl
- koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt
- koha-tmpl/intranet-tmpl/prog/js/checkouts.js
- koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-reserve.tt
- koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt
- misc/cronjobs/automatic_renewals.pl
- opac/opac-reserve.pl
- opac/opac-user.pl
- t/db_dependent/Circulation.t
All tests should pass successfully.
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
This commit addresses several issues found in QA review:
1. Fixed logic bug in C4::Circulation::CanBookBeRenewed
- Removed incorrect check of AllowFineOverrideRenewing preference
- The function now always returns 'too_much_oweing' error when
patron balance exceeds FineNoRenewals limit
- AllowFineOverrideRenewing should only control UI override
capability, not the core renewal check
2. Added permission check in circ/renew.pl
- Override is now only allowed when both override_debt parameter
is set AND AllowFineOverrideRenewing preference is enabled
- Prevents security issue where staff could bypass the preference
by crafting POST requests
3. Fixed template to conditionally display override button
- Override button in renew.tt now only shows when
AllowFineOverrideRenewing is enabled
- Prevents confusion when override is not permitted
4. Added test coverage
- Tests verify CanBookBeRenewed behavior with AllowFineOverrideRenewing
both enabled and disabled
- Confirms error is always returned regardless of preference setting
5. Fixed minor issues
- Fixed typo: "he patron" -> "the patron" in checkouts.js
- Fixed typo: OPACFineNoRenewalsIncludeCredit ->
OPACFineNoRenewalsIncludeCredits in test
All tests should pass successfully.
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
This patch adds new syspref AllowFineOverrideRenewing. It allows
staff to renew items for patrons whose fines are over limit set
in syspref FineNoRenewals. Otherwise renewing is prevented. If
renewing items is allowed staff is still required to confirm
if they really want to renew items for the patron.
To test:
1. Apply this patch, update database and restart all services.
2. Find patron with fines over limit set in FineNoRenewals and
renewable items.
=> Note that renewing is prevented with message "Cannot renew,
the patron has a debt of..."
3. Set syspref AllowFineOverrideRenewing as "Allow".
=> Note that items can now be renewed and renewing them displays
confirmation pop-up.
Sponsored-by: Koha-Suomi Oy
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-of-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
This moves the basic calculation for too_much_oweing out of the
controller and into the class method.
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
OPACFineNoRenewals no longer applies just to OPAC.
To avoid confusion rename it as FineNoRenewals and
also rename all occurences in code.
To test, confirm everything works as described in
previous test plans.
Also prove t/db_dependent/Circulation.t
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Shi Yao Wang <shi-yao.wang@inlibro.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
This patch ensures that the accountlines.branchcode field correctly records
which branch's circulation rules were applied when creating OVERDUE, LOST,
and PROCESSING fee debits. Previously, this field was often NULL or set
to the logged-in user's branch, making it difficult to track which branch's
policies governed the fee calculation.
Changes made:
1. New helper method: Koha::Checkout->branch_for_fee_context()
- Centralizes branch resolution logic based on system preferences
- For LOST/PROCESSING: honors LostChargesControl preference
- For OVERDUE: honors CircControl preference
- Respects HomeOrHoldingBranch when choosing item's branch
- Supports both Koha objects and plain hashrefs
- Returns branchcode or undef if context unavailable
2. C4::Accounts::chargelostitem()
- Now accepts optional $opts hashref parameter
- Accepts interface, library_id, and issue_id in options
- Determines appropriate branch using branch_for_fee_context
- Passes resolved branch to add_debit as library_id
- Issue_id lookup handles bundled items correctly
3. C4::Circulation::LostItem()
- Calls branch_for_fee_context before chargelostitem
- Passes interface context ('cron' for cronjob, otherwise current)
- Passes resolved branch and issue_id to chargelostitem
4. C4::Overdues::UpdateFine()
- Calls branch_for_fee_context to determine OVERDUE branch
- Passes result as library_id to add_debit
- Resolves long-standing FIXME about branch selection
5. misc/cronjobs/longoverdue.pl
- Determines branch context before marking items lost
- Passes library_id to LostItem when charging fees
The branch resolution logic respects these system preferences:
- CircControl: PatronLibrary | PickupLibrary | ItemHomeLibrary
- LostChargesControl: PatronLibrary | PickupLibrary | ItemHomeLibrary
- HomeOrHoldingBranch: homebranch | holdingbranch
Test plan:
1. Create three test libraries (e.g., FPL, CPL, PVL)
2. Create a test patron with home library PVL
3. Create an item with:
- homebranch = FPL
- holdingbranch = CPL
4. Set system preferences:
- FinesMode: Calculate and charge
- Create circulation rule that charges overdue fines
5. Test OVERDUE fees with CircControl:
a. Set CircControl = PatronLibrary, HomeOrHoldingBranch = homebranch
b. Check out item to patron at CPL, backdate to be overdue
c. Run: perl /usr/share/koha/bin/cronjobs/fines.pl
d. Check accountlines: SELECT accountlines_id, branchcode, debit_type_code
FROM accountlines ORDER BY accountlines_id DESC LIMIT 5;
e. Verify branchcode = PVL (patron's home library)
f. Delete the fine, repeat with CircControl = PickupLibrary
g. Verify branchcode = CPL (checkout library)
h. Delete the fine, repeat with CircControl = ItemHomeLibrary
i. Verify branchcode = FPL (item's home library)
j. Change HomeOrHoldingBranch = holdingbranch, repeat
k. Verify branchcode = CPL (item's holding library)
6. Test LOST fees with LostChargesControl:
a. Set WhenLostChargeReplacementFee = Charge
b. Set item replacement price > 0
c. Ensure item is checked out to patron
d. Set LostChargesControl = PatronLibrary
e. Mark item as lost in staff interface
f. Check accountlines for LOST debit
g. Verify branchcode = PVL (patron's home library)
h. Return item, re-checkout, repeat with LostChargesControl = PickupLibrary
i. Verify branchcode = CPL (checkout library)
j. Repeat with LostChargesControl = ItemHomeLibrary + homebranch
k. Verify branchcode = FPL (item's home)
l. Repeat with LostChargesControl = ItemHomeLibrary + holdingbranch
m. Verify branchcode = CPL (item's holding)
7. Test longoverdue cronjob:
a. Re-checkout item with due date triggering longoverdue
b. Run: perl /usr/share/koha/bin/cronjobs/longoverdue.pl --lost 30=1 --charge 1 --confirm --verbose
c. Verify LOST debit created with correct branchcode per LostChargesControl
8. Test edge cases:
- WhenLostChargeReplacementFee = Don't charge → no LOST debit
- Replacement price = 0 → no LOST debit
- FinesMode = Don't calculate → no OVERDUE debits
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This patch additionally fetches the reply to address for advance notices
To test:
1 - Have some issues that will be due soon for a patron(s)
Checkout with the due date set to tomorrow
2 - Verify the patron(s) have an email defined, verify the issuing branch has a reply to set
3 - Verify the patron(s) have messaging preference set to receive Advance notices by email 1 day in advance
4 - perl misc/cronjobs/advance_notices.pl -v -c
5 - Check the message queue
SELECT * FROM message_queue WHERE borrowernumber={##}
6 - Note no rpely to is set
7 - Apply patch
8 - perl misc/cronjobs/advance_notices.pl -v -c
9 - Check the message queue
10 - Confirm newer message has the reply to populated
11 - Ensure the issued item has a different homebranch with a reply to address se
12 - perl misc/cronjobs/advance_notices.pl -v -c --frombranch item-homebranch
13 - Confirm message has correct reply to
14 - Set patron to want digest in messaging preferences
15 - Generate notices
16 - Confirm digets has the right reply to
Signed-off-by: Roman Dolny <roman.dolny@jezuici.pl>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Tidied inline
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Note: tests have to be performed on addReturn and have therefore been
added in a separate test
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This patch adds the optional 'tranferbranch' parameter to the
CanBookBeReturned routine. This allows for passing the correct
'ReturnToX' transfer to be tested at return time for transfer limit
restrictions.
Signed-off-by: Julian Maurice <julian.maurice@biblibre.com>
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Mathieu Saby <mathsabypro@gmail.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>