From 05fc2acdc4244f96d1300953e7252e82f4c05c64 Mon Sep 17 00:00:00 2001
From: Kyle Hall <kyle@bywatersolutions.com>
Date: Mon, 25 Jul 2022 10:56:08 -0400
Subject: [PATCH] Bug 31236: Add ability to send custom item fields via SIP
 using Template Toolkit

Koha has been able to send arbitrary item fields via the "item_field" parameter in the config. We have partners that need the ability to created custom item fields from templates, as the item_fields feature cannot accomplish what they need. We need to add a templated custom field feature for items, similar to what we have for patrons.

Test Plan:
1) Apply this patch
2) Choose a SIP login to use, edit that account and add the following
   *inside* the login section:
   <custom_item_field field="IN" template="[% item.itemnumber %]" />
3) Restart SIP
4) Run an item information query
5) Note the itemnumber is sent in the IN field!
---
 C4/SIP/ILS/Item.pm           | 62 +++++++++++++++++++++++++++++++++++-
 C4/SIP/Sip/MsgType.pm        |  1 +
 etc/SIPconfig.xml            |  1 +
 t/db_dependent/SIP/Message.t | 32 ++++++++++++++++++-
 4 files changed, 94 insertions(+), 2 deletions(-)

diff --git a/C4/SIP/ILS/Item.pm b/C4/SIP/ILS/Item.pm
index 105b8d01003..aba4f0bfd28 100644
--- a/C4/SIP/ILS/Item.pm
+++ b/C4/SIP/ILS/Item.pm
@@ -14,7 +14,7 @@ use Carp;
 use Template;
 
 use C4::SIP::ILS::Transaction;
-use C4::SIP::Sip qw(add_field);
+use C4::SIP::Sip qw(add_field maybe_add);
 
 use C4::Biblio;
 use C4::Circulation qw( barcodedecode );
@@ -429,9 +429,69 @@ sub build_additional_item_fields_string {
         }
     }
 
+    if ( $server->{account}->{custom_item_field} ) {
+        my @custom_fields =
+            ref $server->{account}->{custom_item_field} eq "ARRAY"
+            ? @{ $server->{account}->{custom_item_field} }
+            : $server->{account}->{custom_item_field};
+
+        foreach my $custom_field ( @custom_fields ) {
+            my $field = $custom_field->{field};
+            return q{} unless defined $field;
+            my $template = $custom_field->{template};
+            my $formatted = $self->format( $template );
+            my $substring = maybe_add( $field, $formatted, $server );
+            $string .= $substring;
+        }
+    }
+
+    return $string;
+}
+
+=head2 build_custom_field_string
+
+This method builds the part of the sip message for custom item fields as defined in the sip config
+
+=cut
+
+sub build_custom_field_string {
+    my ( $self, $server ) = @_;
+
+    my $string = q{};
+
+
     return $string;
 }
 
+=head2 format
+
+This method uses a template to build a string from a Koha::Item object
+If errors are encountered in processing template we log them and return nothing
+
+=cut
+
+sub format {
+    my ( $self, $template ) = @_;
+
+    if ($template) {
+        require Template;
+
+        my $tt = Template->new();
+
+        my $item = $self->{_object};
+
+        my $output;
+        eval {
+            $tt->process( \$template, { item => $item }, \$output );
+        };
+        if ( $@ ){
+            siplog("LOG_DEBUG", "Error processing template: $template");
+            return "";
+        }
+        return $output;
+    }
+}
+
 1;
 __END__
 
diff --git a/C4/SIP/Sip/MsgType.pm b/C4/SIP/Sip/MsgType.pm
index 2f7ba7da0fa..dd604d173f9 100644
--- a/C4/SIP/Sip/MsgType.pm
+++ b/C4/SIP/Sip/MsgType.pm
@@ -1270,6 +1270,7 @@ sub handle_item_information {
         $resp .= maybe_add( FID_PRINT_LINE, $item->print_line, $server );
 
         $resp .= $item->build_additional_item_fields_string( $server );
+        $resp .= $item->build_custom_field_string( $server );
     }
 
     $self->write_msg( $resp, undef, $server->{account}->{terminator}, $server->{account}->{encoding} );
diff --git a/etc/SIPconfig.xml b/etc/SIPconfig.xml
index e273cfc25bc..4796877a019 100644
--- a/etc/SIPconfig.xml
+++ b/etc/SIPconfig.xml
@@ -86,6 +86,7 @@
               <AllFinesNeedOverride>0</AllFinesNeedOverride>
           </syspref_overrides>
           <custom_patron_field field="DE" template="[% patron.dateexpiry %]" />
+          <custom_item_field field="IN" template="[% item.itemnumber %]" />
       </login>
   </accounts>
 
diff --git a/t/db_dependent/SIP/Message.t b/t/db_dependent/SIP/Message.t
index fc0e11944b0..73e7b58d8c5 100755
--- a/t/db_dependent/SIP/Message.t
+++ b/t/db_dependent/SIP/Message.t
@@ -21,7 +21,7 @@
 # along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 use Modern::Perl;
-use Test::More tests => 13;
+use Test::More tests => 14;
 use Test::Exception;
 use Test::MockObject;
 use Test::MockModule;
@@ -230,6 +230,36 @@ subtest "Test build_additional_item_fields_string" => sub {
     $schema->storage->txn_rollback;
 };
 
+subtest "Test build_custom_field_string" => sub {
+    my $schema = Koha::Database->new->schema;
+    $schema->storage->txn_begin;
+
+    plan tests => 2;
+
+    my $builder = t::lib::TestBuilder->new();
+
+    my $item = $builder->build_sample_item;
+    my $item_id = $item->id;
+    my $item_barcode = $item->barcode;
+    my $ils_item = C4::SIP::ILS::Item->new( $item->barcode );
+
+    my $server = {};
+    $server->{account}->{custom_item_field}->{field} = "XY";
+    $server->{account}->{custom_item_field}->{template} = "[% item.id %] [% item.barcode %], woo!";
+    my $attribute_string = $ils_item->build_additional_item_fields_string( $server );
+    is( $attribute_string, "XY$item_id $item_barcode, woo!|", 'Attribute field generated correctly with single param' );
+
+    $server = {};
+    $server->{account}->{custom_item_field}->[0]->{field} = "ZY";
+    $server->{account}->{custom_item_field}->[0]->{template} = "[% item.id %]!";
+    $server->{account}->{custom_item_field}->[1]->{field} = "ZX";
+    $server->{account}->{custom_item_field}->[1]->{template} = "[% item.barcode %]*";
+    $attribute_string = $ils_item->build_additional_item_fields_string( $server );
+    is( $attribute_string, sprintf("ZY%s!|ZX%s*|", $item_id, $item_barcode), 'Attribute field generated correctly with multiple params' );
+
+    $schema->storage->txn_rollback;
+};
+
 subtest "Test cr_item_field" => sub {
     plan tests => 2;
 
-- 
2.30.2