From 8a36043de0afdeb634dde5b94c8dba1b584a3afd Mon Sep 17 00:00:00 2001
From: Martin Renvoize <martin.renvoize@ptfs-europe.com>
Date: Mon, 21 Sep 2020 15:20:38 +0100
Subject: [PATCH] Bug 26057: Add 'cancel' method to Koha::Item::Transfer

This patch adds the 'cancel' method to Koha::Item::Transfer which sets
the transfer as cancelled by updating the datecancelled field. We also
update Koha::Item->get_transfer here to accomodate for the new
resolution available for a transfer.

Test plan:
1/ Run the included unit tests additions (t/db_dependent/Koha/Items.t,
t/db_dependent/Koha/Item/Transfer.t
---
 Koha/Exceptions/Item/Transfer.pm    |  5 ++-
 Koha/Item.pm                        | 10 ++++--
 Koha/Item/Transfer.pm               | 18 ++++++++++
 t/db_dependent/Koha/Item/Transfer.t | 51 ++++++++++++++++++++++++++++-
 t/db_dependent/Koha/Items.t         | 33 +++++++++++--------
 5 files changed, 99 insertions(+), 18 deletions(-)

diff --git a/Koha/Exceptions/Item/Transfer.pm b/Koha/Exceptions/Item/Transfer.pm
index 40b247c59d..aa596c314a 100644
--- a/Koha/Exceptions/Item/Transfer.pm
+++ b/Koha/Exceptions/Item/Transfer.pm
@@ -19,8 +19,11 @@ use Exception::Class (
     'Koha::Exceptions::Item::Transfer::Out' => {
         isa => 'Koha::Exceptions::Item::Transfer',
         description => "Transfer item is currently checked out"
+    },
+    'Koha::Exceptions::Item::Transfer::Transit' => {
+        isa => 'Koha::Exceptions::Item::Transfer',
+        description => "Transfer item is currently in transit"
     }
-
 );
 
 1;
diff --git a/Koha/Item.pm b/Koha/Item.pm
index ba5082e700..23380068e1 100644
--- a/Koha/Item.pm
+++ b/Koha/Item.pm
@@ -467,10 +467,14 @@ if it exists, otherwise the oldest unsatisfied transfer will be returned.
 sub get_transfer {
     my ($self) = @_;
     my $transfer_rs = $self->_result->branchtransfers->search(
-        { datearrived => undef },
         {
-            order_by => [ { -desc => 'datesent' }, { -asc => 'daterequested' } ],
-            rows     => 1
+            datearrived   => undef,
+            datecancelled => undef
+        },
+        {
+            order_by =>
+              [ { -desc => 'datesent' }, { -asc => 'daterequested' } ],
+            rows => 1
         }
     )->first;
     return unless $transfer_rs;
diff --git a/Koha/Item/Transfer.pm b/Koha/Item/Transfer.pm
index 99ea77e630..c05585e4de 100644
--- a/Koha/Item/Transfer.pm
+++ b/Koha/Item/Transfer.pm
@@ -116,6 +116,24 @@ sub receive {
     return $self;
 }
 
+=head3 cancel
+
+Cancel the transfer by setting the datecancelled time.
+
+=cut
+
+sub cancel {
+    my ($self) = @_;
+
+    # Throw exception if item is in transit already
+    Koha::Exceptions::Item::Transfer::Transit->throw() if ( $self->in_transit );
+
+    # Update the cancelled date
+    $self->set( { datecancelled => dt_from_string } )->store;
+
+    return $self;
+}
+
 =head3 type
 
 =cut
diff --git a/t/db_dependent/Koha/Item/Transfer.t b/t/db_dependent/Koha/Item/Transfer.t
index 9a8c8258fa..750c0e4bd9 100644
--- a/t/db_dependent/Koha/Item/Transfer.t
+++ b/t/db_dependent/Koha/Item/Transfer.t
@@ -24,7 +24,7 @@ use Koha::DateUtils;
 
 use t::lib::TestBuilder;
 
-use Test::More tests => 4;
+use Test::More tests => 5;
 use Test::Exception;
 
 my $schema  = Koha::Database->new->schema;
@@ -204,5 +204,54 @@ subtest 'in_transit tests' => sub {
     ok( !$transfer->in_transit, 'in_transit returns false when datearrived is defined');
 
 
+    $schema->storage->txn_rollback;
+};
+
+subtest 'cancel tests' => sub {
+    plan tests => 4;
+
+    $schema->storage->txn_begin;
+
+    my $library1 = $builder->build_object( { class => 'Koha::Libraries' } );
+    my $library2 = $builder->build_object( { class => 'Koha::Libraries' } );
+    my $item     = $builder->build_sample_item(
+        {
+            homebranch    => $library1->branchcode,
+            holdingbranch => $library2->branchcode,
+            datelastseen  => undef
+        }
+    );
+
+    my $transfer = $builder->build_object(
+        {
+            class => 'Koha::Item::Transfers',
+            value => {
+                itemnumber    => $item->itemnumber,
+                frombranch    => $library2->branchcode,
+                tobranch      => $library1->branchcode,
+                datesent      => \'NOW()',
+                datearrived   => undef,
+                datecancelled => undef,
+                reason        => 'Manual'
+            }
+        }
+    );
+    is( ref($transfer), 'Koha::Item::Transfer', 'Mock transfer added' );
+
+    # Item in transit should result in failure
+    throws_ok { $transfer->cancel() }
+    'Koha::Exceptions::Item::Transfer::Transit',
+      'Exception thrown if item is in transit';
+
+    $transfer->datesent(undef)->store();
+
+    # Transit state set
+    $transfer->discard_changes;
+    $transfer->cancel();
+    ok( $transfer->datecancelled, 'Cancellation date set upon call to cancel' );
+
+    # Last seen
+    is( $transfer->reason, 'Manual', 'Reason is not updated by cancelling the transfer' );
+
     $schema->storage->txn_rollback;
 };
diff --git a/t/db_dependent/Koha/Items.t b/t/db_dependent/Koha/Items.t
index 978a257557..adad803b47 100755
--- a/t/db_dependent/Koha/Items.t
+++ b/t/db_dependent/Koha/Items.t
@@ -811,7 +811,7 @@ subtest 'store' => sub {
 };
 
 subtest 'get_transfer' => sub {
-    plan tests => 6;
+    plan tests => 7;
 
     my $transfer = $new_item_1->get_transfer();
     is( $transfer, undef, 'Koha::Item->get_transfer should return undef if the item is not in transit' );
@@ -828,6 +828,7 @@ subtest 'get_transfer' => sub {
                 reason        => 'Manual',
                 datesent      => undef,
                 datearrived   => undef,
+                datecancelled => undef,
                 daterequested => \'NOW()'
             }
         }
@@ -840,12 +841,13 @@ subtest 'get_transfer' => sub {
         {
             class => 'Koha::Item::Transfers',
             value => {
-                itemnumber  => $new_item_1->itemnumber,
-                frombranch  => $new_item_1->holdingbranch,
-                tobranch    => $library_to->{branchcode},
-                reason      => 'Manual',
-                datesent    => undef,
-                datearrived => undef,
+                itemnumber    => $new_item_1->itemnumber,
+                frombranch    => $new_item_1->holdingbranch,
+                tobranch      => $library_to->{branchcode},
+                reason        => 'Manual',
+                datesent      => undef,
+                datearrived   => undef,
+                datecancelled => undef,
                 daterequested => \'NOW()'
             }
         }
@@ -862,12 +864,13 @@ subtest 'get_transfer' => sub {
         {
             class => 'Koha::Item::Transfers',
             value => {
-                itemnumber  => $new_item_1->itemnumber,
-                frombranch  => $new_item_1->holdingbranch,
-                tobranch    => $library_to->{branchcode},
-                reason      => 'Manual',
-                datesent    => undef,
-                datearrived => undef,
+                itemnumber    => $new_item_1->itemnumber,
+                frombranch    => $new_item_1->holdingbranch,
+                tobranch      => $library_to->{branchcode},
+                reason        => 'Manual',
+                datesent      => undef,
+                datearrived   => undef,
+                datecancelled => undef,
                 daterequested => \'NOW()'
             }
         }
@@ -877,6 +880,10 @@ subtest 'get_transfer' => sub {
     $transfer = $new_item_1->get_transfer();
     is( $transfer->branchtransfer_id, $transfer_1->branchtransfer_id, 'Koha::Item->get_transfer returns the next queued transfer');
     is( $transfer->itemnumber, $new_item_1->itemnumber, 'Koha::Item->get_transfer returns the right items transfer' );
+
+    $transfer_1->datecancelled(\'NOW()')->store;
+    $transfer = $new_item_1->get_transfer();
+    is( $transfer->branchtransfer_id, $transfer_3->branchtransfer_id, 'Koha::Item->get_transfer ignores cancelled transfers');
 };
 
 subtest 'holds' => sub {
-- 
2.20.1