1 package Koha::StockRotationItem;
3 # Copyright PTFS Europe 2016
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>.
23 use DateTime::Duration;
25 use Koha::DateUtils qw( dt_from_string );
26 use Koha::Item::Transfer;
28 use Koha::StockRotationStage;
29 use Try::Tiny qw( catch try );
31 use base qw(Koha::Object);
35 StockRotationItem - Koha StockRotationItem Object class
39 StockRotationItem class used primarily by stockrotation .pls and the stock
44 Standard Koha::Objects definitions, and additional methods.
57 return 'Stockrotationitem';
62 my $item = Koha::StockRotationItem->item;
64 Returns the item associated with the current stock rotation item.
70 my $rs = $self->_result->itemnumber;
71 return Koha::Item->_new_from_dbic( $rs );
76 my $stage = Koha::StockRotationItem->stage;
78 Returns the stage associated with the current stock rotation item.
84 my $rs = $self->_result->stage;
85 return Koha::StockRotationStage->_new_from_dbic( $rs );
88 =head3 needs_repatriating
90 1|0 = $item->needs_repatriating;
92 Return 1 if this item is currently not at the library it should be at
93 according to our stockrotation plan.
97 sub needs_repatriating {
99 my ( $item, $stage ) = ( $self->item, $self->stage );
100 if ( $self->item->get_transfer ) {
101 return 0; # We're in transit.
102 } elsif ( $item->holdingbranch ne $stage->branchcode_id
103 || $item->homebranch ne $stage->branchcode_id ) {
104 return 1; # We're not where we should be.
106 return 0; # We're at home.
110 =head3 needs_advancing
112 1|0 = $item->needs_advancing;
114 Return 1 if this item is ready to be moved on to the next stage in its rota.
118 sub needs_advancing {
120 return 0 if $self->item->get_transfer; # intransfer: don't advance.
121 return 1 if $self->fresh; # Just on rota: advance.
122 my $completed = $self->item->_result->branchtransfers->search(
123 { 'reason' => "StockrotationAdvance" },
124 { order_by => { -desc => 'datearrived' } }
126 # Do maths on whether we need to be moved on.
127 if ( $completed->count ) {
128 my $arrival = dt_from_string(
129 $completed->next->datearrived, 'iso'
131 my $duration = DateTime::Duration
132 ->new( days => $self->stage->duration );
133 if ( $arrival + $duration le dt_from_string() ) {
139 warn "We have no historical branch transfer for item " . $self->item->itemnumber . "; This should not have happened!";
145 1|0 = $sritem->repatriate
147 Put this item into branch transfer with 'StockrotationRepatriation' comment, so
148 that it may return to it's stage.branch to continue its rota as normal.
150 Note: Stockrotation falls outside of the normal branch transfer limits and so we
151 pass 'ignore_limits' in the call to request_transfer.
156 my ( $self, $msg ) = @_;
158 # Create the transfer.
160 $self->item->request_transfer(
162 to => $self->stage->branchcode,
163 reason => "StockrotationRepatriation",
170 # Ensure the homebranch is still in sync with the rota stage
171 $self->item->homebranch( $self->stage->branchcode_id )->store;
173 return defined($transfer) ? 1 : 0;
178 1|0 = $sritem->advance;
180 Put this item into branch transfer with 'StockrotationAdvance' comment, to
181 transfer it to the next stage in its rota.
183 If this is the last stage in the rota and this rota is cyclical, we return to
184 the first stage. If it is not cyclical, then we delete this
187 If this item is 'indemand', and advance is invoked, we disable 'indemand' and
188 advance the item as per usual.
190 Note: Stockrotation falls outside of the normal branch transfer limits and so we
191 pass 'ignore_limits' in the call to request_transfer.
197 my $item = $self->item;
198 my $current_branch = $item->holdingbranch;
201 # Find and interpret our stage
202 my $stage = $self->stage;
204 if ( $self->indemand && !$self->fresh ) {
205 $self->indemand(0); # De-activate indemand
210 if ( $self->fresh ) {
211 $new_stage = $self->stage->first_sibling || $self->stage;
212 $self->fresh(0); # Reset fresh
215 elsif ( !$stage->last_sibling ) {
217 if ( $stage->rota->cyclical ) {
219 $stage->first_sibling || $stage; # Revert to first stage.
222 $self->delete; # StockRotationItem is done.
227 $new_stage = $self->stage->next_sibling; # Just advance
231 # Update stage and record transfer
232 $self->stage_id( $new_stage->stage_id ); # Set new stage
234 $item->homebranch( $new_stage->branchcode_id )->store; # Update homebranch
236 $item->request_transfer(
238 to => $new_stage->branchcode,
239 reason => "StockrotationAdvance",
240 ignore_limits => 1 # Ignore transfer limits
245 if ( $_->isa('Koha::Exceptions::Item::Transfer::InQueue') ) {
247 my $found_transfer = $_->transfer;
248 if ( $found_transfer->in_transit
249 || $found_transfer->reason eq 'Reserve'
250 || $found_transfer->reason eq 'RotatingCollection' )
252 return $item->request_transfer(
254 to => $new_stage->branchcode,
255 reason => "StockrotationAdvance",
261 return $item->request_transfer(
263 to => $new_stage->branchcode,
264 reason => "StockrotationAdvance",
268 ); # Replace transfer
275 if $item->holdingbranch eq $new_stage->branchcode_id && !$item->checkout;
276 # If item is already at branch, and not checked out
277 # If item is checked out, the return will either receive or initiate the transfer
282 =head3 toggle_indemand
284 $sritem->toggle_indemand;
286 Toggle this items in_demand status.
288 If the item is in the process of being advanced to the next stage then we cancel
289 the transfer, revert the advancement and reset the 'StockrotationAdvance' counter,
290 as though 'in_demand' had been set prior to the call to advance, by updating the
291 in progress transfer.
295 sub toggle_indemand {
298 # Toggle the item's indemand flag
299 my $new_indemand = ($self->indemand == 1) ? 0 : 1;
301 # Cancel 'StockrotationAdvance' transfer if one is in progress
303 my $item = $self->item;
304 my $transfer = $item->get_transfer;
305 if ($transfer && $transfer->reason eq 'StockrotationAdvance') {
306 my $stage = $self->stage;
308 if ( $stage->rota->cyclical && !$stage->first_sibling ) { # First stage
309 $new_stage = $stage->last_sibling;
311 $new_stage = $stage->previous_sibling;
313 $self->stage_id($new_stage->stage_id)->store; # Revert stage change
314 $item->homebranch($new_stage->branchcode_id)->store; # Revert update homebranch
315 $new_indemand = 0; # Reset indemand
316 $transfer->tobranch($new_stage->branchcode_id); # Reset StockrotationAdvance
317 $transfer->datearrived(dt_from_string); # Reset StockrotationAdvance
322 $self->indemand($new_indemand)->store;
327 my $report = $item->investigate;
329 Return the base set of information, namely this individual item's report, for
330 generating stockrotation reports about this stockrotationitem.
337 title => $self->item->_result->biblioitem
338 ->biblionumber->title,
339 author => $self->item->_result->biblioitem
340 ->biblionumber->author,
341 callnumber => $self->item->itemcallnumber,
342 location => $self->item->location,
343 onloan => $self->item->onloan,
344 barcode => $self->item->barcode,
345 itemnumber => $self->itemnumber_id,
346 branch => $self->item->_result->holdingbranch,
350 if ( $self->fresh ) {
351 $reason = 'initiation';
352 } elsif ( $self->needs_repatriating ) {
353 $reason = 'repatriation';
354 } elsif ( $self->needs_advancing ) {
355 $reason = 'advancement';
356 $reason = 'in-demand' if $self->indemand;
358 $reason = 'not-ready';
360 $item_report->{reason} = $reason;
369 Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>