From ea45a0fd7cc3e753167376618f6780aa2327c8ad Mon Sep 17 00:00:00 2001
From: David Bourgault <dav.bour@gmail.com>
Date: Fri, 4 May 2018 15:38:11 -0400
Subject: [PATCH] Bug 12747: Add extra column in Z3950 search

This patch makes it possible to add an extra column to Z3950 search results.
The system preference AdditionalFieldsInZ3950ResultSearch decides which MARC field/subfields are displayed in the column.

Testing:

I Apply the patch
II Run updatedatabase.pl

ACQUISITIONS
0) Enter a field/subfield in the AdditionalFieldsInZ3950ResultSearch
1) Create a new basket or use an existing one
2) In -Add order to basket-, click "From an external source"
3) Select some search targets and enter a subject heading ex. house
4) Click Search bouton
5) Validate "Additional fields" column with the field/subfield value.

CATALOGUING
0) Shares same syspref as above
1) Go to cataloguing, click New from z3950
2) Fill to result in a successful search
3) Validate column Addition Fields

prove t/db_dependent/Breeding.t

Sponsored-by: CCSR (https://ccsr.qc.ca)

Signed-off-by: Katrin Fischer <katrin.fischer.83@web.de>
---
 C4/Breeding.pm                                     | 57 ++++++++++++++++++++--
 ...47-additional_fields_in_Z3950_search_result.sql |  1 +
 installer/data/mysql/sysprefs.sql                  |  1 +
 .../prog/en/modules/acqui/z3950_search.tt          | 22 ++++++++-
 .../en/modules/admin/preferences/cataloguing.pref  |  4 ++
 .../prog/en/modules/cataloguing/z3950_search.tt    | 17 ++++++-
 t/db_dependent/Breeding.t                          | 50 ++++++++++++++++++-
 7 files changed, 145 insertions(+), 7 deletions(-)
 create mode 100644 installer/data/mysql/atomicupdate/bug_12747-additional_fields_in_Z3950_search_result.sql
 mode change 100644 => 100755 t/db_dependent/Breeding.t

diff --git a/C4/Breeding.pm b/C4/Breeding.pm
index 37f450d..d187703 100644
--- a/C4/Breeding.pm
+++ b/C4/Breeding.pm
@@ -25,6 +25,7 @@ use C4::Biblio;
 use C4::Koha;
 use C4::Charset;
 use MARC::File::USMARC;
+use MARC::Field;
 use C4::ImportBatch;
 use C4::AuthoritiesMarc; #GuessAuthTypeCode, FindDuplicateAuthority
 use C4::Languages;
@@ -374,15 +375,65 @@ sub _add_rowdata {
         author => 'biblio.author',
         isbn =>'biblioitems.isbn',
         lccn =>'biblioitems.lccn', #LC control number (not call number)
-        edition =>'biblioitems.editionstatement',
-        date => 'biblio.copyrightdate', #MARC21
-        date2 => 'biblioitems.publicationyear', #UNIMARC
+        edition =>'biblioitems.editionstatement'
     );
+    $fetch{date} = C4::Context->preference('marcflavour') eq "MARC21" ? 'biblio.copyrightdate' : 'biblioitems.publicationyear';
+
     foreach my $k (keys %fetch) {
         $row->{$k} = C4::Biblio::TransformMarcToKohaOneField( $fetch{$k}, $record );
     }
     $row->{date}//= $row->{date2};
     $row->{isbn}=_isbn_replace($row->{isbn});
+
+    $row = _add_custom_field_rowdata($row, $record);
+
+    return $row;
+}
+
+sub _add_custom_field_rowdata
+{
+    my ( $row, $record ) = @_;
+    my $pref_newtags = C4::Context->preference('AdditionalFieldsInZ3950ResultSearch');
+
+    $pref_newtags =~ s/^\s+|\s+$//g;
+    $pref_newtags =~ s/\h+/ /g;
+
+    my @addnumberfields;
+
+    foreach my $field (split /\,/, $pref_newtags) {
+        $field =~ s/^\s+|\s+$//g ;  # trim whitespace
+        my ($tag, $subtags) = split(/\$/, $field);
+
+        if ( $record->field($tag) ) {
+            my @content = ();
+
+            for my $marcfield ($record->field($tag)) {
+                if ( $subtags ) {
+                    my $str = '';
+                    for my $code (split //, $subtags) {
+                        if ( $marcfield->subfield($code) ) {
+                            $str .= $marcfield->subfield($code) . ' ';
+                        }
+                    }
+                    if ( not $str eq '') {
+                        push @content, $str;
+                    }
+                } elsif ( $tag <= 10 ) {
+                    push @content, $marcfield->data();
+                } else {
+                    push @content, $marcfield->as_string();
+                }
+            }
+
+            if ( @content ) {
+                $row->{$field} = \@content;
+                push( @addnumberfields, $field );
+            }
+        }
+    }
+
+    $row->{'addnumberfields'} = \@addnumberfields;
+
     return $row;
 }
 
diff --git a/installer/data/mysql/atomicupdate/bug_12747-additional_fields_in_Z3950_search_result.sql b/installer/data/mysql/atomicupdate/bug_12747-additional_fields_in_Z3950_search_result.sql
new file mode 100644
index 0000000..d60bed3
--- /dev/null
+++ b/installer/data/mysql/atomicupdate/bug_12747-additional_fields_in_Z3950_search_result.sql
@@ -0,0 +1 @@
+INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('AdditionalFieldsInZ3950ResultSearch', '', 'NULL', 'Determines which MARC field/subfields are displayed in -Additional field- column in the result of a search Z3950', 'Free');
diff --git a/installer/data/mysql/sysprefs.sql b/installer/data/mysql/sysprefs.sql
index 4a62a26..ada7b8f 100644
--- a/installer/data/mysql/sysprefs.sql
+++ b/installer/data/mysql/sysprefs.sql
@@ -6,6 +6,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `
 ('AcquisitionDetails', '1', '', 'Hide/Show acquisition details on the biblio detail page.', 'YesNo'),
 ('AcqViewBaskets','user','user|branch|all','Define which baskets a user is allowed to view: his own only, any within his branch or all','Choice'),
 ('AcqWarnOnDuplicateInvoice','0','','Warn librarians when they try to create a duplicate invoice','YesNo'),
+('AdditionalFieldsInZ3950ResultSearch', '', NULL, 'Determines which MARC field/subfields are displayed in -Additional field- column in the result of a search Z3950', 'Free'),
 ('AddressFormat','us','us|de|fr','Choose format to display postal addresses', 'Choice'),
 ('advancedMARCeditor','0','','If ON, the MARC editor won\'t display field/subfield descriptions','YesNo'),
 ('AdvancedSearchLanguages','','','ISO 639-2 codes of languages you wish to see appear as an Advanced search option.  Example: eng|fre|ita','Textarea'),
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/z3950_search.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/z3950_search.tt
index 81445f0..0615866 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/z3950_search.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/acqui/z3950_search.tt
@@ -4,6 +4,9 @@
 <title>Koha &rsaquo; Acquisitions &rsaquo; [% IF ( opsearch ) %]Order from external source[% ELSE %]Order from external source &rsaquo; Search results[% END %]</title>
 [% Asset.css("css/datatables.css") %]
 [% INCLUDE 'doc-head-close.inc' %]
+[% INCLUDE 'datatables.inc' %]
+[% USE Koha %]
+
 <style type="text/css">
 .linktools { background-color:#FFF;border-top:1px solid #DDD; border-left: 1px solid #DDD; border-right: 1px solid #666; border-bottom:1px solid #666;display: none; white-space: nowrap;}
 .linktools a { font-size : 85%; text-decoration:none; padding:.3em;;background-color:#FFF; display:block;float:left;border-right:1px solid #DDD;}
@@ -15,7 +18,7 @@ tr.selected { background-color : #FFFFCC; } tr.selected td { background-color :
 <body id="acq_z3950_search" class="acq">
 [% INCLUDE 'header.inc' %]
 [% INCLUDE 'acquisitions-search.inc' %]
-
+[% INCLUDE 'z3950_search.inc' %]
 <div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/acqui/acqui-home.pl">Acquisitions</a> &rsaquo; <a href="/cgi-bin/koha/acqui/supplier.pl?booksellerid=[% booksellerid | uri %]">[% name %]</a> &rsaquo; <a href="/cgi-bin/koha/acqui/basket.pl?basketno=[% basketno | uri %]">Basket [% basketno | html %]</a> &rsaquo; [% IF ( opsearch ) %]Order from external source[% ELSE %]<a href="/cgi-bin/koha/acqui/z3950_search.pl?booksellerid=[% booksellerid | uri %]&amp;basketno=[% basketno | uri %]">Order from external source</a> &rsaquo; Search results[% END %]</div>
 
 <div class="main container-fluid">
@@ -102,6 +105,9 @@ tr.selected { background-color : #FFFFCC; } tr.selected td { background-color :
         <th>Author</th>
         <th>ISBN</th>
         <th>LCCN</th>
+        [% IF Koha.Preference('AdditionalFieldsInZ3950ResultSearch') != '' %]
+        <th>Additional fields</th>
+        [% END %]
         <th>Preview</th>
 		<th>&nbsp;</th>
     </tr></thead>
@@ -114,6 +120,18 @@ tr.selected { background-color : #FFFFCC; } tr.selected td { background-color :
             <td>[% breeding_loo.author %]</td>
             <td>[% breeding_loo.isbn %]</td>
             <td>[% breeding_loo.lccn %]</td>
+            [% IF Koha.Preference('AdditionalFieldsInZ3950ResultSearch') != '' %]
+            <td>
+               <dl>
+                  [% FOREACH addnumberfield IN breeding_loo.addnumberfields %]
+                    [% FOREACH string IN breeding_loo.$addnumberfield %]
+                        <dt>[% addnumberfield %]:</dt>
+                        <dd>[% string %]</dd>
+                    [% END %]
+                  [% END %]
+               </dl>
+            </td>
+            [% END %]
             <td><a href="/cgi-bin/koha/catalogue/showmarc.pl?importid=[% breeding_loo.breedingid %]" title="MARC" class="previewData">MARC</a> | <a href="/cgi-bin/koha/catalogue/showmarc.pl?viewas=card&amp;importid=[% breeding_loo.breedingid %]" title="Card" class="previewData">Card</a></td>
             <td><a href="/cgi-bin/koha/acqui/neworderempty.pl?frameworkcode=[% frameworkcode | uri %]&amp;breedingid=[% breeding_loo.breedingid %]&amp;booksellerid=[% booksellerid | uri %]&amp;basketno=[% basketno | uri %]">Order</a></td>
 
@@ -227,4 +245,4 @@ tr.selected { background-color : #FFFFCC; } tr.selected td { background-color :
     [% Asset.js("js/z3950_search.js") %]
 [% END %]
 
-[% INCLUDE 'intranet-bottom.inc' %]
\ No newline at end of file
+[% INCLUDE 'intranet-bottom.inc' %]
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref
index cc75b6d..c883e88 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref
@@ -246,6 +246,10 @@ Cataloging:
                   no: "don't"
             - attempt to match aggressively by trying all variations of the ISBNs in the imported record as a phrase in the ISBN fields of already cataloged records.  Note that this preference has no effect if UseQueryParser is on.
         -
+            - Display the MARC field/subfields
+            - pref: AdditionalFieldsInZ3950ResultSearch
+            - " in the 'Additional fields' column in the result of a search Z3950 (use comma as delimiter e.g.: \"<code>001, 082$ab, 090$ab</code>\")"
+        -
             - When matching on ISSN with the record import tool,
             - pref: AggressiveMatchOnISSN
               choices:
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/z3950_search.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/z3950_search.tt
index 3e22aca..5f88e85 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/z3950_search.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/z3950_search.tt
@@ -1,5 +1,6 @@
 [% USE Asset %]
 [% SET footerjs = 1 %]
+[% USE Koha %]
 [% INCLUDE 'doc-head-open.inc' %]
 <title>Koha &rsaquo; Z39.50/SRU search results</title>
 [% INCLUDE 'doc-head-close.inc' %]
@@ -101,6 +102,9 @@
         <th>Edition</th>
         <th>ISBN</th>
         <th>LCCN</th>
+        [% IF Koha.Preference('AdditionalFieldsInZ3950ResultSearch') != '' %]
+        <th>Additional fields</th>
+        [% END %]
         <th>Actions</th>
     </tr></thead>
     <tbody>[% FOREACH breeding_loo IN breeding_loop %]
@@ -114,7 +118,18 @@
             <td>[% breeding_loo.edition %]</td>
             <td>[% breeding_loo.isbn %]</td>
             <td>[% breeding_loo.lccn %]</td>
-
+            [% IF Koha.Preference('AdditionalFieldsInZ3950ResultSearch') != '' %]
+            <td>
+               <dl>
+                  [% FOREACH addnumberfield IN breeding_loo.addnumberfields %]
+                    [% FOREACH string IN breeding_loo.$addnumberfield %]
+                        <dt>[% addnumberfield %]:</dt>
+                        <dd>[% string %]</dd>
+                    [% END %]
+                  [% END %]
+               </dl>
+            </td>
+            [% END %]
             <td>
                 <div class="dropdown">
                     <a class="btn btn-default btn-xs dropdown-toggle" id="cataloguesearchactions[% breeding_loo.breedingid %]" role="button" data-toggle="dropdown" href="#">
diff --git a/t/db_dependent/Breeding.t b/t/db_dependent/Breeding.t
old mode 100644
new mode 100755
index 65de56c..d55dd33
--- a/t/db_dependent/Breeding.t
+++ b/t/db_dependent/Breeding.t
@@ -20,9 +20,11 @@
 use Modern::Perl;
 
 use FindBin;
-use Test::More tests => 3;
+use Test::More tests => 4;
 use Test::Warn;
+use t::lib::Mocks qw( mock_preference );
 
+use C4::Context;
 use C4::Breeding;
 use Koha::XSLT_Handler;
 
@@ -49,6 +51,11 @@ subtest '_do_xslt_proc' => sub {
     plan tests => 6;
     test_do_xslt();
 };
+#Group 4: testing _add_rowdata (part of Z3950Search)
+subtest '_add_rowdata' => sub {
+    plan tests => 5;
+    test_add_rowdata();
+};
 
 #-------------------------------------------------------------------------------
 
@@ -189,3 +196,44 @@ sub test_do_xslt {
     is ( $res[0]->subfield('245','a'), 'Just a title',
         'At least the title is the same :)' );
 }
+
+sub test_add_rowdata {
+    t::lib::Mocks::mock_preference('AdditionalFieldsInZ3950ResultSearch','');
+
+    my $row = {
+       biblionumber => 0,
+       server => "testServer",
+       breedingid => 0
+   };
+
+    my $biblio = MARC::Record->new();
+    $biblio->append_fields(
+        MARC::Field->new('245', ' ', ' ', a => 'Just a title'), #title
+    );
+
+    my $returned_row = C4::Breeding::_add_rowdata($row, $biblio);
+
+    is($returned_row->{title}, "Just a title", "_add_rowdata returns the title of a biblio");
+    is($returned_row->{addnumberfields}[0], undef, "_add_rowdata returns undef if it has no additionnal field");
+
+    t::lib::Mocks::mock_preference('AdditionalFieldsInZ3950ResultSearch',"245\$a, 035\$a");
+
+    $row = {
+       biblionumber => 0,
+       server => "testServer",
+       breedingid => 0
+   };
+   $biblio = MARC::Record->new();
+   $biblio->append_fields(
+        MARC::Field->new('245', ' ', ' ', a => 'Just a title'), #title
+        MARC::Field->new('035', ' ', ' ', a => 'First 035'),
+        MARC::Field->new('035', ' ', ' ', a => 'Second 035')
+   );
+   $returned_row = C4::Breeding::_add_rowdata($row, $biblio);
+
+   is($returned_row->{title}, "Just a title", "_add_rowdata returns the title of a biblio");
+   is($returned_row->{addnumberfields}[0], "245\$a", "_add_rowdata returns the field number chosen in the AdditionalFieldsInZ3950ResultSearch preference");
+
+   # Test repeatble tags,the trailing whitespace is a normal side-effect of _add_custom_row_data
+   is_deeply(\$returned_row->{"035\$a"}, \["First 035 ", "Second 035 "],"_add_rowdata supports repeatable tags");
+}
-- 
2.1.4