Koha::Hold::set_waiting calls Koha::Calendar::days_forward to derive the
holds-shelf expiration date when ExcludeHolidaysFromMaxPickUpDelay is on.
days_forward iterated next_open_days($dt, 1) ReservesMaxPickUpDelay times,
and next_open_days consults get_push_amt for every closed day it
encounters. Under useDaysMode=Dayweek, get_push_amt returns 7 for any
closure that is not a permanently closed weekday -- so an intermediate
Bank Holiday Monday inside the pickup window pushed the cursor a whole
week forward instead of one day, inflating the expiration by seven days.
Dayweek is a loan-due-date concept: it exists to keep a Friday-due loan
due on a Friday across closures. A patron does not pick a weekday for a
hold-shelf collection; staff set the expiration when they trap the item,
and the only thing that should drive it is how many open days the patron
should have to come and collect. days_forward is now decoupled from
useDaysMode and always counts forward one open day at a time, ignoring
closures without consuming them from the count.
next_open_days, prev_open_days, get_push_amt and addDays are unchanged --
loan due-date math keeps the existing Dayweek behaviour.
Test plan:
1. Inside KTD, run the updated unit tests:
prove t/db_dependent/Calendar.t
prove t/db_dependent/Hold.t
Confirm both pass, including the new Bug 42608 sub-tests. These cover
the full matrix of starting weekdays and useDaysMode values; the
manual steps below are a single confirmatory pass through the UI.
2. Manual reproduction (UI only -- no database or CLI access needed):
- Set sysprefs: useDaysMode=Dayweek, ReservesMaxPickUpDelay=6,
ExcludeHolidaysFromMaxPickUpDelay=ON, ExpireReservesOnHolidays=ON.
- Administration > Calendar: on a test branch, add one single
(one-time) holiday -- not weekly/repeating -- on any weekday within
the next 6 days that isn't already closed (e.g. the day after
tomorrow, as long as it isn't a Sunday or other closed day). This
one-off closure inside the pickup window is what triggers the bug.
- Place a hold on an available item, then check the item in at that
branch and confirm/trap it. This stamps waitingdate with today's
date automatically -- no manual date entry required.
- Check the hold's expiration date (Holds awaiting pickup list, or
the patron's holds tab):
Without the fix: expiration lands a full 7 days later than it
should (today + 6 + 7), from the week-jump.
With the fix: expiration is today + 6 open days, only skipping
the one closed day.
3. Verify the existing Calendar mode behaviour is unchanged:
- Switch useDaysMode to Calendar and repeat step 2 -- the same
expected expiration date should apply.
4. Verify loan due-date behaviour is unchanged:
- With useDaysMode=Dayweek, check out an item whose loan period would
place its due date on the same closed day used in step 2. Confirm
the due date still rolls forward by a whole week (the original
Dayweek intent), proving this patch did not regress
addDays/addDuration.
Sponsored-by: OpenFifth <https://openfifth.co.uk/>
Signed-off-by: Jackie Usher <jackie.usher@westsussex.gov.uk>
Signed-off-by: Andrew Fuerste Henry <andrew@bywatersolutions.com>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
add_weekly_closure/delete_weekly_closure and add_repeating_closure/
delete_repeating_closure returned $self without refreshing
$self->{weekly_closed_days}/{day_month_closed_days}, so a calendar object
would keep reporting the pre-change state to is_holiday (and everything
built on it - days_forward, next_open_days, etc.) until it was
re-instantiated. This is distinct from the _holidays Koha::Caches entry,
which single/exception closures already flush correctly on store/delete.
Call _init to rebuild both structures from the database after each
add/delete, so the same object reflects the change immediately.
Test plan:
1) prove t/db_dependent/Koha/Library/Calendar.t t/db_dependent/Calendar.t
t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t
t/db_dependent/Holds/WaitingReserves.t t/db_dependent/Koha/CurbsidePickups.t
t/db_dependent/Reserves/CancelExpiredReserves.t
t/db_dependent/api/v1/libraries.t
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
store() only flushes the _holidays cache on insert, on the assumption that
updates only ever touch title/description. That assumption held for every
current caller (ModSingleholiday/ModExceptionholiday only ever change those
two fields), but nothing enforced it - a future caller updating date in
place would silently desync the cache for up to its TTL, with no error.
Make the assumption explicit: reject an update that changes date, rather
than silently allowing it. Callers that need to move a closure/exception to
a different date must delete and re-add.
Test plan:
1) prove t/db_dependent/Koha/Library/Calendar.t t/db_dependent/Calendar.t
t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
C4::Calendar::insert_week_day_holiday used to croak "Invalid weekday
$weekday" unless $weekday =~ m/^[0-6]$/. That guard was dropped when the
insert delegated to Koha::Library::Calendar::WeeklyClosure, and nothing
replaced it - an out-of-range or undef weekday now persists silently to
library_weekly_closures instead of failing at the API boundary.
Add the check to WeeklyClosure->store() rather than the legacy wrapper, so
every caller (C4::Calendar, Koha::Library::Calendar->add_weekly_closure,
and any future REST/admin caller) gets it, not just the old entry point.
Test plan:
1) prove t/db_dependent/Koha/Library/Calendar.t t/db_dependent/Calendar.t
t/db_dependent/Holidays.t t/db_dependent/HoldsQueue.t
t/db_dependent/Holds/WaitingReserves.t
Signed-off-by: Tomás Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
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>
Fixed a pre-existing bug where branch transfer limits would prevent ANY
transfer if the optimal library was blocked, instead of trying the next
best candidate.
Original behavior:
- Sort candidates by best ratio
- Check if transfer to best candidate is allowed
- If not allowed: exit loop immediately (bug!) and return undef
- Result: No transfer created even if other valid candidates exist
Fixed behavior:
- Sort candidates by best ratio
- Check if transfer to best candidate is allowed
- If allowed: use that library and exit loop
- If not allowed: continue to next candidate
- Result: Uses the best ALLOWED candidate
This fix ensures that when branch transfer limits block the optimal
destination, the system will try the next-best option instead of
giving up entirely.
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
Refactored lowest_ratio_library() to eliminate the N+1 query problem
by using aggregated queries with GROUP BY instead of per-branch queries.
Performance improvement:
- Before: O(3n) queries where n = number of branches with float limits
Example: 20 branches = 60 database queries
- After: O(3) queries regardless of number of branches
Example: 20 branches = 3 database queries
The optimization uses three aggregated queries:
1. Single query with GROUP BY to get item counts at all branches
2. Single query with GROUP BY to get in-transit-to counts for all branches
3. Single query with GROUP BY to get in-transit-from counts for all branches
Results are combined in memory to calculate ratios, maintaining identical
logic and behavior while dramatically improving database efficiency.
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
- Add comprehensive POD documentation for lowest_ratio_library() method
including parameter descriptions, return values, and algorithm explanation
- Add database index on itemtype column in library_float_limits table
to improve query performance when searching by itemtype
Signed-off-by: Martin Renvoize <martin.renvoize@openfifth.co.uk>
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>
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>
Sponsored-by: Catalyst IT
Signed-off-by: Sam Lau <samalau@gmail.com>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
In some of our Koha:: objects we have methods that cache their result and return it in subsequent calls. However there is no invalidation of the cache if the object is modified.
For instance, in Koha/ArticleRequest.pm
sub biblio {
my ($self) = @_;
$self->{_biblio} ||= Koha::Biblios->find( $self->biblionumber() );
return $self->{_biblio};
}
This pattern exists in several places.
It can lead to confusion and incorrect results, such as:
use Koha::ArticleRequests;
my $ar = Koha::ArticleRequest->new({
borrowernumber => 42,
biblionumber => 42,
})->store;
say $ar->biblio->biblionumber; # Display 42, correct
$ar->set({ biblionumber => 24 })->store;
say $ar->biblio->biblionumber; # Display 42, wrong
$ar->discard_changes;
say $ar->biblio->biblionumber; # Display 42, wrong
$ar->delete;
We should remove those caching and rely on DBIC/DBMS caching mechanism instead.
This patch is adjusting the trivial occurrences
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
get_search_groups from Koha/Library/Groups.pm returns library groups sorted by title.
Test plan:
1- Go to administration > library groups and create multiple library groups with different names (e.g. AGroup, BGroup, ÄGroup, etc.). Make sure to tick "Use for OPAC search groups" checkbox.
2- Go to advanced search in OPAC.
3- Under "Groups of librairies" , click the select button.
4- Notice that the library groups are not in alphabetical order.
5- Apply the patch.
6- Notice that the library groups are in alphabetical order.
7- Run `prove t/db_dependent/LibraryGroups.t` and all test should pass.
Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Katrin Fischer <katrin.fischer@bsz-bw.de>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
On bug 29844 we decided to remove wantarray from Koha::Objects->search.
Reviewing the difference occurrences I found some unnecessary uses of ->as_list,
where iterators should be used instead.
This patch only removes the obvious places, not the tricky ones.
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
I think a rebase perhaps lost a change here.. this fix gets the unit
tests passing again.
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
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>
The current code gets all group members, then loops through and fetches the library if there is a
branchcode, or recursively calls itself if a group. This slows down performance.
We can utilize the 'libraries' method to get all child libraries at once, then make a check
for child groups separately
To recreate:
1 - Add 100 items to a biblio
2 - Define a library group as a hold group
3 - Add all libraries to the group
4 - Set 'Default checkout, hold and return policy'->'Hold pickup library match' = 'Any library'
5 - place a hold on the record and note load time after patron is selected
6 - Set 'Default checkout, hold and return policy'->'Hold pickup library match' = 'Patrons hold group'
7 - place a hold, note longer load time after patron selection
8 - Apply patch
9 - note improvement
10 - prove -v t/db_dependent/Koha/Libraries.t
Signed-off-by: Andrew Fuerste-Henry <andrew@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Fridolin Somers <fridolin.somers@biblibre.com>
On bug 17591 we discovered that there was something weird going on with
the way we export and use subroutines/modules.
This patch tries to standardize our EXPORT to use EXPORT_OK only.
That way we will need to explicitely define the subroutine we want to
use from a module.
This patch is a squashed version of:
Bug 17600: After export.pl
Bug 17600: After perlimport
Bug 17600: Manual changes
Bug 17600: Other manual changes after second perlimports run
Bug 17600: Fix tests
And a lot of other manual changes.
export.pl is a dirty script that can be found on bug 17600.
"perlimport" is:
git clone https://github.com/oalders/App-perlimports.git
cd App-perlimports/
cpanm --installdeps .
export PERL5LIB="$PERL5LIB:/kohadevbox/koha/App-perlimports/lib"
find . \( -name "*.pl" -o -name "*.pm" \) -exec perl App-perlimports/script/perlimports --inplace-edit --no-preserve-unused --filename {} \;
The ideas of this patch are to:
* use EXPORT_OK instead of EXPORT
* perltidy the EXPORT_OK list
* remove '&' before the subroutine names
* remove some uneeded use statements
* explicitely import the subroutines we need within the controllers or
modules
Note that the private subroutines (starting with _) should not be
exported (and not used from outside of the module except from tests).
EXPORT vs EXPORT_OK (from
https://www.thegeekstuff.com/2010/06/perl-exporter-examples/)
"""
Export allows to export the functions and variables of modules to user’s namespace using the standard import method. This way, we don’t need to create the objects for the modules to access it’s members.
@EXPORT and @EXPORT_OK are the two main variables used during export operation.
@EXPORT contains list of symbols (subroutines and variables) of the module to be exported into the caller namespace.
@EXPORT_OK does export of symbols on demand basis.
"""
If this patch caused a conflict with a patch you wrote prior to its
push:
* Make sure you are not reintroducing a "use" statement that has been
removed
* "$subroutine" is not exported by the C4::$MODULE module
means that you need to add the subroutine to the @EXPORT_OK list
* Bareword "$subroutine" not allowed while "strict subs"
means that you didn't imported the subroutine from the module:
- use $MODULE qw( $subroutine list );
You can also use the fully qualified namespace: C4::$MODULE::$subroutine
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Bug 9978 should have fixed them all, but some were missing.
We want all the license statements part of Koha to be identical, and
using the GPLv3 statement.
Signed-off-by: David Nind <david@davidnind.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
This patch adds new methods in Koha::Library::Groups and Koha::Library.
1) For Koha::Library::Groups adds get_root_ancestor that returns all root
groups for a given search parameters, for example
Koha::Library::Groups->get_root_ancestor( { id => $group_id } )
2) For Koha::Library adds
2.1) get_hold_libraries: returns all libraries (including self) that
belongs to the same holdgroups. If $self belongs to several holdgroups
it will return a distinct list of all libraries belonging to them.
2.2) validate_hold_sibling: Returns 1 if the given parameters matches any of the
libraries that belong to any of the holdgroups this library belongs. For example
$library->validate_hold_sibling( { branchcode => $branchcode } )
To test:
1) apply this patch
2) prove t/db_dependent/Koha/Libraries.t t/db_dependent/LibraryGroups.t
SUCCESS => green letters :-D
3) Sign off
Sponsored-by: VOKAL
Signed-off-by: Josef Moravec <josef.moravec@gmail.com>
Signed-off-by: Liz Rea <wizzyrea@gmail.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
To test:
1 - Add a library group (Admin->Library groups)
2 - Enable use as an opac and staff search limit
3 - Add some libraries to the group
4 - Visit advanced search on staff and opac
5 - Note the dropdown has as many empty rows as there are libraries
in the group
6 - Apply patch, restart all the things
7 - Visit staff and opac advanced search
8 - Confirm the group dropdowns are correct
9 - Enable OpacMastheadLibraryPulldown
10 - Ensure the dropdown on opac shows groups correctly
11 - Confirm earchign groups works from all three locations
12 - prove -v t/db_dependent/LibraryGroups.t
Signed-off-by: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Signed-off-by: Josef Moravec <josef.moravec@gmail.com>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
The 'authname' field required for OverDrive can differ per branch.
This patch adds Koha Objects for dealing with OD info and submitting
authnames per branch. The description is left open so future branch info
can be added.
To test:
1 - prove -v t/db_dependent/Koha/Library/OverDriveInfos.t
2 - visit cgi-bin/koha/admin/overdrive.pl
3 - Add some authnames for various branches
4 - Verify data saves correctly
Signed-off-by: Sandy Allgood <sandy.allgood@citruslibraries.org>
Signed-off-by: Chris Cormack <chrisc@catalyst.net.nz>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Instead of a list of Koha::Library::Group
Ideally it should be a Koh::Libraries iterator
Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Marcel de Rooy <m.de.rooy@rijksmuseum.nl>
Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Instead of basing the group searches on the group name, which is an
inherently touchy system, we should use the same checkbox style that
Jonathan introduced for the patron limits by group feature.
Test Plan:
1) Check to ensure existing group searches still show as they used to
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
This is more a follow-up for bug 15707. It could be moved on its own bug report
if necessary.
IMPORTANT NOTE: At the moment the feature only works for 1 level depth, see
bug 15707 comment 166+ for the discussion
It means that if we have:
root_group
+ groupA
+ groupA1
+ groupA1_library2
+ groupA_library1
+ groupA2
+ groupB
+ groupB_library1
groupA1_library2 is not considered a child of groupA1.
Note that this can change.
Test plan:
prove t/db_dependent/LibraryGroups.t
should return green
Signed-off-by: Signed-off-by: Jon McGowan <jon.mcgowan@ptfs-europe.com>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Test Plan:
1) Apply this patch set
2) Note your existing search groups have been ported over to the new
__SEARCH_GROUPS__ group if you had any
3) Create the group __SEARCH_GROUPS__ if one does not already exist
4) Add some first level subgroups to this group, add libraries to those groups
5) Search the library group searching in the intranet and opac
6) Note you get the same results as pre-patch
Signed-off-by: Josef Moravec <josef.moravec@gmail.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Signed-off-by: Mark Tompsett <mtompset@hotmail.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
Signed-off-by: Jonathan Druart <jonathan.druart@bugs.koha-community.org>