From 5683be9c705dc1114691e1ee594256cd93ae12b9 Mon Sep 17 00:00:00 2001
From: Nick Clemens
Date: Fri, 21 Nov 2025 18:46:12 +0000
Subject: [PATCH] Bug 41282: Alert staff when patron's hold is filled at
checkout
When an item is checked out and the patron has a hold on the biblio we will fill thart hold with the item in hand
Sometimes the hold this item fills has another copy that is already in transit or waiting on the shelf.
We need to alert staff when this happens
This patch adds a return of the hold from MoveReserve and adds an object message to the issue that is passed to the template
If the hold was waiting or in transit we additionally pass a message in the hold that is returned
To test:
1 - Place a biblio level hold for a patron
2 - Check an item from the biblio in and confirm the hold
3 - Check out a different item from the biblio to the patron
4 - Note the hold is filled, but there is no notice
5 - Apply the patch
6 - Repeat 1-3, note there is now a notice that a waiting hold was filled
7 - Place another hold for the patron for delivery at current branch
8 - Check the item in at a different branch and confirm transfer
9 - Switch back to first branch and check a different item from the biblio out to the patron
10 - Confirm the hold is filled and you are notified that a hold in transit was filled
---
C4/Circulation.pm | 4 ++-
C4/Reserves.pm | 17 ++++++++++++-
.../prog/en/modules/circ/circulation.tt | 25 +++++++++++++++++++
3 files changed, 44 insertions(+), 2 deletions(-)
diff --git a/C4/Circulation.pm b/C4/Circulation.pm
index 0a8df342638..433c8774d80 100644
--- a/C4/Circulation.pm
+++ b/C4/Circulation.pm
@@ -1608,6 +1608,7 @@ sub AddIssue {
my $barcodecheck = CheckValidBarcode($barcode);
my $issue;
+ my $filled_hold;
if ( $datedue && ref $datedue ne 'DateTime' ) {
$datedue = dt_from_string($datedue);
@@ -1716,7 +1717,7 @@ sub AddIssue {
);
}
- C4::Reserves::MoveReserve( $item_object, $patron, $cancelreserve );
+ $filled_hold = C4::Reserves::MoveReserve( $item_object, $patron, $cancelreserve );
# Starting process for transfer job (checking transfer and validate it if we have one)
if ( my $transfer = $item_object->get_transfer ) {
@@ -1989,6 +1990,7 @@ sub AddIssue {
if C4::Context->preference('RealTimeHoldsQueue');
}
}
+ $issue->add_message( { type => 'hold_filled', payload => $filled_hold, message => 'F' } );
return $issue;
}
diff --git a/C4/Reserves.pm b/C4/Reserves.pm
index c4eb3b7ff69..d0c7701418e 100644
--- a/C4/Reserves.pm
+++ b/C4/Reserves.pm
@@ -2174,7 +2174,7 @@ sub _ShiftPriority {
=head2 MoveReserve
- MoveReserve( $item, $patron, $cancelreserve )
+ my $filled_hold = MoveReserve( $item, $patron, $cancelreserve )
Use when checking out an item to handle reserves
If $cancelreserve boolean is set to true, it will remove existing reserve
@@ -2204,6 +2204,7 @@ sub MoveReserve {
if ( $res && $res->{borrowernumber} == $patron->borrowernumber ) {
my $hold = Koha::Holds->find( $res->{reserve_id} );
$hold->fill( { item_id => $item->id } );
+ return $hold;
} else {
# The item is reserved by someone else.
@@ -2227,7 +2228,20 @@ sub MoveReserve {
if ($hold) {
# The item is reserved by the current patron
+ # if we are filling a hold previously found we need to alert the staff
+ if ( $hold->found() eq 'W' ) {
+ $hold->add_message(
+ { message => "W", type => 'filled_waiting', payload => { waiting_branch => $hold->branchcode } } );
+ } elsif ( $hold->found() eq 'T' ) {
+ $hold->add_message(
+ {
+ message => "T", type => 'filled_transit',
+ payload => { from_branch => $hold->item->holdingbranch }
+ }
+ );
+ }
$hold->fill( { item_id => $item->id } );
+ return $hold;
}
$hold = Koha::Holds->find( $res->{reserve_id} );
@@ -2237,6 +2251,7 @@ sub MoveReserve {
$hold->cancel;
}
}
+ return;
}
=head2 MergeHolds
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
index 672d27da176..d8a3eba66fc 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
@@ -963,6 +963,31 @@
[% END %]
Due on [% issue.date_due | $KohaDates as_due_date => 1 %]
+ [%- SET issue_messages = issue.object_messages %]
+ [%- IF (issue_messages.size) %]
+
+ [%- FOREACH message IN issue_messages %]
+ [%- IF (message.type == 'hold_filled') %]
+
+ [%- SET hold = message.payload %]
+ [%- SET hold_messages = hold.object_messages -%]
+ [%- FOREACH message IN hold_messages %]
+ [%- IF (message.type == 'filled_transit') %]
+ [% SET from_branch = message.payload.from_branch | html %]
+ This item filled a hold that had another item in-transit to this patron from [% Branches.GetName(from_branch) %].
+ [%- ELSIF (message.type == 'filled_waiting') %]
+ [% SET waiting_branch = message.payload.waiting_branch | html %]
+ This item filled a hold that had another item waiting on the shelf for this patron at [% Branches.GetName(waiting_branch) %], please check the holds shelf and check in any other
+ copies waiting for this patron.
+ [%- END %]
+ [%- END %]
+
+ [%- ELSE %]
+
Message type: ([% message.type | html %]) Message: [% message.message | html %]
+ [%- END %]
+ [%- END %]
+
+ [%- END %]
[% END %]
--
2.39.5