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->itemnumber;
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->itemnumber, $self->stage );
100 if ( $self->itemnumber->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->itemnumber->get_transfer; # intransfer: don't advance.
121 return 1 if $self->fresh; # Just on rota: advance.
122 my $completed = $self->itemnumber->_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 itemnumber " . $self->itemnumber->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->itemnumber->request_transfer(
162 to => $self->stage->branchcode,
163 reason => "StockrotationRepatriation",
170 # Ensure the homebranch is still in sync with the rota stage
171 $self->itemnumber->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->itemnumber;
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; # Already at branch
280 =head3 toggle_indemand
282 $sritem->toggle_indemand;
284 Toggle this items in_demand status.
286 If the item is in the process of being advanced to the next stage then we cancel
287 the transfer, revert the advancement and reset the 'StockrotationAdvance' counter,
288 as though 'in_demand' had been set prior to the call to advance, by updating the
289 in progress transfer.
293 sub toggle_indemand {
296 # Toggle the item's indemand flag
297 my $new_indemand = ($self->indemand == 1) ? 0 : 1;
299 # Cancel 'StockrotationAdvance' transfer if one is in progress
301 my $item = $self->itemnumber;
302 my $transfer = $item->get_transfer;
303 if ($transfer && $transfer->reason eq 'StockrotationAdvance') {
304 my $stage = $self->stage;
306 if ( $stage->rota->cyclical && !$stage->first_sibling ) { # First stage
307 $new_stage = $stage->last_sibling;
309 $new_stage = $stage->previous_sibling;
311 $self->stage_id($new_stage->stage_id)->store; # Revert stage change
312 $item->homebranch($new_stage->branchcode_id)->store; # Revert update homebranch
313 $new_indemand = 0; # Reset indemand
314 $transfer->tobranch($new_stage->branchcode_id); # Reset StockrotationAdvance
315 $transfer->datearrived(dt_from_string); # Reset StockrotationAdvance
320 $self->indemand($new_indemand)->store;
325 my $report = $item->investigate;
327 Return the base set of information, namely this individual item's report, for
328 generating stockrotation reports about this stockrotationitem.
335 title => $self->itemnumber->_result->biblioitem
336 ->biblionumber->title,
337 author => $self->itemnumber->_result->biblioitem
338 ->biblionumber->author,
339 callnumber => $self->itemnumber->itemcallnumber,
340 location => $self->itemnumber->location,
341 onloan => $self->itemnumber->onloan,
342 barcode => $self->itemnumber->barcode,
343 itemnumber => $self->itemnumber_id,
344 branch => $self->itemnumber->_result->holdingbranch,
348 if ( $self->fresh ) {
349 $reason = 'initiation';
350 } elsif ( $self->needs_repatriating ) {
351 $reason = 'repatriation';
352 } elsif ( $self->needs_advancing ) {
353 $reason = 'advancement';
354 $reason = 'in-demand' if $self->indemand;
356 $reason = 'not-ready';
358 $item_report->{reason} = $reason;
367 Alex Sassmannshausen <alex.sassmannshausen@ptfs-europe.com>