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>
local_holdgroup_match was being hardcoded to 1 in the two LocalHoldsPriority
allocation paths (GiveLibrary and GiveLibraryGroup), regardless of whether the
chosen item actually satisfied the LocalHoldsExclusivity conditions. This
caused staff to be directed to pull an item that would not trigger the hold at
checkin when the two features used different patron/item controls.
The fix removes the premature local_holdgroup_match => 1 from both LHP paths and
lets _flag_local_holdgroup_matches evaluate all allocated items using the correct
LocalHoldsExclusivity* sysprefs.
Also fixes a pre-existing missing bind-variable placeholder in the
INSERT INTO tmp_holdsqueue statement (17 columns, only 16 ?).
Test updates:
- Existing local_holdgroup_match test gains the matching LocalHoldsExclusivity
sysprefs so the flag is set via the correct code path.
- New subtest reproduces the reported bug: LHP (HomeLibrary/homebranch) targets
a non-local item while exclusivity (PickupLibrary/holdingbranch) should not
flag it — confirms local_holdgroup_match is 0 after the fix.
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Sponsored-by: Main Library Alliance <https://www.mainlib.org/>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
LocalHoldsExclusivity and LocalHoldsPriority are adjacent but distinct
features: priority alters *which patron's hold* gets filled first, while
exclusivity restricts *which items* may fill a hold during a time window.
Each should be usable independently of the other.
Changes:
- Rename LocalHoldsPriorityExclusivityPeriod to LocalHoldsExclusivityPeriod
- Add LocalHoldsExclusivityPatronControl (PickupLibrary/HomeLibrary)
- Add LocalHoldsExclusivityItemControl (homebranch/holdingbranch)
- HoldsQueue: add _flag_local_holdgroup_matches() that flags
local_holdgroup_match on allocated items using hold-group matching
and the new exclusivity control prefs, regardless of LocalHoldsPriority
- Reserves: CheckReserves exclusivity check now computes its own
"is this item local" using the new prefs and hold-group siblings,
independent of the LocalHoldsPriority matching variables
- Atomicupdate handles both fresh install and rename-from-old-pref paths
- Pref UI note clarifies independence from LocalHoldsPriority
Test plan:
1. Apply patch, run updatedatabase.pl
2. Verify three new sysprefs exist in Administration > System preferences
> Circulation: LocalHoldsExclusivityPeriod, LocalHoldsExclusivityPatronControl,
LocalHoldsExclusivityItemControl
3. Set LocalHoldsPriority to "Don't give" (None)
4. Create a library hold group with at least two libraries (e.g. Lib-A, Lib-B)
5. Create a third library (Lib-C) NOT in the hold group
6. Create an item at Lib-B
7. Place a hold for a patron at Lib-A (pickup at Lib-A)
8. Set LocalHoldsExclusivityPeriod to 7, PatronControl to HomeLibrary,
ItemControl to homebranch
9. Run the holds queue builder (misc/cronjobs/holds/build_holds_queue.pl)
10. Verify hold_fill_targets.local_holdgroup_match = 1 for that hold
(item at Lib-B is in the same hold group as patron at Lib-A)
11. Check in the item at Lib-C — it should NOT fill the hold (exclusivity
blocks the non-local item within the 7-day window)
12. Check in the item at Lib-B — it SHOULD fill the hold (local match)
13. Reset: delete the hold, create a new one with a patron at Lib-C
(pickup at Lib-C). Run the queue again.
14. Verify hold_fill_targets.local_holdgroup_match = 0 for this hold
15. The item at Lib-B should now fill this hold at Lib-C checkin
(non-local patron, no exclusivity protection)
16. Set LocalHoldsExclusivityPeriod to 0 — verify non-local items can
fill holds normally regardless of hold_fill_targets flag
17. prove t/db_dependent/Holds/LocalHoldsPriority.t — passes
18. prove t/db_dependent/HoldsQueue.t — passes
19. prove t/db_dependent/Reserves.t — passes
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
When LocalHoldsPriority is enabled, the holds queue picks a local-group
item for eligible holds. Until now there was nothing to reserve that
priority at checkin time: if a non-local item was returned first, it
would happily fill the hold and the local-priority decision was lost.
This patch adds a time-bounded exclusivity window so that, for a
configurable number of days after a hold is placed, a hold whose queue
target is a local-group item will not be filled by a non-local item.
Changes:
- C4/HoldsQueue.pm: in MapItemsToHoldRequests, flag %item_map entries
that matched on local library (GiveLibrary/GiveLibraryAndGroup) or
local hold group (GiveLibraryGroup/GiveLibraryAndGroup) with
local_holdgroup_match => 1, and propagate that into both the
tmp_holdsqueue and hold_fill_targets INSERTs.
- C4/Reserves.pm: in the CheckReserves loop, when
LocalHoldsPriorityExclusivityPeriod is set, the hold is still within
that window, and the item being evaluated is not itself a local
match, skip the reserve if its hold_fill_targets row has
local_holdgroup_match = 1. Missing hold_fill_targets row means "no
information" -- fall through so holds are never trapped between
queue runs.
- circulation.pref: expose the new LocalHoldsPriorityExclusivityPeriod
preference next to the existing LocalHoldsPriority* entries.
The feature is a no-op unless both LocalHoldsPriority is set to
something other than "Don't give" AND
LocalHoldsPriorityExclusivityPeriod is > 0.
Test plan:
1) Apply the patches and run the atomicupdate.
2) Set up a library group flagged as a local hold group containing
two libraries (call them A and B). Add a third library C that is
NOT in the group.
3) Add one item to each library (itemA, itemB, itemC) on the same
biblio.
4) Administration -> System preferences -> Circulation:
- Set LocalHoldsPriority to "Give library group".
- Set LocalHoldsPriorityPatronControl to "home library".
- Set LocalHoldsPriorityItemControl to "home library".
- Set LocalHoldsPriorityExclusivityPeriod to 7.
5) As a patron whose home library is A, place a title-level hold with
pickup at A.
6) Run the holds queue (misc/cronjobs/holds/build_holds_queue.pl).
-> The queue should target itemA (or itemB) for this hold.
-> Confirm in the database:
SELECT reserve_id, itemnumber, local_holdgroup_match
FROM hold_fill_targets;
The targeted row must have local_holdgroup_match = 1.
-> Holds to pull / holds queue report should also show the flag
(tmp_holdsqueue.local_holdgroup_match = 1).
7) At library C, check in itemC (the non-local item).
-> The hold must NOT be captured -- itemC simply goes back on the
shelf.
8) At library A, check in itemA (the local item).
-> The hold IS captured for the patron.
9) Cancel and re-place the hold, run the queue again. Manually age
the hold past the window:
UPDATE reserves
SET reservedate = DATE_SUB(CURRENT_DATE, INTERVAL 10 DAY)
WHERE reserve_id = <id>;
Now check in itemC again.
-> The hold IS captured (exclusivity window has expired).
10) Re-place the hold but do NOT run the queue. With no
hold_fill_targets row for the reserve, check in itemC.
-> The hold IS captured (we never trap holds between queue runs).
11) Flip LocalHoldsPriorityExclusivityPeriod back to 0 and repeat
step 7.
-> The hold IS captured; the feature is fully disabled.
12) Run:
prove t/db_dependent/Holds/LocalHoldsPriority.t \
t/db_dependent/HoldsQueue.t \
t/db_dependent/Reserves.t \
t/db_dependent/Koha/Hold.t
-> All tests pass.
Sponsored-by: Main Library Alliance <https://www.mainlib.org/>
Signed-off-by: Trevor Diamond <trevor.diamond@mainlib.org>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
The previous two commits on this bug fixed two ordering assumptions in
the RETRY loop of _allocateWithTransportCostMatrix(): resetting $inf at
the start of each attempt, and splicing unallocated task indices out of
@requests in descending order (removing a lower index first would shift
the position of any higher index still waiting to be removed).
This is a third instance of the same underlying problem, a few lines
earlier in the loop that compacts the working cost matrix $m before
that splice runs. @unallocated is built by iterating over agents (item
rows), pushing the column index Munkres assigned to each row that
turned out infeasible - and Munkres' row-to-column assignment is a
permutation, not a monotonic function of the row index, so
@unallocated is no more reliably sorted here than it was for the
splice.
That compaction loop scans matrix columns in ascending order and
advances a single pointer into @unallocated, expecting to meet each
entry in that same ascending order. When @unallocated arrives out of
order, the pointer never catches up: columns that should have been
dropped are left in place, and the columns after them are never
shifted left to fill the gap. From that point on, $m no longer lines
up with @requests, which *is* correctly reduced by the splice - so on
the next retry pass a hold's transport cost gets evaluated using a
different hold's matrix row. Depending on the exact misalignment, this
can silently drop a fillable hold from the queue while a genuinely
available item sits unused, or fill a hold via the wrong-cost item.
It didn't show up in the "many holds" regression test added earlier on
this bug, because that test's transport cost matrix is uniform (every
disabled pair costs the same); this defect only surfaces once the
columns competing for a scarce item have distinct costs.
Sort @unallocated once, ascending, and use that copy for the
compaction pass; reverse it for the splice, which needs descending
order.
Test plan:
1. Run the new t/db_dependent/HoldsQueue/RetryAllocationOrdering.t -
it calls _allocateWithTransportCostMatrix() directly with a small
hand-built scarce transport cost matrix and a pinned srand() (the
specific item-to-branch permutation needed to trigger the bug
depends on the shuffle() inside the routine). Reverting just this
patch makes 3 of its 6 subtests fail: the L2 pickup hold is dropped
even though an available item could have filled it.
2. Run t/db_dependent/HoldsQueue/TransportCostOptimizations.t to
confirm no regression in the existing retry-loop coverage.
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
* The representation of the value "infinity" must be reset to -1 at the
start of each allocation attempt.
* Unallocated items must be spliced out from the candidate arrays in
reverse index order.
Test plan:
1. Run the unit tests in
t/db_dependent/HoldsQueue/TransportCostOptimizations.t
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
If HoldsQueueParallelLoopsCount is set to a value greater than 1, build_holds_queue.pl will fail with the message:
Can't locate object method "new" via package "Parallel::ForkManager" (perhaps you forgot to load "Parallel::ForkManager"?) at /kohadevbox/koha/C4/HoldsQueue.pm line 205.
Test Plan:
1) Run misc/cronjobs/holds/build_holds_queue.pl
2) Note the error message
3) Run misc/cronjobs/holds/build_holds_queue.pl
4) Note the error message is gone!
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
So it is done before the other use statements.
Also uniformize the pattern, must now be:
```
use Modern::Perl;
use base 'Exporter';
BEGIN {
our @EXPORT_OK = qw(subroutine list);
}
```
Rebased-by: Victor Grousset/tuxayo <victor@tuxayo.net>
Bug38936 exported redirect_if_opac_suppressed
Signed-off-by: Victor Grousset/tuxayo <victor@tuxayo.net>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This fixes the issue reported by Andrew on comment 23.
Following the scenario he describes, the hold should now still appear, but attached to the correct patron (Patron B).
This was an oversight as I wasn't aware of GetPendingHoldRequestsForBib and had only added the skip logic to GetBibsWithPendingHoldRequests.
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
When a hold that belongs to a hold group becomes 'In transit' or 'Waiting',
it now becomes that hold group's target hold.
Subsequent check-ins that would satisfy other holds in the same hold
group are skipped, as they are part of a group that already has a
target.
The behavior change introduced here that differs from the groundwork
from bug 15516 are:
1) Before, only 'Waiting' holds would consider an action based on hold
groups i.e. cancel the other holds in the group. Now 'In transit'
also does this.
2) This hold groups related action used to be to cancel other holds in
the group. This is no longer the case. Now, the respective hold is
set as the hold group's target. This causes the holds in the same group that
are not the target to be skipped when a check-in that would otherwise
satisfy one of those holds happens. This behavior change allows the following
scenario which wasn't possible before:
A hold is marked 'Waiting'. It becomes its group target. For any reason,
that hold is then cancelled. Any subsequent check-in of an item of a
hold in this group may now becomes that group's new target.
Similarly, the same use case above is also true for 'In transit' holds.
----
The 'skip non-target holds' behavior has been added to check-in logic
(Reserves::_Findgroupreserve), 'holds to pull' logic
(pendingreserves.pl) and holds queue (HoldsQueue.pm).
Signed-off-by: Anneli Österman <anneli.osterman@koha-suomi.fi>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
To Test:
Before applying:
1. Turn on the UseTransportCostMatrix system preference
2. Create holds on a record with multiple items. (I used Lanark in KTD)
3. Set the item location to all be the same (I used MID)
4. Set the holds to pickup at Centerville, Fairfield, and Pleasant Valley
5. Set the transport cost matrix to
Centerville\fairfield 1
Centerville\Midway 1
Fairfield\Centerville 1
Fairfield\Midway 1
Midway\Centerville 1
Midway\Fairfield 1
Midway\Pleasant Valley 4
6. Build the holds queue (either turn on realtime hold queue and then edit the bib to update or run the cron on the command line)
7. Run a report: select * from hold_fill_targets where biblionumber=9 order by borrowernumber;
8. Rebuild the hold queue
9. Run the report again, the results should be the same.
10. Apply the patch
11. Run the hold queue again
12. Observe the results should now be different.
13. Try a few more times and ensure the numbers are changing, create some more items at midway and try again to see more variety in numbers.
Signed-off-by: David Flater <flaterdavid@gmail.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
This fixes the holds queue and associated tests.
I also updated the sql file to fix an issue and the LocalHoldsPriority tests to fix a typo.
I'm working on final unit tests for the holds queue for all the options for QA but I wanted to get the queue changes ready for sign-off.
UPDATED TEST PLAN
This patch adds new options to the LocalHoldsPriority system preference to allow for the following options:
'None' the equivalent to 'Don't' pre-patch
'GiveLibrary' the equivalent to 'Do' pre-patch
'GiveLibraryAndGroup' Allows for checking the library first, then hold groups
'GiveGroup' Allows to prioritize within a group without prioritizing any library first.
The included patches will update the preference in existing installations to maintain current behavior.
To Test:
BEFORE APPLYING THE PATCH
/Tip/
I kept the following tabs open:
-The holds screen (for suspending, checking order, etc)
-Check in screen (can ignore holds to keep them all in place)
-Holds to Pull with "All" for Libraries
-System Preferences
/Setup Groups and confirm current behavior/
1. Set the following system preferences:
-" LocalHoldsPriority " system preference to "Give"
-"LocalHoldsPriorityPatronControl" to "home library"
-"LocalHoldsPriorityItemControl" to "home library"
-"RealTimeHoldsQueue" to "Enable"
2. Create 2 Library Groups
- Set them to be hold groups
- I called mine group 1 & group 2
3. Add 2 libraries each to each group.
- Group 1
- Centerville
- Fairfield
- Group 2
- Fairview
- Franklin
4. Find a patron for each branch in the groups
- Centerville - Changed 23529000035676 (Henry)
- Fairfield - Changed 23529000050113 (Jordan)
- Fairview - Changed 23529001000463 (Edna)
- Franklin - 23529000121682 (Nicole)
5. Find a record with at least 2 items
6. If needed change the home and holding libraries so you have at least one item for each hold group
- Centerville - 39999000000252
- Fairview - Changed 39999000000238
7. Place 2 record level holds for the record.
- One for 23529000035676 (Henry) for pickup at Centerville (Priority 1)
- One for 23529001000463 (Edna) for pickup at Fairview (Priority 2)
8. Check in 39999000000238. The hold popup should be for the second hold (Henry), not the first (Edna.) Ignore the hold
9. Edit the record then save to trigger real time queue update
10. On the Holds Queue (submit after each set of changes):
- Centerville should be for Henry
- Fairview should be for Edna
/apply patch and confirm behavior still works/
10. Apply patch
11. Rebuild the database then restart_all (in sandboxes it's an action, in ktd " dbic && updatedatabase && restart_all ")
12. Confirm that " LocalHoldsPriority " is set to "Give Library"
13. Repeat steps 8-10, behavior should be the same.
/ check library then library group setting/
14. Change " LocalHoldsPriority " to "Give library then library group"
15. Set the following record level holds for the record in the following order:
*You can add Jordan and Nicole's, then rearrange the order.
- Pickup at Fairfield - 23529000050113 (Jordan)
- Pickup at Franklin - 23529000121682 (Nicole)
- Pickup at Centerville - 23529000035676 (Henry)
- Pickup at Fairview - 23529001000463 (Edna)
17. Check in 39999000000252 - should try and fill to Centerville - 23529000035676 (Henry)
17. Check in 39999000000238 - should try and fill to Fairview - 23529001000463 (Edna)
18. On the Hold Queue:
- Centerville should be for Henry
- Fairview should be for Edna
19. Suspend the hold for 23529001000463 (Edna)
20. Check in 39999000000238 should try and fill to 23529000121682 (Nicole) (ignore the hold)
21. On the Holds Queue:
- Centerville should be for Henry
- Fairview should be for Nicole
/ check library group setting /
22. Reset the holds to match step 15.
23. Change " LocalHoldsPriority " to "Give group"
24. Check in 39999000000252 - should try and fill to Fairfield (Jordan) (ignore the hold)
25. Check in 39999000000238 - should try and fill to Franklin (Nicole) (ignore the hold)
26. On the Holds Queue:
- Centerville should be for Jordan
- Fairview should be for Nicole
/check no priority /
27. Change " LocalHoldsPriority " to "Don't give"
28. Reset the holds to match step 15.
29. Check in 39999000000238 - Should fill to Fairfield (Jordan) (ignore the hold)
30. Check in 39999000000252 - Should fill to Fairfield hold (Jordan) (ignore the hold)
31. On the Holds Queue:
- Centerville should be for Jordan
- Fairview should be for Nicole
/Also check/
Item level holds behave as expected
Different combinations of LocalHoldsPriorityItemControl and LocalHoldsPriorityPatronControl
Sponsored by: Cape Libraries Automated Materials Sharing
Sponsored by: Northeast Kansas Library System (NEKLS)
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
This patch adds new options to the LocalHoldsPriority system preference to allow for the following options:
'None' the equivalent to 'Don't' pre-patch
'GiveLibrary' the equivalent to 'Do' pre-patch
'GiveLibraryAndGroup' Allows for checking the library first, then hold groups
'GiveGroup' Allows to prioritize within a group without prioritizing any library first.
The included patches will update the preference in existing installations to maintain current behavior.
To Test:
BEFORE APPLYING THE PATCH
/Setup Groups and confirm current behavior/
1. Set the " LocalHoldsPriority " system preference to "Give", "LocalHoldsPriorityPatronControl" to "home library" and "LocalHoldsPriorityItemControl" to "home library"
2. Create 2 Library hold Groups
- I called mine group 1 & group 2
3. Add 2 libraries each to each group.
- Group 1
- Centerville
- Fairfield
- Group 2
- Fairview
- Franklin
4. Find a patron for each branch in the groups
- Centerville - 23529000035676 (Henry)
- Fairfield - Changed 23529000050113
- Fairview - Changed 23529001000463 (Edna)
- Franklin - 23529000121682
5. Find a record with at least 2 items
6. If needed change the home and holding libraries so you have at least one item for each hold group
- Centerville - 39999000000252
- Fairview - Changed 39999000000238
7. Place 2 record level holds for the record.
- One for 23529000035676 for pickup at Centerville (Priority 1)
- One for 23529001000463 for pickup at fairview (Priority 2)
8. Check in 39999000000238. The hold popup should be for the second hold, not the first.
/apply patch and confirm behavior still works/
9. Apply patch
10. Rebuild the database then restart_all (in sandboxes it's an action, in ktd " dbic && updatedatabase && restart_all ")
11. Confirm that " LocalHoldsPriority " is set to "Give Library"
12. Repeat steps 7-8, behavior should be the same.
/ check library then library group setting/
13. Change " LocalHoldsPriority " to "Give library then library group"
14. Set the following record level holds for the record:
- Pickup at Fairfield - 23529000050113
- Pickup at Franklin - 23529000121682
- Pickup at Centerville - 23529000035676 (Henry)
- Pickup at Fairview - 23529001000463 (Edna)
15. Check in 39999000000252 - should try and fill to Centerville - 23529000035676 (Henry)
16. Check in 39999000000238 - should try and fill to Fairview - 23529001000463 (Edna)
17. Cancel the hold for 23529001000463
18. Check in 39999000000238 should try and fill to 23529000121682
/ check library group setting /
19. Reset the holds to match step 14.
20. Check in 39999000000252 - should try and fill to Fairfield
21. Check in 39999000000238 - should try and fill to Franklin
/check no priority /
22. Reset the holds to match step 14.
23. Check in 39999000000238 - Should fill the Fairfield hold
24. Check in 39999000000252 - Should fill the Franklin hold
/Also check/
Item level holds behave as expected
Different combinations of LocalHoldsPriorityItemControl and LocalHoldsPriorityPatronControl
Sponsored by: Cape Libraries Automated Materials Sharing
Sponsored by: Northeast Kansas Library System (NEKLS)
Signed-off-by: Jason Robb <jrobb@sekls.org>
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Matt Blenkinsop <matt.blenkinsop@openfifth.co.uk>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Added head2 right before sub with missing POD
Signed-off-by: Baptiste Wojtkowski <baptiste.wojtkowski@biblibre.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
This commit is generated using:
% perl misc/devel/tidy.pl
*within* ktd, to get the same version of perltidy than what will be used
by our CI (currently v20230309).
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
The holds queue builder can take a very long time to run on systems with many holds. For example, a partner with 124,784 unfilled ( not found ) holds, is taking about 64 minutes to run. If we run that same number of holds in 5 parallel chunks ( splitting the number of records as evenly as possible, but *not* taking into account the holds per bib ), it takes 21.5 minutes. If we use 10 loops, it takes less then 14 minutes.
Test Plan:
0) Install the Perl library Parallel::ForkManager
1) Generate a huge number of holds ( a few thousand at the minimum )
2) Run the holds queue builder, use the `time` utility to track how much
time it took to run
3) Set HoldsQueueParallelLoopsCount to 10
4) Repeat step 2, note the improvement in speed
5) Experiment with other values for HoldsQueueParallelLoopsCount
6) prove t/db_dependent/HoldsQueue.t
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
This patch simply weeds out allocated holds before filling from the matrix
To test:
1 - Enable RealTimeHoldsQueue
2 - Enable UseTransportCostMatrix
3 - Enable LocalHoldsPriority Give/Home/Home
4 - Administration - Transport cost matrix - enable transfers to/from Centreville and other libraries, add a cost, and save
5 - Find a bib with a Centerville item
6 - Place a hold for a centerville patron
7 - Circulation - Holds queue - All libraries
8 - Note hold is entered twice
9 - On command line:
perl misc/cronjobs/holds/build_holds_queue.pl --force
10 - Run holds queue again, still there twice
11 - Apply patch
12 - On command line:
perl misc/cronjobs/holds/build_holds_queue.pl --force
Confirm allocated only once
13 - Delete hold, place again from bib record (to test real time allocation)
14 - Confirm allocated only once
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Brendan Lawlor <blawlor@clamsnet.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Add an unallocated option to CreateQueue and pass through as needed
Avoid deletion of the tmp_holdsqueue, and only check holds
and items that are not currently matched
A future hold with a higher priority will still fail here - because the
item may already be assigned, but on next change to the biblio it would
be corrected
To test:
1) Apply both patches
2) Enable RealTimeHoldsQueue and set HoldsQueueSkipClosed to "open"
3) Add a holiday to the calendar for all libraries for today, visit:
/cgi-bin/koha/tools/holidays.pl
-- Click today's day on the calendar and pick "Holiday repeated every same day of the week"
-- Click "Copy to all libraries". Hit "Save.
4) Place a biblio-level hold on a biblio record and set the pickup location to a library that has available copies, visit:
-- /cgi-bin/koha/reserve/request.pl?biblionumber=76&borrowernumber=51
-- Click the first "Place hold" button to place the biblio-level hold.
5) Verify that that hold got added to the holds queue, visit:
/cgi-bin/koha/circ/view_holdsqueue.pl?branchlimit=&itemtypeslimit=&ccodeslimit=&locationslimit=&run_report=1
6) Place a biblio-level hold on a biblio record where there are no other holds and copies are available at another location, but not the pickup location, visit:
-- /cgi-bin/koha/reserve/request.pl?biblionumber=437&borrowernumber=51
-- On the "pickup at" dropdown, pick something else other than "Centerville", e.g. "Fairfield".
-- Click the first "Place hold" button to place the biblio-level hold.
7) Check the holds queue again, notice that this 2nd hold was not added to the queue:
/cgi-bin/koha/circ/view_holdsqueue.pl?branchlimit=&itemtypeslimit=&ccodeslimit=&locationslimit=&run_report=1
8) Run the updated cronscript:
perl misc/cronjobs/holds/build_holds_queue.pl --force --unallocated
9) Notice nothing changed in the holds queue, visit:
/cgi-bin/koha/circ/view_holdsqueue.pl?branchlimit=&itemtypeslimit=&ccodeslimit=&locationslimit=&run_report=1
10) Remove the holiday we created previously, visit:
/cgi-bin/koha/tools/holidays.pl
-- Click today's day on the calendar and pick "Delete this holiday"
-- Click "Copy to all libraries". Hit "Save.
11) Run the updated cronscript:
perl misc/cronjobs/holds/build_holds_queue.pl --force --unallocated
12) Confirm the second hold is added to the holds queue, visit:
/cgi-bin/koha/circ/view_holdsqueue.pl?branchlimit=&itemtypeslimit=&ccodeslimit=&locationslimit=&run_report=1
Signed-off-by: Pedro Amorim <pedro.amorim@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Test plan:
prove t/db_dependent/HoldsQueue.t
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
PULL_BRANCHES and PULL_BRANCHES2 felt a little arbitrary, moved
to using a last in the outer loop.
Swapped 'next unless' for an if to more directly show when we are acting
Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
The code here is going to check items held the the pickup location for a request
or from the least cost branch matching the patron's home library against the HoldsQueuePrioritizeBranch
setting
The loop is the same in both case, so lets simplify this a bit to make the intent more clear
To test:
1 - prove -v t/db_dependent/HoldsQueue.t
2 - It should pass before and after this patch
Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
There are a series of repeated checks throughout MapItemsToHoldRequests.
This patch simply consolidates them into a single routine that can be called.
To test:
1 - prove t/db_dependent/HoldsQueue.t
2 - Confirm it passes before and after this patch is applied
Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Phil Ringnalda <phil@chetcolibrary.org>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
When using background jobs, there is a possibility of a race condition where two jobs will be updating the holds queue for the same biblio. We should try to minimize those cases (see bug 34596)
In the meantime though, we should prevent jobs possibly dying, and allow the most recent update to succeed.
There is a possibility two updates wil assign different items to the same reserve, and that a reserve could end up in the queue twice, however, whichever one is filled first will delete both entries. as filling the hold deletes by reserve id (see bug 24359)
This patch adds a transaction to delete and then inset the new row
To test:
1 - prove -v t/db_dependent/Reserves.t
2 - It fails
3 - Apply patch
4 - t/db_dependent/Reserves.t
5 - It succeeds!
Signed-off-by: Emily Lamancusa <emily.lamancusa@montgomerycountymd.gov>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Test Plan:
1) Generate the holds queue
2) Load the holds queue viewer page
3) Apply this patch
4) Restart all the things!
5) Reload the page
6) Note nothing has changed
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Current code removes all items without an active transfer, and any with completed transfers.
This patch moves the conditionals for transfers into the join, then adds a new
condition to remove items with active transfers.
To test:
1 - Apply unit test patch only
2 - prove -v t/db_dependent/HoldsQueue.t
3 - It fails
4 - Apply second patch
5 - prove -v t/db_dependent/HoldsQueue.t
6 - Success!
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Right now the holds queue builder starts filling bib-level holds with
items whose patron's home library matches the item's home library.
It would be good and reasonable to have the option to prioritize
item's whose patron's home library matches the item's holding library
to minimize transfers.
Signed-off-by: Andrew Fuerste-Henry <andrewfh@dubcolib.org>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
update_queue_for_biblio currently
1 - gets the holds on a bib
2 - gets the items available to fill any holds
3 - combines these to build the queue, exiting if there are no holds or items
If there are no holds at step 1, we don't need to do step 2 or 3
This patch simply deletes the queue for this biblio, then exits if there are no holds
To test:
prove -v t/db_dependent/Reserves.t t/db_dependent/Koha/Item.t t/db_dependent/Koha/Hold.t t/db_dependent/Koha/BackgroundJobs/BatchDeleteItem.t t/db_dependent/Koha/BackgroundJobs/BatchDeleteBiblio.t t/db_dependent/HoldsQueue.t t/db_dependent/Circulation_holdsqueue.t t/db_dependent/Biblio_holdsqueue.t t/db_dependent/Biblio.t
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com>
Signed-off-by: Rebecca Coert <rcoert@arlingtonva.us>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
The introduction of _checkHoldPolicy has made this check superfluous.
Test plan stolen/updated from 27068
To test:
1) In library groups add a root group and check it as hold group.
2) Add two libraries to the group
3) In circulation and fines rules, in 'Default checkout, hold and return
policy', in Hold pickup library match change the value to 'From patron's hold group'
4) Place a hold from a patron whose home library is from the group
4.5) perl misc/cronjobs/holds/build_holdsqueue.pl
5) Go to /cgi-bin/koha/circ/view_holdsqueue.pl
6) Select the holding branch of the item with a hold
7) observe no results
8) Apply Patch
9) Repeat 5-6
10) The item should come up on the holds queue results
11) Place a hold on an item where 1 record has 2 copies, 1 in the hold group, 1 not.
12) Run the HoldQueue for the library not in the group and make sure the hold isn't showing.
13) Turn on transportation cost matrix and set costs for the libraries within the group.
14) Place a hold for a patron where multiple copies are on the bib.
15) Check both branch's hold queue for the item, it should only show on the lower cost branch's list if both copies are available.
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
This patch removes the GetTransfers call from
GetItemsAvailableToFillHoldRequestsForBib instead replacing it with an
inline JOIN in the initial query.
Test plan
1/ Run the holds queue
2/ Check the results
3/ Put one of the items in the holds queue into transit
4/ Run the holds queue again
5/ Check that the results do not contain the item that is in transit
6/ Apply the patch
7/ Run the holds queue again
8/ Check that the results still do not contain the item that is in
transit
Rebased-by: Joonas Kylmälä <joonas.kylmala@iki.fi>
Signed-off-by: Joonas Kylmälä <joonas.kylmala@iki.fi>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
I suppose this is similar to circular dependency on other patch
HoldsQueue uses Circulation uses BatchUpdateBiblioHoldsQueueuse HoldsQueue
Without this the background job builds the queue, but reports failure:
Holds queue for biblio The Jacobite clans of the Great Glen, 1650-1784 /. An error occurred (Undefined subroutine &C4::HoldsQueue::GetTransfers called at /kohadevbox/koha/C4/HoldsQueue.pm line 351. )
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
The CreateQueue() method deletes the holds queue data, fetches some
configuration (branches to use, transport cost matrix) and then loops
through a list of biblionumbers, generating the tmp_holdsqueue and
hold_fill_targets rows for the specified biblio.
This patch simply moves that last bit that is run inside the biblios
loop into a separate sub.
The update_queue_for_biblio sub is designed so it does the exact same
thing it did inside the loop, but also gets added the capability of
querying those parameters if not passed, and it also gets a 'delete'
parameter so it deletes the biblio-specific holds queue rows before
starting to work.
This way, it can be reused to write a background job for real-time holds
queue update :-D
To test:
1. Run:
$ kshell
k$ prove t/db_dependent/HoldsQueue.t
=> SUCCESS: Tests pass!
2. Apply this patch
3. Repeat 1
=> SUCCESS: Tests still pass! Behavior is kept!
4. Sign off :-D
Sponsored-by: Montgomery County Public Libraries
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
and some more...
There are lot of inconsistencies in our ->search calls. We could
simplify some of them, but not in this patch. Here we want to prevent
regressions as much as possible and so don't add unecessary changes.
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
This patch makes the code for itemtypeslimit work, and adds options for shelving location and collection code
This also remove the 'post' method from the form to allow easy bookmarking
To test:
1 - Add holds to your system
2 - Run the holds queue builder
3 - Browse to Circulation->Holds queue
4 - Note the library dropdown
5 - Apply patch
6 - Reload and note new options
7 - Test that both limits and 'All' options work as expected
8 - Note that description at top includes options when selected
"### items found for All libraries and item type:(Books)"
Signed-off-by: Owen Leonard <oleonard@myacpl.org>
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
This reverts commit d284735d05.
The following test was failing randomly:
# Failed test 'take from lowest cost branch (don't use cost matrix) holding branch'
# at t/db_dependent/HoldsQueue.t line 1494.
# got: 'LHKtxLk'
# expected: 'JL9C_OR'
# Wrong pick-up/hold for first target (pick_branch, hold_branch, reserves, hold_fill_targets, tmp_holdsqueue)
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>