From 2b1a0e9d0d163bd75f9a989ee6016a2fb7f3a546 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Tue, 10 May 2022 10:29:27 +0200 Subject: [PATCH] Bug 30650: Add some useful modules and tests Sponsored-by: Association KohaLa - https://koha-fr.org/ Signed-off-by: Koha Team University Lyon 3 Signed-off-by: Katrin Fischer Signed-off-by: Tomas Cohen Arazi --- Koha/CurbsidePickup.pm | 173 +++++++++++++++++-- Koha/CurbsidePickupIssue.pm | 20 +-- Koha/CurbsidePickupIssues.pm | 26 +-- Koha/CurbsidePickupOpeningSlot.pm | 22 +-- Koha/CurbsidePickupOpeningSlots.pm | 26 +-- Koha/CurbsidePickupPolicies.pm | 26 +-- Koha/CurbsidePickupPolicy.pm | 73 ++++++-- Koha/CurbsidePickups.pm | 77 +++++++-- Koha/Exceptions/CurbsidePickup.pm | 46 +++++ t/db_dependent/Koha/CurbsidePickups.t | 236 ++++++++++++++++++++++++++ 10 files changed, 639 insertions(+), 86 deletions(-) create mode 100644 Koha/Exceptions/CurbsidePickup.pm create mode 100755 t/db_dependent/Koha/CurbsidePickups.t diff --git a/Koha/CurbsidePickup.pm b/Koha/CurbsidePickup.pm index f43f1c5be9..1e47f0413e 100644 --- a/Koha/CurbsidePickup.pm +++ b/Koha/CurbsidePickup.pm @@ -2,18 +2,18 @@ package Koha::CurbsidePickup; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; @@ -23,9 +23,12 @@ use Koha::Database; use base qw(Koha::Object); +use C4::Circulation qw( CanBookBeIssued AddIssue ); +use Koha::DateUtils qw( dt_from_string ); use Koha::Patron; use Koha::Library; use Koha::CurbsidePickupIssues; +use Koha::Exceptions::CurbsidePickup; =head1 NAME @@ -35,6 +38,45 @@ Koha::CurbsidePickup - Koha Curbside Pickup Object class =head2 Class methods +=cut + +=head3 new + +=cut + +sub new { + my ( $self, $params ) = @_; + + my $existing_curbside_pickups = Koha::CurbsidePickups->search( + { + branchcode => $params->{branchcode}, + borrowernumber => $params->{borrowernumber}, + delivered_datetime => undef, + scheduled_pickup_datetime => { '>' => \'DATE(NOW())' }, + } + ); + Koha::Exceptions::CurbsidePickup::TooManyPickups->throw( + branchcode => $params->{branchcode}, + borrowernumber => $params->{borrowernumber} + ) if $existing_curbside_pickups->count; + + my $policy = + Koha::CurbsidePickupPolicies->find( { branchcode => $params->{branchcode} } ); + my $is_valid = + $policy->is_valid_pickup_datetime( $params->{scheduled_pickup_datetime} ); + unless ($is_valid) { + my $error = @{ $is_valid->messages }[0]->message; + Koha::Exceptions::CurbsidePickup::NoMatchingSlots->throw + if $error eq 'no_matching_slots'; + Koha::Exceptions::CurbsidePickup::NoMorePickupsAvailable->throw + if $error eq 'no_more_available'; + Koha::Exceptions->throw( + "Error message must raise the appropriate exception"); + } + + return $self->SUPER::new($params); +} + =head3 checkouts Return the checkouts linked to this pickup @@ -91,6 +133,117 @@ sub library { return Koha::Library->_new_from_dbic( $rs ); } +=head3 mark_as_staged + +Mark the pickup as staged + +=cut + +sub mark_as_staged { + my ( $self ) = @_; + my $staged_by = C4::Context->userenv ? C4::Context->userenv->{number} : undef; + $self->set( + { + staged_datetime => dt_from_string(), + staged_by => $staged_by, + arrival_datetime => undef, + } + )->store; +} + +=head3 mark_as_unstaged + +Mark the pickup as unstaged + +=cut + +sub mark_as_unstaged { + my ( $self ) = @_; + + $self->set( + { + staged_datetime => undef, + staged_by => undef, + arrival_datetime => undef, + } + )->store; +} + +=head3 mark_patron_has_arrived + +Set the arrival time of the patron + +=cut + +sub mark_patron_has_arrived { + my ( $self ) = @_; + $self->set( + { + arrival_datetime => dt_from_string(), + } + )->store; +} + +=head3 mark_as_delivered + +Mark the pickup as delivered. The waiting holds will be filled. + +=cut + +sub mark_as_delivered { + my ( $self ) = @_; + my $patron = $self->patron; + my $holds = $patron->holds; + my $branchcode = C4::Context->userenv ? C4::Context->userenv->{branch} : undef; + foreach my $hold ( $holds->as_list ) { + if ( $hold->found eq 'W' && $branchcode && $hold->branchcode eq $branchcode ) { + my ( $issuingimpossible, $needsconfirmation ) = + C4::Circulation::CanBookBeIssued( $patron, $hold->item->barcode ); + + unless ( keys %$issuingimpossible ) { + my $issue = + C4::Circulation::AddIssue( $patron->unblessed, $hold->item->barcode ); + if ($issue) { + Koha::CurbsidePickupIssue->new( + { + curbside_pickup_id => $self->id, + issue_id => $issue->id, + reserve_id => $hold->id, + } + )->store(); + } + else { + Koha::Exceptions->throw(sprintf("Cannot checkout hold %s for patron %s: %s", $patron->id, $hold->id, join(", ", keys %$issuingimpossible))); + } + } + } + } + + my $delivered_by = C4::Context->userenv ? C4::Context->userenv->{number} : undef; + $self->arrival_datetime(dt_from_string) unless $self->arrival_datetime; + $self->set( + { + delivered_datetime => dt_from_string(), + delivered_by => $delivered_by, + } + )->store; +} + +=head3 status + +Return the status of the pickup, can be 'to-be-staged', 'staged-and-ready', 'patron-is-outside' or 'delivered'. + +=cut + +sub status { + my ($self) = @_; + return + !defined $self->staged_datetime ? 'to-be-staged' + : !defined $self->arrival_datetime ? 'staged-and-ready' + : !defined $self->delivered_datetime ? 'patron-is-outside' + : 'delivered'; +} + =head2 Internal methods =head3 _type diff --git a/Koha/CurbsidePickupIssue.pm b/Koha/CurbsidePickupIssue.pm index 55864c1367..1821063bc5 100644 --- a/Koha/CurbsidePickupIssue.pm +++ b/Koha/CurbsidePickupIssue.pm @@ -2,18 +2,18 @@ package Koha::CurbsidePickupIssue; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; diff --git a/Koha/CurbsidePickupIssues.pm b/Koha/CurbsidePickupIssues.pm index 590c177041..e886e181dc 100644 --- a/Koha/CurbsidePickupIssues.pm +++ b/Koha/CurbsidePickupIssues.pm @@ -2,18 +2,18 @@ package Koha::CurbsidePickupIssues; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; @@ -35,7 +35,7 @@ Koha::CurbsidePickupIssues - Koha Curbside Pickup Issues Object set class =cut -=head3 type +=head3 _type =cut @@ -43,6 +43,10 @@ sub _type { return 'CurbsidePickupIssue'; } +=head3 object_class + +=cut + sub object_class { return 'Koha::CurbsidePickupIssue'; } diff --git a/Koha/CurbsidePickupOpeningSlot.pm b/Koha/CurbsidePickupOpeningSlot.pm index 9e42e3bd6c..d65c5c20cc 100644 --- a/Koha/CurbsidePickupOpeningSlot.pm +++ b/Koha/CurbsidePickupOpeningSlot.pm @@ -2,18 +2,18 @@ package Koha::CurbsidePickupOpeningSlot; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; @@ -31,6 +31,8 @@ CurbsidePickupOpeningSlot - Koha Curbside Pickup Slot Object class =head2 Class methods +=cut + =head2 Internal methods =head3 _type diff --git a/Koha/CurbsidePickupOpeningSlots.pm b/Koha/CurbsidePickupOpeningSlots.pm index 41aec26f78..c40ed94769 100644 --- a/Koha/CurbsidePickupOpeningSlots.pm +++ b/Koha/CurbsidePickupOpeningSlots.pm @@ -2,18 +2,18 @@ package Koha::CurbsidePickupOpeningSlots; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; @@ -35,7 +35,7 @@ Koha::CurbsidePickupOpeningSlots - Koha Curbside Pickup Opening Slots Object set =cut -=head3 type +=head3 _type =cut @@ -43,6 +43,10 @@ sub _type { return 'CurbsidePickupOpeningSlot'; } +=head3 object_class + +=cut + sub object_class { return 'Koha::CurbsidePickupOpeningSlot'; } diff --git a/Koha/CurbsidePickupPolicies.pm b/Koha/CurbsidePickupPolicies.pm index 97d9bbf519..4399e8a28c 100644 --- a/Koha/CurbsidePickupPolicies.pm +++ b/Koha/CurbsidePickupPolicies.pm @@ -2,18 +2,18 @@ package Koha::CurbsidePickupPolicies; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; @@ -35,7 +35,7 @@ Koha::CurbsidePickupPolicies - Koha Curbside Pickup Policies Object set class =cut -=head3 type +=head3 _type =cut @@ -43,6 +43,10 @@ sub _type { return 'CurbsidePickupPolicy'; } +=head3 object_class + +=cut + sub object_class { return 'Koha::CurbsidePickupPolicy'; } diff --git a/Koha/CurbsidePickupPolicy.pm b/Koha/CurbsidePickupPolicy.pm index c974dc406a..118e178f49 100644 --- a/Koha/CurbsidePickupPolicy.pm +++ b/Koha/CurbsidePickupPolicy.pm @@ -2,27 +2,28 @@ package Koha::CurbsidePickupPolicy; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; -use Carp; - use Koha::Database; use Koha::Library; use Koha::CurbsidePickupOpeningSlots; +use Koha::Result::Boolean; +use Koha::Exceptions::CurbsidePickup; + use base qw(Koha::Object); =head1 NAME @@ -72,6 +73,54 @@ sub add_opening_slot { )->store; } +=head3 is_valid_pickup_datetime + +=cut + +sub is_valid_pickup_datetime { + my ( $self, $datetime ) = @_; + + my $opening_slots = + $self->opening_slots->search( { day => $datetime->dow % 7 } ); + my $matching_slot; + while ( my $opening_slot = $opening_slots->next ) { + my $start = $datetime->clone->set_hour( $opening_slot->start_hour ) + ->set_minute( $opening_slot->start_minute ); + my $end = $datetime->clone->set_hour( $opening_slot->end_hour ) + ->set_minute( $opening_slot->start_minute ); + my $keep_going = 1; + my $slot_start = $start->clone; + my $slot_end = $slot_start->clone->add(minutes => $self->pickup_interval); + while ($slot_end <= $end) { + if ( $slot_start == $datetime ) { + $matching_slot = $slot_start; + last; + } + $slot_start->add( minutes => $self->pickup_interval); + $slot_end->add( minutes => $self->pickup_interval); + } + } + + return Koha::Result::Boolean->new(0) + ->add_message( { message => 'no_matching_slots' } ) + unless $matching_slot; + + my $dtf = Koha::Database->new->schema->storage->datetime_parser; + # Check too many users for this slot + my $existing_pickups = Koha::CurbsidePickups->search( + { + branchcode => $self->branchcode, + scheduled_pickup_datetime => $dtf->format_datetime($matching_slot), + } + ); + + return Koha::Result::Boolean->new(0) + ->add_message( { message => 'no_more_available' } ) + if $existing_pickups->count >= $self->patrons_per_interval; + + return 1; +} + =head2 Internal methods =head3 _type diff --git a/Koha/CurbsidePickups.pm b/Koha/CurbsidePickups.pm index 29f9a050f5..b30b003b3c 100644 --- a/Koha/CurbsidePickups.pm +++ b/Koha/CurbsidePickups.pm @@ -2,18 +2,18 @@ package Koha::CurbsidePickups; # 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 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. +# 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. +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . use Modern::Perl; @@ -35,7 +35,58 @@ Koha::CurbsidePickups - Koha Curbside Pickup Object set class =cut -=head3 type +=head3 filter_by_to_be_staged + +Filter by pickups that have not been staged yet + +=cut + +sub filter_by_to_be_staged { + my ($self) = @_; + return $self->search( { staged_datetime => undef } ); +} + +=head3 filter_by_staged_and_ready + +Filter by pickups that have been staged and are ready + +=cut + +sub filter_by_staged_and_ready { + my ($self) = @_; + return $self->search( + { staged_datetime => { -not => undef }, arrival_datetime => undef } ); +} + +=head3 filter_by_patron_outside + +Filter by pickups with patrons waiting outside + +=cut + +sub filter_by_patron_outside { + my ($self) = @_; + return $self->search( + { arrival_datetime => { -not => undef }, delivered_datetime => undef } + ); +} + +=head3 filter_by_delivered + +Filter by pickups that have been delivered already + +=cut + +sub filter_by_delivered { + my ($self) = @_; + return $self->search( { delivered_datetime => { -not => undef } } ); +} + +=head2 Internal Methods + +=cut + +=head3 _type =cut @@ -43,6 +94,10 @@ sub _type { return 'CurbsidePickup'; } +=head3 object_class + +=cut + sub object_class { return 'Koha::CurbsidePickup'; } diff --git a/Koha/Exceptions/CurbsidePickup.pm b/Koha/Exceptions/CurbsidePickup.pm new file mode 100644 index 0000000000..1f25830b49 --- /dev/null +++ b/Koha/Exceptions/CurbsidePickup.pm @@ -0,0 +1,46 @@ +package Koha::Exceptions::CurbsidePickup; + +# 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, see . + +use Modern::Perl; + +use Koha::Exception; + +use Exception::Class ( + + 'Koha::Exceptions::CurbsidePickup' => { + isa => 'Koha::Exception', + }, + 'Koha::Exceptions::CurbsidePickup::NotEnabled' => { + isa => 'Koha::Exceptions::CurbsidePickup', + description => 'Curbside pickups are not enable for this library', + }, + 'Koha::Exceptions::CurbsidePickup::TooManyPickups' => { + isa => 'Koha::Exceptions::CurbsidePickup', + description => 'Patron already has a scheduled pickup for this library', + fields => [ 'branchcode', 'borrowernumber' ], + }, + 'Koha::Exceptions::CurbsidePickup::NoMatchingSlots' => { + isa => 'Koha::Exceptions::CurbsidePickup', + description => 'Cannot create a pickup with this pickup datetime', + }, + 'Koha::Exceptions::CurbsidePickup::NoMorePickupsAvailable' => { + isa => 'Koha::Exceptions::CurbsidePickup', + description => 'No more pickups available for this slot', + }, +); + +1; diff --git a/t/db_dependent/Koha/CurbsidePickups.t b/t/db_dependent/Koha/CurbsidePickups.t new file mode 100755 index 0000000000..b931b5e7e1 --- /dev/null +++ b/t/db_dependent/Koha/CurbsidePickups.t @@ -0,0 +1,236 @@ +#!/usr/bin/perl + +# 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, see . + +use Modern::Perl; + +use Test::More tests => 3; +use Test::Exception; + +use Koha::City; +use Koha::CurbsidePickups; +use Koha::CurbsidePickupPolicies; +use Koha::Database; +use Koha::DateUtils qw( dt_from_string ); + +use t::lib::TestBuilder; +use t::lib::Dates; +use t::lib::Mocks; + +my $schema = Koha::Database->new->schema; +$schema->storage->txn_begin; + +my $builder = t::lib::TestBuilder->new; +my $library = $builder->build_object( { class => 'Koha::Libraries' } ); +my $library_disabled = $builder->build_object( { class => 'Koha::Libraries' } ); +my $logged_in_patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { branchcode => $library->branchcode } + } +); +t::lib::Mocks::mock_userenv( { patron => $logged_in_patron } ); +my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { branchcode => $library->branchcode } + } +); + +my $policy = Koha::CurbsidePickupPolicy->new( + { + branchcode => $library->branchcode, + enabled => 1, + pickup_interval => 30, + patrons_per_interval => 2, + patron_scheduled_pickup => 1 + } +)->store; +my $policy_disabled = Koha::CurbsidePickupPolicy->new( + { + branchcode => $library_disabled->branchcode, + enabled => 0, + pickup_interval => 30, + patrons_per_interval => 2, + patron_scheduled_pickup => 1 + } +)->store; + +# Open Mondays from 12 to 18 +$policy->add_opening_slot('1-12:00-18:00'); + +my $today = dt_from_string; + +subtest 'Create a pickup' => sub { + plan tests => 5; + + # Day and datetime are ok + my $next_monday = + $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 ); + my $schedule_dt = + $next_monday->set_hour(15)->set_minute(00)->set_second(00); + my $cp = Koha::CurbsidePickup->new( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + scheduled_pickup_datetime => $schedule_dt, + notes => 'just a note' + } + )->store; + is( $cp->status, 'to-be-staged' ); + + throws_ok { + Koha::CurbsidePickup->new( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + scheduled_pickup_datetime => $schedule_dt, + notes => 'just a note' + } + )->store + } + 'Koha::Exceptions::CurbsidePickup::TooManyPickups', + 'Cannot create 2 pickups for the same patron'; + + $cp->delete; + + # Day is not ok + my $next_tuesday = + $today->clone->add( days => ( 2 - $today->day_of_week ) % 7 ); + $schedule_dt = $next_tuesday->set_hour(15)->set_minute(00)->set_second(00); + throws_ok { + Koha::CurbsidePickup->new( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + scheduled_pickup_datetime => $schedule_dt, + notes => 'just a note' + } + )->store + } + 'Koha::Exceptions::CurbsidePickup::NoMatchingSlots', + 'Cannot create a pickup on a day without opening slots defined'; + + # Day ok but datetime not ok + $schedule_dt = $next_monday->set_hour(19)->set_minute(00)->set_second(00); + throws_ok { + Koha::CurbsidePickup->new( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + scheduled_pickup_datetime => $schedule_dt, + notes => 'just a note' + } + )->store + } + 'Koha::Exceptions::CurbsidePickup::NoMatchingSlots', + 'Cannot create a pickup on a time without opening slots defined'; + + # Day ok, datetime inside the opening slot, but wrong (15:15 for instance) + $schedule_dt = $next_monday->set_hour(15)->set_minute(15)->set_second(00); + throws_ok { + Koha::CurbsidePickup->new( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + scheduled_pickup_datetime => $schedule_dt, + notes => 'just a note' + } + )->store + } + 'Koha::Exceptions::CurbsidePickup::NoMatchingSlots', +'Cannot create a pickup on a time that is not matching the start of an interval'; + +}; + +subtest 'workflow' => sub { + plan tests => 9; + + my $pickups = + Koha::CurbsidePickups->search( { branchcode => $library->branchcode } ); + + my $next_monday = + $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 ); + my $schedule_dt = + $next_monday->set_hour(15)->set_minute(00)->set_second(00); + my $cp = Koha::CurbsidePickup->new( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + scheduled_pickup_datetime => $schedule_dt, + notes => 'just a note' + } + )->store; + is( $cp->status, 'to-be-staged' ); + is( $pickups->filter_by_to_be_staged->count, 1 ); + + $cp->mark_as_staged; + is( $cp->status, 'staged-and-ready' ); + is( $pickups->filter_by_staged_and_ready->count, 1 ); + + $cp->mark_as_unstaged; + is( $cp->status, 'to-be-staged' ); + + $cp->mark_as_staged; + + $cp->mark_patron_has_arrived; + is( $cp->status, 'patron-is-outside' ); + is( $pickups->filter_by_patron_outside->count, 1 ); + + $cp->mark_as_delivered; + is( $cp->status, 'delivered' ); + is( $pickups->filter_by_delivered->count, 1 ); +}; + +subtest 'mark_as_delivered' => sub { + plan tests => 3; + + my $item = $builder->build_sample_item({ library => $library->branchcode }); + my $reserve_id = C4::Reserves::AddReserve( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + biblionumber => $item->biblionumber, + priority => 1, + itemnumber => $item->itemnumber, + } + ); + my $hold = Koha::Holds->find($reserve_id); + $hold->set_waiting; + + my $next_monday = + $today->clone->add( days => ( 1 - $today->day_of_week ) % 7 ); + my $schedule_dt = + $next_monday->set_hour(15)->set_minute(00)->set_second(00); + my $cp = Koha::CurbsidePickup->new( + { + branchcode => $library->branchcode, + borrowernumber => $patron->borrowernumber, + scheduled_pickup_datetime => $schedule_dt, + notes => 'just a note' + } + )->store; + + $cp->mark_as_delivered; + $cp->discard_changes; + is( t::lib::Dates::compare( $cp->arrival_datetime, dt_from_string), 0, 'Arrival time has been set to now' ); + + is( $hold->get_from_storage, undef, 'Hold has been filled' ); + my $checkout = Koha::Checkouts->find({ itemnumber => $item->itemnumber }); + is( $checkout->borrowernumber, $patron->borrowernumber, 'Item has correctly been checked out' ) +}; + +$schema->storage->txn_rollback; -- 2.39.5