From 7ea9983a0da95056c230319f1d64076e00307484 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Thu, 21 Apr 2022 11:19:58 -0300 Subject: [PATCH] Bug 22456: Add Koha::Hold::CancellationRequest(s) class(es) This patch adds the Koha::Object-derived classes for cancellation requests. Tests are added for the overloaded ->store method. To test: 1. Apply this patch 2. Run: $ kshell k$ prove t/db_dependent/Koha/Hold/CancellationRequest.t => SUCCESS: Tests pass! 3. Sign off :-D --- Koha/Hold/CancellationRequest.pm | 119 ++++++++ Koha/Hold/CancellationRequests.pm | 117 ++++++++ .../Koha/Hold/CancellationRequest.t | 145 ++++++++++ .../Koha/Hold/CancellationRequests.t | 273 ++++++++++++++++++ 4 files changed, 654 insertions(+) create mode 100644 Koha/Hold/CancellationRequest.pm create mode 100644 Koha/Hold/CancellationRequests.pm create mode 100755 t/db_dependent/Koha/Hold/CancellationRequest.t create mode 100755 t/db_dependent/Koha/Hold/CancellationRequests.t diff --git a/Koha/Hold/CancellationRequest.pm b/Koha/Hold/CancellationRequest.pm new file mode 100644 index 0000000000..1d30b526c3 --- /dev/null +++ b/Koha/Hold/CancellationRequest.pm @@ -0,0 +1,119 @@ +package Koha::Hold::CancellationRequest; + +# 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::Database; +use Koha::Exceptions; + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Hold::CancellationRequest - Koha hold cancellation request Object class + +=head1 API + +=head2 Class methods + +=head3 store + + $request->store; + +Overloaded I method that performs some checks. + +=cut + +sub store { + my ($self) = @_; + + if ( !$self->in_storage ) { # new request + $self->creation_date( \'NOW()' ) + unless $self->creation_date; + } + + return $self->SUPER::store; +} + +=head3 accept + + $request->accept( $resolver_id ); + +Mark the cancellation request as accepted. + +=cut + +sub accept { + my ($self, $resolver_id) = @_; + + Koha::Exceptions::InvalidStatus->throw( invalid_status => $self->status ) + unless $self->status eq 'requested'; + + $resolver_id //= C4::Context->userenv ? C4::Context->userenv->{number} : undef; + + return $self->set( + { + resolution_date => \'NOW()', + resolver_id => $resolver_id, + status => 'accepted', + } + )->store; +} + +=head3 reject + + $request->reject( $resolver_id ); + +Mark the cancellation request as rejected. + +=cut + +sub reject { + my ($self, $resolver_id) = @_; + + Koha::Exceptions::InvalidStatus->throw( invalid_status => $self->status ) + unless $self->status eq 'requested'; + + $resolver_id //= C4::Context->userenv ? C4::Context->userenv->{number} : undef; + + return $self->set( + { + resolution_date => \'NOW()', + resolver_id => $resolver_id, + status => 'rejected', + } + )->store; +} + +=head2 Internal methods + +=head3 _type + +=cut + +sub _type { + return 'HoldCancellationRequest'; +} + +=head1 AUTHORS + +Tomas Cohen Arazi + +=cut + +1; diff --git a/Koha/Hold/CancellationRequests.pm b/Koha/Hold/CancellationRequests.pm new file mode 100644 index 0000000000..30339dd8d7 --- /dev/null +++ b/Koha/Hold/CancellationRequests.pm @@ -0,0 +1,117 @@ +package Koha::Hold::CancellationRequests; + +# 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::Database; + +use Koha::Hold::CancellationRequest; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Hold::CancellationRequests - Koha hold cancellation requests Object set class + +=head1 API + +=head2 Class methods + +=head3 filter_by_current + +=cut + +sub filter_by_current { + my ($self) = @_; + + return $self->search({ status => 'requested' }); +} + +=head3 accept + + $hold->cancellation_requests->filter_by_current->accept( $resolver_id ); + +This method accepts all cancellation requests in the resultset. + +=cut + +sub accept { + my ( $self, $resolver_id ) = @_; + + $resolver_id //= C4::Context->userenv ? C4::Context->userenv->{number} : undef; + + $self->_resultset->result_source->schema->txn_do( + sub { + while ( my $req = $self->next ) { + $req->accept($resolver_id); + } + } + ); + + return $self; +} + +=head3 reject + + $hold->cancellation_requests->filter_by_current->reject( $resolver_id ); + +This method rejects all cancellation requests in the resultset. + +=cut + +sub reject { + my ( $self, $resolver_id ) = @_; + + $resolver_id //= C4::Context->userenv ? C4::Context->userenv->{number} : undef; + + $self->_resultset->result_source->schema->txn_do( + sub { + while ( my $req = $self->next ) { + $req->reject($resolver_id); + } + } + ); + + return $self; +} + +=head2 Internal methods + +=head3 _type + +=cut + +sub _type { + return 'HoldCancellationRequest'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::Hold::CancellationRequest'; +} + +=head1 AUTHORS + +Tomas Cohen Arazi + +=cut + +1; diff --git a/t/db_dependent/Koha/Hold/CancellationRequest.t b/t/db_dependent/Koha/Hold/CancellationRequest.t new file mode 100755 index 0000000000..1032287e07 --- /dev/null +++ b/t/db_dependent/Koha/Hold/CancellationRequest.t @@ -0,0 +1,145 @@ +#!/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::Hold::CancellationRequests; + +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +subtest 'store() tests' => sub { + + plan tests => 2; + + $schema->storage->txn_begin; + + my $item = $builder->build_sample_item; + my $hold = $builder->build_object( + { + class => 'Koha::Holds', + value => { + found => 'W', # waiting hold + itemnumber => $item->id, + } + } + ); + + my $creation_date = '2021-06-25 14:05:35'; + + my $request = Koha::Hold::CancellationRequest->new( + { + creation_date => undef, + hold_id => $hold->id + } + )->store; + + isnt( $request->creation_date, undef, 'creation_date is always set' ); + + $request = Koha::Hold::CancellationRequest->new( + { + creation_date => $creation_date, + hold_id => $hold->id + } + )->store; + + is( $request->creation_date, $creation_date, 'Passed creation_date set' ); + + $schema->storage->txn_rollback; +}; + +subtest 'accept() tests' => sub { + + plan tests => 3; + + $schema->storage->txn_begin; + + my $item = $builder->build_sample_item; + my $hold = $builder->build_object( + { + class => 'Koha::Holds', + value => { + found => 'W', # waiting hold + itemnumber => $item->id, + } + } + ); + + # add a request with an unacceptable status + my $request = Koha::Hold::CancellationRequest->new( { hold_id => $hold->id, status => 'accepted' } )->store; + + throws_ok + { $request->accept; } + 'Koha::Exceptions::InvalidStatus', + "Exception thrown when the request status is not 'requested'"; + + is( $@->invalid_status, 'accepted' ); + + # make the request status acceptable + $request->status('requested')->store; + $request->discard_changes; + + # accept it + $request->accept; + + is( $request->status, 'accepted' ); + + $schema->storage->txn_rollback; +}; + +subtest 'reject() tests' => sub { + + plan tests => 3; + + $schema->storage->txn_begin; + + my $item = $builder->build_sample_item; + my $hold = $builder->build_object( + { + class => 'Koha::Holds', + value => { + found => 'W', # waiting hold + itemnumber => $item->id, + } + } + ); + + # add a request with an unrejectable status + my $request = Koha::Hold::CancellationRequest->new( { hold_id => $hold->id, status => 'accepted' } )->store; + + throws_ok + { $request->reject; } + 'Koha::Exceptions::InvalidStatus', + "Exception thrown when the request status is not 'requested'"; + + is( $@->invalid_status, 'accepted' ); + + # make the request status acceptable + $request->status('requested')->store; + + # accept it + $request->reject; + + is( $request->status, 'rejected' ); + + $schema->storage->txn_rollback; +}; diff --git a/t/db_dependent/Koha/Hold/CancellationRequests.t b/t/db_dependent/Koha/Hold/CancellationRequests.t new file mode 100755 index 0000000000..9d1178aca2 --- /dev/null +++ b/t/db_dependent/Koha/Hold/CancellationRequests.t @@ -0,0 +1,273 @@ +#!/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::Database; + +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +subtest 'filter_by_current() tests' => sub { + + plan tests => 3; + + $schema->storage->txn_begin; + + my $requested = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'requested' } + } + ); + my $accepted = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'accepted' } + } + ); + my $rejected = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'rejected' } + } + ); + + my $rs = Koha::Hold::CancellationRequests->search( + { + hold_cancellation_request_id => [ + $requested->id, + $accepted->id, + $rejected->id, + ] + } + ); + + is( $rs->count, 3 ); + + my $rs_current = $rs->filter_by_current; + + is( $rs_current->count, 1 ); + is( $rs_current->next->status, 'requested' ); + + $schema->storage->txn_rollback; +}; + +subtest 'reject() tests' => sub { + + plan tests => 12; + + $schema->storage->txn_begin; + + my $requested_1 = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'requested' } + } + ); + my $requested_2 = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'requested' } + } + ); + my $accepted = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'accepted' } + } + ); + my $rejected = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'rejected' } + } + ); + + my $requests = [ $requested_1, $requested_2, $accepted ]; + + my $rs = Koha::Hold::CancellationRequests->search( + { + hold_cancellation_request_id => [ map { $_->id } @{ $requests } ] + } + ); + + throws_ok + { $rs->reject; } + 'Koha::Exceptions::InvalidStatus', + 'Exception thrown for accepted request'; + + is( $@->invalid_status, 'accepted', "'invalid_status' parameter set to the conflicting value" ); + + # reset iterator + $rs->reset; + + my $i = 0; + while ( my $req = $rs->next ) { + is( $req->status, $requests->[$i]->status, "After exception, status is kept (" . $req->status . ")" ); + $i++; + } + + $requests = [ $requested_1, $requested_2, $rejected ]; + + $rs = Koha::Hold::CancellationRequests->search( + { + hold_cancellation_request_id => [ map { $_->id } @{ $requests } ] + } + ); + + throws_ok + { $rs->reject; } + 'Koha::Exceptions::InvalidStatus', + 'Exception thrown for accepted request'; + + is( $@->invalid_status, 'rejected', "'invalid_status' parameter set to the conflicting value" ); + + # reset iterator + $rs->reset; + + $i = 0; + while ( my $req = $rs->next ) { + is( $req->status, $requests->[$i]->status, "After exception, status is kept (" . $req->status . ")" ); + $i++; + } + + $requests = [ $requested_1, $requested_2 ]; + + $rs = Koha::Hold::CancellationRequests->search( + { + hold_cancellation_request_id => [ map { $_->id } @{ $requests } ] + } + ); + + $rs = $rs->reject; + + $rs->reset; + + $i = 0; + while ( my $req = $rs->next ) { + is( $req->status, 'rejected', "status is 'rejected'" ); + $i++; + } + + $schema->storage->txn_rollback; +}; + +subtest 'accept() tests' => sub { + + plan tests => 12; + + $schema->storage->txn_begin; + + my $requested_1 = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'requested' } + } + ); + my $requested_2 = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'requested' } + } + ); + my $accepted = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'accepted' } + } + ); + my $rejected = $builder->build_object( + { + class => 'Koha::Hold::CancellationRequests', + value => { status => 'rejected' } + } + ); + + my $requests = [ $requested_1, $requested_2, $accepted ]; + + my $rs = Koha::Hold::CancellationRequests->search( + { + hold_cancellation_request_id => [ map { $_->id } @{ $requests } ] + } + ); + + throws_ok + { $rs->accept; } + 'Koha::Exceptions::InvalidStatus', + 'Exception thrown for accepted request'; + + is( $@->invalid_status, 'accepted', "'invalid_status' parameter set to the conflicting value" ); + + # reset iterator + $rs->reset; + + my $i = 0; + while ( my $req = $rs->next ) { + is( $req->status, $requests->[$i]->status, "After exception, status is kept (" . $req->status . ")" ); + $i++; + } + + $requests = [ $requested_1, $requested_2, $rejected ]; + + $rs = Koha::Hold::CancellationRequests->search( + { + hold_cancellation_request_id => [ map { $_->id } @{ $requests } ] + } + ); + + throws_ok + { $rs->accept; } + 'Koha::Exceptions::InvalidStatus', + 'Exception thrown for accepted request'; + + is( $@->invalid_status, 'rejected', "'invalid_status' parameter set to the conflicting value" ); + + # reset iterator + $rs->reset; + + $i = 0; + while ( my $req = $rs->next ) { + is( $req->status, $requests->[$i]->status, "After exception, status is kept (" . $req->status . ")" ); + $i++; + } + + $requests = [ $requested_1, $requested_2 ]; + + $rs = Koha::Hold::CancellationRequests->search( + { + hold_cancellation_request_id => [ map { $_->id } @{ $requests } ] + } + ); + + $rs = $rs->accept; + + $rs->reset; + + $i = 0; + while ( my $req = $rs->next ) { + is( $req->status, 'accepted', "status is 'accepted'" ); + $i++; + } + + $schema->storage->txn_rollback; +}; -- 2.34.1