From f87fe27af47e71ad9d53e1f9c2310ce57a0f7b25 Mon Sep 17 00:00:00 2001 From: Alex Sassmannshausen Date: Thu, 8 Dec 2016 18:32:04 +0100 Subject: [PATCH] Bug 11897: Add Koha::Objects for Stockrotation module. * Koha/Stockrotationitem.pm: New file. * Koha/Stockrotationitems.pm: New file. * Koha/Stockrotationrota.pm: New file. * Koha/Stockrotationrotas.pm: New file. * Koha/Stockrotationstage.pm: New file. * Koha/Stockrotationstages.pm: New file. * t/db_dependent/Stockrotationitems.t: New file. * t/db_dependent/Stockrotationrotas.t: New file. * t/db_dependent/Stockrotationstages.t: New file. * Koha/Item.pm (stockrotationitem, add_to_rota, biblio): New procedures. * Koha/Library.pm (stockrotationstages): New procedure. * t/db_dependent/Items.t: Add tests. * t/db_dependent/Koha/Libraries.t: Add tests. Signed-off-by: Kathleen Milne --- Koha/Item.pm | 49 +++++- Koha/Library.pm | 15 ++ Koha/Stockrotationitem.pm | 305 +++++++++++++++++++++++++++++++++++ Koha/Stockrotationitems.pm | 65 ++++++++ Koha/Stockrotationrota.pm | 135 ++++++++++++++++ Koha/Stockrotationrotas.pm | 64 ++++++++ Koha/Stockrotationstage.pm | 295 +++++++++++++++++++++++++++++++++ Koha/Stockrotationstages.pm | 64 ++++++++ t/db_dependent/Items.t | 65 +++++++- t/db_dependent/Koha/Libraries.t | 25 ++- t/db_dependent/Stockrotationitems.t | 253 +++++++++++++++++++++++++++++ t/db_dependent/Stockrotationrotas.t | 175 ++++++++++++++++++++ t/db_dependent/Stockrotationstages.t | 196 ++++++++++++++++++++++ 13 files changed, 1703 insertions(+), 3 deletions(-) create mode 100644 Koha/Stockrotationitem.pm create mode 100644 Koha/Stockrotationitems.pm create mode 100644 Koha/Stockrotationrota.pm create mode 100644 Koha/Stockrotationrotas.pm create mode 100644 Koha/Stockrotationstage.pm create mode 100644 Koha/Stockrotationstages.pm create mode 100644 t/db_dependent/Stockrotationitems.t create mode 100644 t/db_dependent/Stockrotationrotas.t create mode 100644 t/db_dependent/Stockrotationstages.t diff --git a/Koha/Item.pm b/Koha/Item.pm index bea05f8317..30e799766b 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -30,6 +30,8 @@ use Koha::IssuingRules; use Koha::Item::Transfer; use Koha::Patrons; use Koha::Libraries; +use Koha::Stockrotationitem; +use Koha::Stockrotationrotas; use base qw(Koha::Object); @@ -235,7 +237,52 @@ sub current_holds { return Koha::Holds->_new_from_dbic($hold_rs); } -=head3 type +=head3 stockrotationitem + + my $sritem = Koha::Item->stockrotationitem; + +Returns the stock rotation item associated with the current item. + +=cut + +sub stockrotationitem { + my ( $self ) = @_; + my $rs = $self->_result->stockrotationitem; + return 0 if !$rs; + return Koha::Stockrotationitem->_new_from_dbic( $rs ); +} + +=head3 add_to_rota + + my $item = $item->add_to_rota($rota_id); + +Add this item to the rota identified by $ROTA_ID, which means associating it +with the first stage of that rota. Should this item already be associated +with a rota, then we will move it to the new rota. + +=cut + +sub add_to_rota { + my ( $self, $rota_id ) = @_; + Koha::Stockrotationrotas->find($rota_id)->add_item($self->itemnumber); + return $self; +} + +=head3 biblio + + my $biblio = $item->biblio; + +Returns the biblio associated with the current item. + +=cut + +sub biblio { + my ( $self ) = @_; + my $rs = $self->_result->biblio; + return Koha::Biblio->_new_from_dbic( $rs ); +} + +=head3 _type =cut diff --git a/Koha/Library.pm b/Koha/Library.pm index 151f30e56a..e5e7154ac8 100644 --- a/Koha/Library.pm +++ b/Koha/Library.pm @@ -24,6 +24,7 @@ use Carp; use C4::Context; use Koha::Database; +use Koha::Stockrotationstages; use base qw(Koha::Object); @@ -72,6 +73,20 @@ sub add_to_categories { } } +=head3 stockrotationstages + + my $stages = Koha::Library->stockrotationstages; + +Returns the stockrotation stages associated with this Library. + +=cut + +sub stockrotationstages { + my ( $self ) = @_; + my $rs = $self->_result->stockrotationstages; + return Koha::Stockrotationstages->_new_from_dbic( $rs ); +} + =head3 get_effective_marcorgcode my $marcorgcode = Koha::Libraries->find( $library_id )->get_effective_marcorgcode(); diff --git a/Koha/Stockrotationitem.pm b/Koha/Stockrotationitem.pm new file mode 100644 index 0000000000..0e06862b0d --- /dev/null +++ b/Koha/Stockrotationitem.pm @@ -0,0 +1,305 @@ +package Koha::Stockrotationitem; + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use DateTime; +use DateTime::Duration; +use Koha::Database; +use Koha::DateUtils qw/dt_from_string/; +use Koha::Item::Transfer; +use Koha::Item; +use Koha::Stockrotationstage; + +use base qw(Koha::Object); + +=head1 NAME + +Stockrotationitem - Koha Stockrotationitem Object class + +=head1 SYNOPSIS + +Stockrotationitem class used primarily by stockrotation .pls and the stock +rotation cron script. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 _type + +=cut + +sub _type { + return 'Stockrotationitem'; +} + +=head3 itemnumber + + my $item = Koha::Stockrotationitem->itemnumber; + +Returns the item associated with the current stock rotation item. + +=cut + +sub itemnumber { + my ( $self ) = @_; + my $rs = $self->_result->itemnumber; + return Koha::Item->_new_from_dbic( $rs ); +} + +=head3 stage + + my $stage = Koha::Stockrotationitem->stage; + +Returns the stage associated with the current stock rotation item. + +=cut + +sub stage { + my ( $self ) = @_; + my $rs = $self->_result->stage; + return Koha::Stockrotationstage->_new_from_dbic( $rs ); +} + +sub needs_initiating { + my ( $self ) = @_; + my $completed = $self->itemnumber->_result->branchtransfers->search; + if ( !$completed->count ) { + return 1; + } else { + my $stage_branch = $self->stage->branchcode_id; + my $home_branch = $self->itemnumber->homebranch; + return !( $stage_branch eq $home_branch ); + } +} + +=head3 needs_repatriating + + my $status = $item->needs_repatriating; + +Return 1 if this item is currently not at the library it should be at +according to our stockrotation plan. + +=cut + +# Check following things: +# +# Homebranch == stockrotationstage.branch +# If not, check if Homebranch == stockrotationstage.stageafter.branch +# If so, presumably in transit :=> 0 +# Else, :=> 1 +# +# Holdingbranch == Homebranch +# If not, :=> 1 + +sub needs_repatriating { + my ( $self ) = @_; + my ( $item, $stage ) = ( $self->itemnumber, $self->stage ); + if ( $item->homebranch ne $stage->branchcode_id ) { + # We're either in transit to new branch or we got corrupted. + my $next_stage = $stage->next_sibling; + ( $next_stage && $item->homebranch eq $next_stage->branchcode_id ) + ? return 0 # We seem to be in transit. + : return 1; # We got corrupted, gotta be repatriated! + } + # Check if we are where we should be… + if ( $item->holdingbranch eq $item->homebranch + || $self->itemnumber->get_transfer ) { + return 0; # Yup, all good + } else { + return 1; # Nope, gotta be repatriated + } +} + +=head3 needs_advancing + + my $status = $item->needs_advancing; + +Return 1 if this item is ready to be moved on to the next stage in its rota. + +=cut + +sub needs_advancing { + my ( $self ) = @_; + my $intransfers = $self->itemnumber->get_transfer; + # Check whether we are in transfer + if ( !$intransfers ) { + my $completed = $self->itemnumber->_result->branchtransfers->search( + {}, + { + order_by => { -desc => 'datearrived' } + } + ); + # Do maths on whether we need to be moved on. + if ( $completed->count ) { + my $arrival = dt_from_string( + $completed->next->datearrived, 'iso' + ); + my $duration = DateTime::Duration + ->new( days => $self->stage->duration ); + if ( $arrival + $duration le DateTime->now ) { + return 1; + } else { + return 0; + } + } else { + die "We have no historical branch transfer; this should not have happened!"; + } + } + # Currently in transfer, do not advance. + return 0; +} + +sub initiate { + my ( $self ) = @_; + my $stage_branch = $self->stage->branchcode_id; + my $home_branch = $self->itemnumber->homebranch; + my $holding_branch = $self->itemnumber->holdingbranch; + if ( !( ( $stage_branch eq $home_branch ) + && ( $holding_branch eq $home_branch ) ) ) { + return $self->repatriate("StockrotationInit"); + } else { + $self->itemnumber->homebranch($self->stage->branchcode_id)->store; + return Koha::Item::Transfer->new({ + 'itemnumber' => $self->itemnumber_id, + 'frombranch' => $self->stage->branchcode_id, + 'tobranch' => $self->stage->branchcode_id, + 'datesent' => DateTime->now, + 'datearrived' => DateTime->now, + 'comments' => "StockrotationInit" + })->store; + } +} + +=head3 repatriate + + $sritem = $sritem->repatriate + +Put this item into branch transfer with 'StockrotationCorrection' comment, so +that it may return to it's stage.branch to continue its rota as normal. + +=cut + +sub repatriate { + my ( $self, $msg ) = @_; + # Create the transfer. + my $transfer_stored = Koha::Item::Transfer->new({ + 'itemnumber' => $self->itemnumber_id, + 'frombranch' => $self->itemnumber->holdingbranch, + 'tobranch' => $self->stage->branchcode_id, + 'datesent' => DateTime->now, + 'comments' => $msg || "StockrotationRepatriation", + })->store; + $self->itemnumber->homebranch($self->stage->branchcode_id)->store; + return $transfer_stored; +} + +=head3 advance + + $sritem = $sritem->advance + +Put this item into branch transfer with 'StockrotationAdvance' comment, to +transfer it to the next stage in its rota. + +If this is the last stage in the rota and this rota is cyclical, we return to +the first stage. If it is not cyclical, then we delete this +Stockrotationitem. + +If this item is 'indemand', and advance is invoked, we disable 'indemand' and +advance the item as per usual. + +=cut + +sub advance { + my ( $self ) = @_; + + my $transfer = Koha::Item::Transfer->new({ + 'itemnumber' => $self->itemnumber_id, + 'frombranch' => $self->itemnumber->holdingbranch, + 'datesent' => DateTime->now, + 'comments' => "StockrotationAdvance" + }); + + if ( $self->indemand ) { + $self->indemand(0)->store; # De-activate indemand + $transfer->tobranch($self->stage->branchcode_id); + $transfer->datearrived(DateTime->now); + } else { + # Find and update our stage. + my $current_stage = $self->stage; + my $new_stage; + # Last stage in rota? + if ( !$current_stage->last_sibling ) { + # Special rules: Cyclical rota? + if ( $current_stage->rota->cyclical ) { + # Revert to first stage. + my $xstg = $current_stage->first_sibling; + # Is this the first (as well as last) stage? + if ( $xstg ) { + # ... No, so return to first stage. + $new_stage = $xstg; + } else { + # ... Yes, so we create a dummy transfer (for statistics) + my $transfer_stored = Koha::Item::Transfer->new({ + 'itemnumber' => $self->itemnumber_id, + 'frombranch' => $self->itemnumber->holdingbranch, + 'tobranch' => $self->itemnumber->holdingbranch, + 'datesent' => DateTime->now, + 'datearrived' => DateTime->now, + 'comments' => "StockrotationAdvance" + })->store; + # and return. + return 1; + } + $new_stage = ( $xstg ) ? $xstg : $current_stage; + } else { + # Stockrotationitem no longer needs to exist. + $self->delete; + return 1; + } + } else { + # Just advance. + $new_stage = $self->stage->next_sibling; + } + + # Update our stage. + $self->stage_id($new_stage->stage_id)->store; + # Update our homebranch. + $self->itemnumber->homebranch($self->stage->branchcode_id)->store; + #Update the transfer + $transfer->tobranch($new_stage->branchcode_id); + } + + return $transfer->store; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Stockrotationitems.pm b/Koha/Stockrotationitems.pm new file mode 100644 index 0000000000..06f2a47b62 --- /dev/null +++ b/Koha/Stockrotationitems.pm @@ -0,0 +1,65 @@ +package Koha::Stockrotationitems; + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Stockrotationitem; + +use base qw(Koha::Objects); + +=head1 NAME + +Stockrotationitems - Koha Stockrotationitems Object class + +=head1 SYNOPSIS + +Stockrotationitems class used primarily by stockrotation .pls and the stock +rotation cron script. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 _type + +=cut + +sub _type { + return 'Stockrotationitem'; +} + +sub object_class { + return 'Koha::Stockrotationitem'; +} + + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Stockrotationrota.pm b/Koha/Stockrotationrota.pm new file mode 100644 index 0000000000..42128929d7 --- /dev/null +++ b/Koha/Stockrotationrota.pm @@ -0,0 +1,135 @@ +package Koha::Stockrotationrota; + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Stockrotationstages; +use Koha::Stockrotationitem; +use Koha::Stockrotationitems; + +use base qw(Koha::Object); + +=head1 NAME + +Stockrotationrota - Koha Stockrotationrota Object class + +=head1 SYNOPSIS + +Stockrotationrota class used primarily by stockrotation .pls and the stock +rotation cron script. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 stockrotationstages + + my $stages = Koha::Stockrotationrota->stockrotationstages; + +Returns the stages associated with the current rota. + +=cut + +sub stockrotationstages { + my ( $self ) = @_; + my $rs = $self->_result->stockrotationstages; + return Koha::Stockrotationstages->_new_from_dbic( $rs ); +} + +=head3 add_item + + my $rota = $rota->add_item($itemnumber); + +Add item identified by $ITEMNUMBER to this rota, which means we associate it +with the first stage of this rota. Should the item already be associated with +a rota, move it from that rota to this rota. + +=cut + +sub add_item { + my ( $self, $itemnumber ) = @_; + my $sritem = Koha::Stockrotationitems->find($itemnumber); + my $stages = $self->stockrotationstages; + die "Rota is missing stages." unless ( $stages->count > 0 ); + if ($sritem) { + $sritem->stage_id($stages->next->stage_id)->store; + } else { + $sritem = Koha::Stockrotationitem->new({ + itemnumber_id => $itemnumber, + stage_id => $stages->next->stage_id, + indemand => 0, + })->store; + } + return $self; +} + +=head3 first_stage + + my $stage = $rota->first_stage; + +Return the first stage attached to this rota (the one that has an undefined +`stagebefore`). + +=cut + +sub first_stage { + my ( $self ) = @_; + my $guess = $self->stockrotationstages->next; + my $stage = $guess->first_sibling; + return ( $stage ) ? $stage : $guess; +} + +=head3 items + + my $items = $rota->items; + +Return all items associated with this rota via its stages. + +=cut + +sub stockrotationitems { + my ( $self ) = @_; + my $rs = Koha::Stockrotationitems->search( + { 'stage.rota_id' => $self->rota_id }, { join => [ qw/stage/ ] } + ); + return $rs; +} + +=head3 _type + +=cut + +sub _type { + return 'Stockrotationrota'; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Stockrotationrotas.pm b/Koha/Stockrotationrotas.pm new file mode 100644 index 0000000000..8851bb3d13 --- /dev/null +++ b/Koha/Stockrotationrotas.pm @@ -0,0 +1,64 @@ +package Koha::Stockrotationrotas; + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Stockrotationrota; + +use base qw(Koha::Objects); + +=head1 NAME + +Stockrotationrotas - Koha Stockrotationrotas Object class + +=head1 SYNOPSIS + +Stockrotationrotas class used primarily by stockrotation .pls and the stock +rotation cron script. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 _type + +=cut + +sub _type { + return 'Stockrotationrota'; +} + +sub object_class { + return 'Koha::Stockrotationrota'; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Stockrotationstage.pm b/Koha/Stockrotationstage.pm new file mode 100644 index 0000000000..4752613a58 --- /dev/null +++ b/Koha/Stockrotationstage.pm @@ -0,0 +1,295 @@ +package Koha::Stockrotationstage; + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Library; +use Koha::Stockrotationitems; +use Koha::Stockrotationrota; + +use base qw(Koha::Object); + +=head1 NAME + +Stockrotationstage - Koha Stockrotationstage Object class + +=head1 SYNOPSIS + +Stockrotationstage class used primarily by stockrotation .pls and the stock +rotation cron script. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 _type + +=cut + +sub _type { + return 'Stockrotationstage'; +} + +sub _relation { + my ( $self, $method, $type ) = @_; + return sub { + my $rs = $self->_result->$method; + return 0 if !$rs; + my $namespace = 'Koha::' . $type; + return $namespace->_new_from_dbic( $rs ); + } +} + +=head3 stockrotationitems + + my $stages = Koha::Stockrotationstage->stockrotationitems; + +Returns the items associated with the current stage. + +=cut + +sub stockrotationitems { + my ( $self ) = @_; + return &{$self->_relation(qw/ stockrotationitems Stockrotationitems /)}; +} + +=head3 branchcode + + my $branch = Koha::Stockrotationstage->branchcode; + +Returns the branch associated with the current stage. + +=cut + +sub branchcode { + my ( $self ) = @_; + return &{$self->_relation(qw/ branchcode Library /)}; +} + +=head3 rota + + my $rota = Koha::Stockrotationstage->rota; + +Returns the rota associated with the current stage. + +=cut + +sub rota { + my ( $self ) = @_; + return &{$self->_relation(qw/ rota Stockrotationrota /)}; +} + +=head3 siblings + + my $siblings = $stage->siblings; + +Koha::Object wrapper around DBIx::Class::Ordered. + +=cut + +sub siblings { + my ( $self ) = @_; + return &{$self->_relation(qw/ siblings Stockrotationstages /)}; +} + +=head3 next_siblings + + my $next_siblings = $stage->next_siblings; + +Koha::Object wrapper around DBIx::Class::Ordered. + +=cut + +sub next_siblings { + my ( $self ) = @_; + return &{$self->_relation(qw/ next_siblings Stockrotationstages /)}; +} + +=head3 previous_siblings + + my $previous_siblings = $stage->previous_siblings; + +Koha::Object wrapper around DBIx::Class::Ordered. + +=cut + +sub previous_siblings { + my ( $self ) = @_; + return &{$self->_relation(qw/ previous_siblings Stockrotationstages /)}; +} + +=head3 next_sibling + + my $next = $stage->next_sibling; + +Koha::Object wrapper around DBIx::Class::Ordered. + +=cut + +sub next_sibling { + my ( $self ) = @_; + return &{$self->_relation(qw/ next_sibling Stockrotationstage /)}; +} + +=head3 previous_sibling + + my $previous = $stage->previous_sibling; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub previous_sibling { + my ( $self ) = @_; + return &{$self->_relation(qw/ previous_sibling Stockrotationstage /)}; +} + +=head3 first_sibling + + my $first = $stage->first_sibling; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub first_sibling { + my ( $self ) = @_; + return &{$self->_relation(qw/ first_sibling Stockrotationstage /)}; +} + +=head3 last_sibling + + my $last = $stage->last_sibling; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub last_sibling { + my ( $self ) = @_; + return &{$self->_relation(qw/ last_sibling Stockrotationstage /)}; +} + +=head3 move_previous + + 1|0 = $stage->move_previous; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub move_previous { + my ( $self ) = @_; + return $self->_result->move_previous; +} + +=head3 move_next + + 1|0 = $stage->move_next; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub move_next { + my ( $self ) = @_; + return $self->_result->move_next; +} + +=head3 move_first + + 1|0 = $stage->move_first; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub move_first { + my ( $self ) = @_; + return $self->_result->move_first; +} + +=head3 move_last + + 1|0 = $stage->move_last; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub move_last { + my ( $self ) = @_; + return $self->_result->move_last; +} + +=head3 move_to + + 1|0 = $stage->move_to($position); + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub move_to { + my ( $self, $position ) = @_; + return $self->_result->move_to($position) + if ( $position le $self->rota->stockrotationstages->count ); + return 0; +} + +=head3 move_to_group + + 1|0 = $stage->move_to_group($rota_id, [$position]); + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub move_to_group { + my ( $self, $rota_id, $position ) = @_; + return $self->_result->move_to_group($rota_id, $position); +} + +=head3 delete + + 1|0 = $stage->delete; + +Koha::Object Wrapper around DBIx::Class::Ordered. + +=cut + +sub delete { + my ( $self ) = @_; + return $self->_result->delete; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/Koha/Stockrotationstages.pm b/Koha/Stockrotationstages.pm new file mode 100644 index 0000000000..b1ad81e0c9 --- /dev/null +++ b/Koha/Stockrotationstages.pm @@ -0,0 +1,64 @@ +package Koha::Stockrotationstages; + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use Koha::Stockrotationstage; + +use base qw(Koha::Objects); + +=head1 NAME + +Stockrotationstages - Koha Stockrotationstages Object class + +=head1 SYNOPSIS + +Stockrotationstages class used primarily by stockrotation .pls and the stock +rotation cron script. + +=head1 DESCRIPTION + +Standard Koha::Objects definitions, and additional methods. + +=head1 API + +=head2 Class Methods + +=cut + +=head3 _type + +=cut + +sub _type { + return 'Stockrotationstage'; +} + +sub object_class { + return 'Koha::Stockrotationstage'; +} + +1; + +=head1 AUTHOR + +Alex Sassmannshausen + +=cut diff --git a/t/db_dependent/Items.t b/t/db_dependent/Items.t index 8c85959bb7..f71e649e2a 100755 --- a/t/db_dependent/Items.t +++ b/t/db_dependent/Items.t @@ -30,7 +30,7 @@ use t::lib::TestBuilder; use Koha::MarcSubfieldStructures; use Koha::Caches; -use Test::More tests => 12; +use Test::More tests => 14; use Test::Warn; @@ -758,6 +758,69 @@ subtest 'get_hostitemnumbers_of' => sub { is( @itemnumbers, 0, ); }; +subtest 'Check stockrotationitem relationship' => sub { + plan tests => 1; + + $schema->storage->txn_begin(); + + my $builder = t::lib::TestBuilder->new; + my $item = $builder->build({ source => 'Item' }); + + $builder->build({ + source => 'Stockrotationitem', + value => { itemnumber_id => $item->{itemnumber} } + }); + + my $sritem = Koha::Items->find($item->{itemnumber})->stockrotationitem; + isa_ok( $sritem, 'Koha::Stockrotationitem', "Relationship works and correctly creates Koha::Object." ); + + $schema->storage->txn_rollback; +}; + +subtest 'Check add_to_rota method' => sub { + plan tests => 2; + + $schema->storage->txn_begin(); + + my $builder = t::lib::TestBuilder->new; + my $item = $builder->build({ source => 'Item' }); + my $rota = $builder->build({ source => 'Stockrotationrota' }); + my $srrota = Koha::Stockrotationrotas->find($rota->{rota_id}); + + $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + + my $sritem = Koha::Items->find($item->{itemnumber}); + $sritem->add_to_rota($rota->{rota_id}); + + is( + Koha::Stockrotationitems->find($item->{itemnumber})->stage_id, + $srrota->stockrotationstages->next->stage_id, + "Adding to a rota a new sritem item being assigned to its first stage." + ); + + my $newrota = $builder->build({ source => 'Stockrotationrota' }); + + my $srnewrota = Koha::Stockrotationrotas->find($newrota->{rota_id}); + + $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $newrota->{rota_id} }, + }); + + $sritem->add_to_rota($newrota->{rota_id}); + + is( + Koha::Stockrotationitems->find($item->{itemnumber})->stage_id, + $srnewrota->stockrotationstages->next->stage_id, + "Moving an item results in that sritem being assigned to the new first stage." + ); + + $schema->storage->txn_rollback; +}; + # Helper method to set up a Biblio. sub get_biblio { my ( $frameworkcode ) = @_; diff --git a/t/db_dependent/Koha/Libraries.t b/t/db_dependent/Koha/Libraries.t index 22c704786b..98f98a5a1f 100644 --- a/t/db_dependent/Koha/Libraries.t +++ b/t/db_dependent/Koha/Libraries.t @@ -19,7 +19,7 @@ use Modern::Perl; -use Test::More tests => 10; +use Test::More tests => 12; use Koha::Library; use Koha::Libraries; @@ -88,6 +88,29 @@ is( Koha::Libraries->search->count, $nb_of_libraries + 1, 'Delete should have de $retrieved_category_2->delete; is( Koha::LibraryCategories->search->count, $nb_of_categories + 2, 'Delete should have deleted the library category' ); +# Stockrotation relationship testing + +my $new_library_sr = $builder->build({ source => 'Branch' }); + +$builder->build({ + source => 'Stockrotationstage', + value => { branchcode_id => $new_library_sr->{branchcode} }, +}); +$builder->build({ + source => 'Stockrotationstage', + value => { branchcode_id => $new_library_sr->{branchcode} }, +}); +$builder->build({ + source => 'Stockrotationstage', + value => { branchcode_id => $new_library_sr->{branchcode} }, +}); + +my $srstages = Koha::Libraries->find($new_library_sr->{branchcode}) + ->stockrotationstages; +is( $srstages->count, 3, 'Correctly fetched stockrotationstages associated with this branch'); + +isa_ok( $srstages->next, 'Koha::Stockrotationstage', "Relationship correctly creates Koha::Objects." ); + $schema->storage->txn_rollback; subtest '->get_effective_marcorgcode' => sub { diff --git a/t/db_dependent/Stockrotationitems.t b/t/db_dependent/Stockrotationitems.t new file mode 100644 index 0000000000..11d5cde13d --- /dev/null +++ b/t/db_dependent/Stockrotationitems.t @@ -0,0 +1,253 @@ +#!/usr/bin/perl + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use DateTime; +use Koha::Database; +use Koha::Item::Transfer; +use t::lib::TestBuilder; + +use Test::More tests => 7; + +my $schema = Koha::Database->new->schema; + +use_ok('Koha::Stockrotationitems'); +use_ok('Koha::Stockrotationitem'); + +my $builder = t::lib::TestBuilder->new; + +subtest 'Basic object tests' => sub { + + plan tests => 5; + + $schema->storage->txn_begin; + + my $itm = $builder->build({ source => 'Item' }); + my $stage = $builder->build({ source => 'Stockrotationstage' }); + + my $item = $builder->build({ + source => 'Stockrotationitem', + value => { + itemnumber_id => $itm->{itemnumber}, + stage_id => $stage->{stage_id}, + }, + }); + + my $sritem = Koha::Stockrotationitems->find($item->{itemnumber_id}); + isa_ok( + $sritem, + 'Koha::Stockrotationitem', + "Correctly create and load a stock rotation item." + ); + + # Relationship to rota + isa_ok( $sritem->itemnumber, 'Koha::Item', "Fetched related item." ); + is( $sritem->itemnumber->itemnumber, $itm->{itemnumber}, "Related rota OK." ); + + # Relationship to stage + isa_ok( $sritem->stage, 'Koha::Stockrotationstage', "Fetched related stage." ); + is( $sritem->stage->stage_id, $stage->{stage_id}, "Related stage OK." ); + + + $schema->storage->txn_rollback; +}; + +subtest 'Tests for needs_repatriating' => sub { + + plan tests => 4; + + $schema->storage->txn_begin; + + # Setup a pristine stockrotation context. + my $sritem = $builder->build({ source => 'Stockrotationitem' }); + my $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id); + $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id); + $dbitem->stage->position(1); + + my $dbrota = $dbitem->stage->rota; + my $newstage = $builder->build({ + source => 'Stockrotationstage', + values => { + rota_id => $dbrota->rota_id, + position => 2, + } + }); + + # - homebranch == holdingbranch [0] + is( + $dbitem->needs_repatriating, 0, + "Homebranch == Holdingbranch." + ); + + my $branch = $builder->build({ source => 'Branch' }); + $dbitem->itemnumber->holdingbranch($branch->{branchcode}); + + # - homebranch != holdingbranch [1] + is( + $dbitem->needs_repatriating, 1, + "Homebranch != holdingbranch." + ); + + # Set to incorrect homebranch. + $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id); + $dbitem->itemnumber->homebranch($branch->{branchcode}); + # - homebranch != stockrotationstage.branch & not in transit [1] + is( + $dbitem->needs_repatriating, 1, + "Homebranch != Stockrotationstage.Branchcode_id & not in transit." + ); + + # Set to in transit (by implication). + $dbitem->stage($newstage->{stage_id}); + # - homebranch != stockrotaitonstage.branch & in transit [0] + is( + $dbitem->needs_repatriating, 1, + "homebranch != stockrotaitonstage.branch & in transit." + ); + + $schema->storage->txn_rollback; +}; + +subtest "Tests for repatriate." => sub { + plan tests => 3; + $schema->storage->txn_begin; + my $sritem = $builder->build({ source => 'Stockrotationitem' }); + my $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + $dbitem->stage->position(1); + $dbitem->stage->duration(50); + my $branch = $builder->build({ source => 'Branch' }); + $dbitem->itemnumber->holdingbranch($branch->{branchcode}); + + # Test a straight up repatriate + ok($dbitem->repatriate, "Repatriation done."); + my $intransfer = $dbitem->itemnumber->get_transfer; + is($intransfer->frombranch, $branch->{branchcode}, "Origin correct."); + is($intransfer->tobranch, $dbitem->stage->branchcode_id, "Target Correct."); + + $schema->storage->txn_rollback; +}; + +subtest "Tests for needs_advancing." => sub { + plan tests => 3; + $schema->storage->txn_begin; + + # Setup a pristine stockrotation context. + my $sritem = $builder->build({ source => 'Stockrotationitem' }); + my $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + $dbitem->itemnumber->homebranch($dbitem->stage->branchcode_id); + $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id); + $dbitem->stage->position(1); + $dbitem->stage->duration(50); + + my $dbtransfer = Koha::Item::Transfer->new({ + 'itemnumber' => $dbitem->itemnumber_id, + 'frombranch' => $dbitem->stage->branchcode_id, + 'tobranch' => $dbitem->stage->branchcode_id, + 'datesent' => DateTime->now, + 'datearrived' => undef, + 'comments' => "Test item", + })->store; + + # Test item will not be advanced if in transit. + is($dbitem->needs_advancing, 0, "Not ready to advance: in transfer."); + + # Test item will not be advanced if it has not spent enough time. + $dbtransfer->datearrived(DateTime->now)->store; + is($dbitem->needs_advancing, 0, "Not ready to advance: Not spent enough time."); + + # Test item will be advanced if it has spent enough time. + $dbtransfer->datesent( # Item was sent 100 days ago... + DateTime->now - DateTime::Duration->new( days => 100 ) + )->store; + $dbtransfer->datearrived( # And arrived 75 days ago. + DateTime->now - DateTime::Duration->new( days => 75 ) + )->store; + is($dbitem->needs_advancing, 1, "Ready to be advanced."); + + $schema->storage->txn_rollback; +}; + +subtest "Tests for advance." => sub { + plan tests => 12; + $schema->storage->txn_begin; + + my $sritem = $builder->build({ source => 'Stockrotationitem' }); + my $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + $dbitem->itemnumber->holdingbranch($dbitem->stage->branchcode_id); + my $dbstage = $dbitem->stage; + $dbstage->position(1)->duration(50)->store; # Configure stage. + # Configure item + $dbitem->itemnumber->holdingbranch($dbstage->branchcode_id)->store; + $dbitem->itemnumber->homebranch($dbstage->branchcode_id)->store; + # Sanity check + is($dbitem->stage->stage_id, $dbstage->stage_id, "Stage sanity check."); + + # Test cases of single stage + $dbstage->rota->cyclical(1)->store; # Set Rota to cyclical. + ok($dbitem->advance, "Single stage cyclical advance done."); + ## Refetch dbitem + $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + is($dbitem->stage->stage_id, $dbstage->stage_id, "Single stage cyclical stage OK."); + + # Test with indemand advance + $dbitem->indemand(1)->store; + ok($dbitem->advance, "Indemand item advance done."); + ## Refetch dbitem + $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + is($dbitem->indemand, 0, "Indemand OK."); + is($dbitem->stage->stage_id, $dbstage->stage_id, "Indemand item advance stage OK."); + + # Multi stages + my $srstage = $builder->build({ + source => 'Stockrotationstage', + values => { duration => 50 } + }); + my $dbstage2 = Koha::Stockrotationstages->find($srstage->{stage_id}); + $dbstage2->move_to_group($dbitem->stage->rota_id); + $dbstage2->move_last; + + # Test a straight up advance + ok($dbitem->advance, "Advancement done."); + ## Refetch dbitem + $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + ## Test results + is($dbitem->stage->stage_id, $dbstage2->stage_id, "Stage updated."); + my $intransfer = $dbitem->itemnumber->get_transfer; + is($intransfer->frombranch, $dbstage->branchcode_id, "Origin correct."); + is($intransfer->tobranch, $dbstage2->branchcode_id, "Target Correct."); + + $dbstage->rota->cyclical(0)->store; # Set Rota to non-cyclical. + + # Arrive at new branch + $intransfer->datearrived(DateTime->now)->store; + $dbitem->itemnumber->holdingbranch($srstage->{branchcode_id})->store; + $dbitem->itemnumber->homebranch($srstage->{branchcode_id})->store; + + # Advance again, Remove from rota. + ok($dbitem->advance, "Non-cyclical advance."); + ## Refetch dbitem + $dbitem = Koha::Stockrotationitems->find($sritem->{itemnumber_id}); + is($dbitem, undef, "Stockrotationitem has been removed."); + + $schema->storage->txn_rollback; +}; + +1; diff --git a/t/db_dependent/Stockrotationrotas.t b/t/db_dependent/Stockrotationrotas.t new file mode 100644 index 0000000000..24dcaebc06 --- /dev/null +++ b/t/db_dependent/Stockrotationrotas.t @@ -0,0 +1,175 @@ +#!/usr/bin/perl + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use t::lib::TestBuilder; + +use Test::More tests => 5; + +my $schema = Koha::Database->new->schema; + +use_ok('Koha::Stockrotationrotas'); +use_ok('Koha::Stockrotationrota'); + +subtest 'Basic object tests' => sub { + + plan tests => 5; + + $schema->storage->txn_begin; + + my $builder = t::lib::TestBuilder->new; + + my $rota = $builder->build({ source => 'Stockrotationrota' }); + + my $srrota = Koha::Stockrotationrotas->find($rota->{rota_id}); + isa_ok( + $srrota, + 'Koha::Stockrotationrota', + "Correctly create and load a stock rotation rota." + ); + + $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + + my $srstages = $srrota->stockrotationstages; + is( $srstages->count, 3, 'Correctly fetched stockrotationstages associated with this rota'); + + isa_ok( $srstages->next, 'Koha::Stockrotationstage', "Relationship correctly creates Koha::Objects." ); + + #### Test add_item + + my $item = $builder->build({ source => 'Item' }); + + $srrota->add_item($item->{itemnumber}); + + is( + Koha::Stockrotationitems->find($item->{itemnumber})->stage_id, + $srrota->stockrotationstages->next->stage_id, + "Adding an item results in a new sritem item being assigned to the first stage." + ); + + my $newrota = $builder->build({ source => 'Stockrotationrota' }); + + my $srnewrota = Koha::Stockrotationrotas->find($newrota->{rota_id}); + + $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $newrota->{rota_id} }, + }); + + $srnewrota->add_item($item->{itemnumber}); + + is( + Koha::Stockrotationitems->find($item->{itemnumber})->stage_id, + $srnewrota->stockrotationstages->next->stage_id, + "Moving an item results in that sritem being assigned to the new first stage." + ); + + $schema->storage->txn_rollback; +}; + +subtest '->first_stage test' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + + my $builder = t::lib::TestBuilder->new; + + my $rota = $builder->build({ source => 'Stockrotationrota' }); + + my $stage1 = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + my $stage2 = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + my $stage3 = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + + my $srrota = Koha::Stockrotationrotas->find($rota->{rota_id}); + my $srstage2 = Koha::Stockrotationstages->find($stage2->{stage_id}); + my $firststage = $srstage2->first_sibling || $srstage2; + + is( $srrota->first_stage->stage_id, $firststage->stage_id, "First stage works" ); + + $srstage2->move_first; + + is( Koha::Stockrotationrotas->find($rota->{rota_id})->first_stage->stage_id, $stage2->{stage_id}, "Stage re-organized" ); + + $schema->storage->txn_rollback; +}; + +subtest '->items test' => sub { + plan tests => 1; + + $schema->storage->txn_begin; + + my $builder = t::lib::TestBuilder->new; + + my $rota = $builder->build({ source => 'Stockrotationrota' }); + + my $stage1 = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + my $stage2 = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + my $stage3 = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id} }, + }); + + map { $builder->build({ + source => 'Stockrotationitem', + value => { stage_id => $_ }, + }) } ( + $stage1->{stage_id}, $stage1->{stage_id}, + $stage2->{stage_id}, $stage2->{stage_id}, + $stage3->{stage_id}, $stage3->{stage_id}, + ); + + my $srrota = Koha::Stockrotationrotas->find($rota->{rota_id}); + + is( + $srrota->stockrotationitems->count, + 6, "Correct number of items" + ); + + $schema->storage->txn_rollback; +}; + +1; diff --git a/t/db_dependent/Stockrotationstages.t b/t/db_dependent/Stockrotationstages.t new file mode 100644 index 0000000000..edb2e20253 --- /dev/null +++ b/t/db_dependent/Stockrotationstages.t @@ -0,0 +1,196 @@ +#!/usr/bin/perl + +# Copyright PTFS Europe 2016 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Koha::Database; +use t::lib::TestBuilder; + +use Test::More tests => 5; + +my $schema = Koha::Database->new->schema; + +use_ok('Koha::Stockrotationstages'); +use_ok('Koha::Stockrotationstage'); + +my $builder = t::lib::TestBuilder->new; + +subtest 'Basic object tests' => sub { + plan tests => 5; + + $schema->storage->txn_begin; + + my $library = $builder->build({ source => 'Branch' }); + my $rota = $builder->build({ source => 'Stockrotationrota' }); + my $stage = $builder->build({ + source => 'Stockrotationstage', + value => { + branchcode_id => $library->{branchcode}, + rota_id => $rota->{rota_id}, + }, + }); + + my $srstage = Koha::Stockrotationstages->find($stage->{stage_id}); + isa_ok( + $srstage, + 'Koha::Stockrotationstage', + "Correctly create and load a stock rotation stage." + ); + + # Relationship to library + isa_ok( $srstage->branchcode, 'Koha::Library', "Fetched related branch." ); + is( $srstage->branchcode->branchcode, $library->{branchcode}, "Related branch OK." ); + + # Relationship to rota + isa_ok( $srstage->rota, 'Koha::Stockrotationrota', "Fetched related rota." ); + is( $srstage->rota->rota_id, $rota->{rota_id}, "Related rota OK." ); + + $schema->storage->txn_rollback; +}; + +subtest 'DBIx::Class::Ordered tests' => sub { + plan tests => 33; + + $schema->storage->txn_begin; + + my $library = $builder->build({ source => 'Branch' }); + my $rota = $builder->build({ source => 'Stockrotationrota' }); + my $stagefirst = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id}, position => 1 } + }); + my $stageprevious = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id}, position => 2 } + }); + my $stage = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id}, position => 3 }, + }); + my $stagenext = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id}, position => 4 } + }); + my $stagelast = $builder->build({ + source => 'Stockrotationstage', + value => { rota_id => $rota->{rota_id}, position => 5 } + }); + + my $srstage = Koha::Stockrotationstages->find($stage->{stage_id}); + + is($srstage->siblings->count, 4, "Siblings works."); + is($srstage->previous_siblings->count, 2, "Previous Siblings works."); + is($srstage->next_siblings->count, 2, "Next Siblings works."); + + my $map = { + first_sibling => $stagefirst, + previous_sibling => $stageprevious, + next_sibling => $stagenext, + last_sibling => $stagelast, + }; + # Test plain relations: + while ( my ( $srxsr, $check ) = each %{$map} ) { + my $sr = $srstage->$srxsr; + isa_ok($sr, 'Koha::Stockrotationstage', "Fetched using '$srxsr'."); + is($sr->stage_id, $check->{stage_id}, "'$srxsr' data is correct."); + }; + + # Test mutators + ## Move Previous + ok($srstage->move_previous, "Previous."); + is($srstage->previous_sibling->stage_id, $stagefirst->{stage_id}, "Previous, correct previous."); + is($srstage->next_sibling->stage_id, $stageprevious->{stage_id}, "Previous, correct next."); + ## Move Next + ok($srstage->move_next, "Back to middle."); + is($srstage->previous_sibling->stage_id, $stageprevious->{stage_id}, "Middle, correct previous."); + is($srstage->next_sibling->stage_id, $stagenext->{stage_id}, "Middle, correct next."); + ## Move First + ok($srstage->move_first, "First."); + is($srstage->previous_sibling, 0, "First, correct previous."); + is($srstage->next_sibling->stage_id, $stagefirst->{stage_id}, "First, correct next."); + ## Move Last + ok($srstage->move_last, "Last."); + is($srstage->previous_sibling->stage_id, $stagelast->{stage_id}, "Last, correct previous."); + is($srstage->next_sibling, 0, "Last, correct next."); + ## Move To + + ### Out of range moves. + is( + $srstage->move_to($srstage->siblings->count + 2), + 0, "Move above count of stages." + ); + is($srstage->move_to(0), 0, "Move to 0th position."); + is($srstage->move_to(-1), 0, "Move to negative position."); + + ### Move To + ok($srstage->move_to(3), "Move."); + is($srstage->previous_sibling->stage_id, $stageprevious->{stage_id}, "Move, correct previous."); + is($srstage->next_sibling->stage_id, $stagenext->{stage_id}, "Move, correct next."); + + # Group manipulation + my $newrota = $builder->build({ source => 'Stockrotationrota' }); + ok($srstage->move_to_group($newrota->{rota_id}), "Move to Group."); + is(Koha::Stockrotationstages->find($srstage->stage_id)->rota_id, $newrota->{rota_id}, "Moved correctly."); + + # Delete in ordered context + ok($srstage->delete, "Deleted OK."); + is( + Koha::Stockrotationstages->find($stageprevious)->next_sibling->stage_id, + $stagenext->{stage_id}, + "Delete, correctly re-ordered." + ); + + $schema->storage->txn_rollback; +}; + +subtest 'Relationship to stockrotationitems' => sub { + plan tests => 2; + + $schema->storage->txn_begin; + my $stage = $builder->build({ source => 'Stockrotationstage' }); + + $builder->build({ + source => 'Stockrotationitem', + value => { stage_id => $stage->{stage_id} }, + }); + $builder->build({ + source => 'Stockrotationitem', + value => { stage_id => $stage->{stage_id} }, + }); + $builder->build({ + source => 'Stockrotationitem', + value => { stage_id => $stage->{stage_id} }, + }); + + my $srstage = Koha::Stockrotationstages->find($stage->{stage_id}); + my $sritems = $srstage->stockrotationitems; + is( + $sritems->count, 3, + 'Correctly fetched stockrotationitems associated with this stage' + ); + + isa_ok( + $sritems->next, 'Koha::Stockrotationitem', + "Relationship correctly creates Koha::Objects." + ); + + $schema->storage->txn_rollback; +}; + +1; -- 2.13.4