3 # Copyright 2020 Aleisha Amohia <aleisha@catalyst.net.nz>
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 use Koha::DateUtils qw( dt_from_string );
27 use C4::Stats qw( UpdateStats );
29 use base qw(Koha::Objects);
33 Koha::Recalls - Koha Recalls Object set class
39 =head3 filter_by_current
41 my $current_recalls = $recalls->filter_by_current;
43 Returns a new resultset, filtering out finished recalls.
47 sub filter_by_current {
62 =head3 filter_by_finished
64 my $finished_recalls = $recalls->filter_by_finished;
66 Returns a new resultset, filtering out current recalls.
70 sub filter_by_finished {
86 my ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall({
87 patron => $patron_object,
88 biblio => $biblio_object,
89 branchcode => $branchcode,
91 expirationdate => $expirationdate,
95 Add a new requested recall. We assume at this point that a recall is allowed to be placed on this item or biblio. We are past the checks and are now doing the recall.
96 Interface param is either OPAC or INTRANET
97 Send a RETURN_RECALLED_ITEM notice.
98 Add statistics and logs.
99 #FIXME: Add recallnotes and priority when staff-side recalls is added
104 my ( $self, $params ) = @_;
106 my $patron = $params->{patron};
107 my $biblio = $params->{biblio};
108 return if ( !defined($patron) or !defined($biblio) );
109 my $branchcode = $params->{branchcode};
110 $branchcode ||= $patron->branchcode;
111 my $item = $params->{item};
112 my $itemnumber = $item ? $item->itemnumber : undef;
113 my $expirationdate = $params->{expirationdate};
114 my $interface = $params->{interface};
116 if ( $expirationdate ){
117 my $now = dt_from_string;
118 $expirationdate = dt_from_string($expirationdate)->set({ hour => $now->hour, minute => $now->minute, second => $now->second });
121 my $recall_request = Koha::Recall->new({
122 patron_id => $patron->borrowernumber,
123 created_date => dt_from_string(),
124 biblio_id => $biblio->biblionumber,
125 pickup_library_id => $branchcode,
126 status => 'requested',
127 item_id => defined $itemnumber ? $itemnumber : undef,
128 expiration_date => $expirationdate,
129 item_level => defined $itemnumber ? 1 : 0,
132 if (defined $recall_request->id){ # successful recall
133 my $recall = Koha::Recalls->find( $recall_request->id );
135 # get checkout and adjust due date based on circulation rules
136 my $checkout = $recall->checkout;
137 my $recall_due_date_interval = Koha::CirculationRules->get_effective_rule({
138 categorycode => $checkout->patron->categorycode,
139 itemtype => $checkout->item->effective_itemtype,
140 branchcode => $branchcode,
141 rule_name => 'recall_due_date_interval',
143 my $due_interval = defined $recall_due_date_interval ? $recall_due_date_interval->rule_value : 5;
144 my $timestamp = dt_from_string( $recall->timestamp );
145 my $checkout_timestamp = dt_from_string( $checkout->date_due );
146 my $due_date = $timestamp->set(
148 hour => $checkout_timestamp->hour, minute => $checkout_timestamp->minute,
149 second => $checkout_timestamp->second
151 )->add( days => $due_interval );
152 $checkout->update( { date_due => $due_date } );
154 # get itemnumber of most relevant checkout if a biblio-level recall
155 unless ( $recall->item_level ) { $itemnumber = $checkout->itemnumber; }
157 # send notice to user with recalled item checked out
158 my $letter = C4::Letters::GetPreparedLetter (
159 module => 'circulation',
160 letter_code => 'RETURN_RECALLED_ITEM',
161 branchcode => $recall->pickup_library_id,
163 biblio => $biblio->biblionumber,
164 borrowers => $checkout->borrowernumber,
165 items => $itemnumber,
166 issues => $itemnumber,
170 C4::Message->enqueue( $letter, $checkout->patron, 'email' );
172 $item = Koha::Items->find( $itemnumber );
173 # add to statistics table
174 C4::Stats::UpdateStats(
176 branch => C4::Context->userenv->{'branch'},
178 itemnumber => $itemnumber,
179 borrowernumber => $recall->patron_id,
180 itemtype => $item->effective_itemtype,
181 ccode => $item->ccode,
182 categorycode => $checkout->patron->categorycode,
183 interface => $interface,
188 'after_recall_action',
191 payload => { recall => $recall->get_from_storage }, # FIXME Bug 32107
196 C4::Log::logaction( 'RECALLS', 'CREATE', $recall->id, "Recall requested by borrower #" . $recall->patron_id, $interface ) if ( C4::Context->preference('RecallsLog') );
198 return ( $recall, $due_interval, $due_date );
201 # unable to add recall
207 my $message = Koha::Recalls->move_recall({
208 recall_id = $recall_id,
210 item => $item_object,
211 borrowernumber => $borrowernumber,
214 A patron is attempting to check out an item that has been recalled by another patron.
215 If the recall is requested/overdue, they have the option of cancelling the recall.
216 If the recall is waiting, they also have the option of reverting the waiting status.
218 We can also fulfill the recall here if the recall is placed by this borrower.
220 recall_id = ID of the recall to perform the action on
221 action = either cancel or revert
222 item = item object that the patron is attempting to check out
223 borrowernumber = borrowernumber of the patron that is attemptig to check out
228 my ( $self, $params ) = @_;
230 my $recall_id = $params->{recall_id};
231 my $action = $params->{action};
232 return 'no recall_id provided' if ( !defined $recall_id );
233 my $item = $params->{item};
234 my $borrowernumber = $params->{borrowernumber};
236 my $message = 'no action provided';
238 if ( $action and $action eq 'cancel' ) {
239 my $recall = Koha::Recalls->find( $recall_id );
240 $recall->set_cancelled;
241 $message = 'cancelled';
242 } elsif ( $action and $action eq 'revert' ) {
243 my $recall = Koha::Recalls->find( $recall_id );
244 $recall->revert_waiting;
245 $message = 'reverted';
248 if ( $message eq 'no action provided' and $item and $item->biblionumber and $borrowernumber ) {
249 # move_recall was not called to revert or cancel, but was called to fulfill
250 my $recall = Koha::Recalls->search(
252 patron_id => $borrowernumber,
253 biblio_id => $item->biblionumber,
254 item_id => [ $item->itemnumber, undef ],
257 { order_by => { -asc => 'created_date' } }
260 $recall->set_fulfilled;
261 $message = 'fulfilled';
268 =head2 Internal methods
283 return 'Koha::Recall';