From 62f52e2d6d252437b038f49ae5403d40094f82d6 Mon Sep 17 00:00:00 2001
From: Jonathan Druart <jonathan.druart@bugs.koha-community.org>
Date: Tue, 27 Feb 2018 18:35:41 -0300
Subject: [PATCH] Bug 20307: Language overlay for authorised values

---
 C4/Koha.pm                                         | 47 +++++-------------
 Koha/AuthorisedValue.pm                            | 55 ++++++++++++++++++++++
 Koha/AuthorisedValues.pm                           | 30 +++++++++++-
 Koha/Schema/Result/AuthorisedValue.pm              | 17 ++++++-
 Koha/Schema/Result/AuthorisedValueLocalization.pm  | 32 +++++++++++++
 admin/authorised_values.pl                         | 21 +++------
 admin/localization.pl                              | 16 ++-----
 .../prog/en/modules/admin/authorised_values.tt     | 47 ++++++++++++------
 .../prog/en/modules/admin/localization.tt          |  4 +-
 svc/localization                                   | 29 ++++++------
 10 files changed, 204 insertions(+), 94 deletions(-)
 create mode 100644 Koha/Schema/Result/AuthorisedValueLocalization.pm

diff --git a/C4/Koha.pm b/C4/Koha.pm
index a15080998a..f198f5b1dc 100644
--- a/C4/Koha.pm
+++ b/C4/Koha.pm
@@ -547,43 +547,22 @@ sub GetAuthorisedValues {
     my $result = $cache->get_from_cache($cache_key);
     return $result if $result;
 
+    # FIXME Need to deal with $opac
+    my $avs = Koha::AuthorisedValues->search_with_localization(
+        {
+            ( $category ? ( category => $category ) : () ),
+            ( $branch_limit ? ( branchcode => $branch_limit ) : () ),
+        }
+    );
     my @results;
-    my $dbh      = C4::Context->dbh;
-    my $query = qq{
-        SELECT DISTINCT av.*
-        FROM authorised_values av
-    };
-    $query .= qq{
-          LEFT JOIN authorised_values_branches ON ( id = av_id )
-    } if $branch_limit;
-    my @where_strings;
-    my @where_args;
-    if($category) {
-        push @where_strings, "category = ?";
-        push @where_args, $category;
-    }
-    if($branch_limit) {
-        push @where_strings, "( branchcode = ? OR branchcode IS NULL )";
-        push @where_args, $branch_limit;
-    }
-    if(@where_strings > 0) {
-        $query .= " WHERE " . join(" AND ", @where_strings);
-    }
-    $query .= ' ORDER BY category, ' . (
-                $opac ? 'COALESCE(lib_opac, lib)'
-                      : 'lib, lib_opac'
-              );
-
-    my $sth = $dbh->prepare($query);
+    while ( my $av = $avs->next ) {
+        my $av_unblessed = $av->unblessed;
+        $av_unblessed->{translated_description} = $av->translated_description;
+        $av_unblessed->{lib} = $av->translated_description;
+        $av_unblessed->{lib_opac} = $av->translated_description;
+        push @results, $av_unblessed;
 
-    $sth->execute( @where_args );
-    while (my $data=$sth->fetchrow_hashref) {
-        if ($opac && $data->{lib_opac}) {
-            $data->{lib} = $data->{lib_opac};
-        }
-        push @results, $data;
     }
-    $sth->finish;
 
     $cache->set_in_cache( $cache_key, \@results, { expiry => 5 } );
     return \@results;
diff --git a/Koha/AuthorisedValue.pm b/Koha/AuthorisedValue.pm
index 898b630279..b60c57d67d 100644
--- a/Koha/AuthorisedValue.pm
+++ b/Koha/AuthorisedValue.pm
@@ -21,7 +21,9 @@ use Modern::Perl;
 
 use Carp;
 
+use C4::Languages;
 use Koha::Database;
+use Koha::Localizations;
 
 use base qw(Koha::Object);
 
@@ -143,6 +145,59 @@ sub opac_description {
     return $self->lib_opac() || $self->lib();
 }
 
+=head3 translated_description
+
+=cut
+
+sub translated_description {
+    my ( $self, $lang ) = @_;
+    if ( my $translated_description = eval { $self->get_column('translated_description') } ) {
+        # If the value has already been fetched (eg. from sarch_with_localization),
+        # do not search for it again
+        # Note: This is a bit hacky but should be fast
+        return $translated_description
+             ? $translated_description
+             : $self->lib;
+    }
+    $lang ||= C4::Languages::getlanguage;
+    my $translated_description = Koha::Localizations->search({
+        code => $self->authorised_value,
+        entity => 'avs',
+        lang => $lang
+    })->next;
+    return $translated_description
+         ? $translated_description->translation
+         : $self->lib;
+}
+
+=head3 translated_descriptions
+
+=cut
+
+sub translated_descriptions {
+    my ( $self ) = @_;
+    my @translated_descriptions = Koha::Localizations->search(
+        {   entity => 'avs',
+            code   => $self->authorised_value,
+        }
+    );
+    return [ map {
+        {
+            lang => $_->lang,
+            translation => $_->translation,
+        }
+    } @translated_descriptions ];
+}
+
+=head3 image_location
+
+=cut
+
+sub image_location {
+    my ( $self, $interface ) = @_;
+    return C4::Koha::getitemtypeimagelocation( $interface, $self->SUPER::imageurl );
+}
+
 =head3 _avb_resultset
 
 Returns the internal resultset or creates it if undefined
diff --git a/Koha/AuthorisedValues.pm b/Koha/AuthorisedValues.pm
index 5c73052802..bab3e0ce18 100644
--- a/Koha/AuthorisedValues.pm
+++ b/Koha/AuthorisedValues.pm
@@ -60,7 +60,10 @@ sub search {
         ]
       }
       : {};
-    my $join = $branchcode ? { join => 'authorised_values_branches' } : {};
+
+    my @join = $attributes->{join} || ();
+    push @join, 'authorised_values_branches';
+    my $join = { join => \@join };
     $attributes //= {};
     $attributes = { %$attributes, %$join };
     return $self->SUPER::search( { %$params, %$or, }, $attributes );
@@ -108,7 +111,7 @@ sub find_by_koha_field {
     my $kohafield        = $params->{kohafield};
     my $authorised_value = $params->{authorised_value};
 
-    my $av = $self->SUPER::search(
+    my $av = $self->search(
         {   'marc_subfield_structures.frameworkcode' => $frameworkcode,
             'marc_subfield_structures.kohafield'     => $kohafield,
             'me.authorised_value'                    => $authorised_value,
@@ -175,6 +178,29 @@ sub categories {
     return map $_->get_column('category'), $rs->all;
 }
 
+=head3 search_with_localization
+
+my $avs = Koha::AuthorisedValues->search_with_localization
+
+=cut
+
+sub search_with_localization {
+    my ( $self, $params, $attributes ) = @_;
+
+    my $language = C4::Languages::getlanguage();
+    $Koha::Schema::Result::AuthorisedValue::LANGUAGE = $language;
+    $attributes->{order_by} = 'translated_description' unless exists $attributes->{order_by};
+    $attributes->{join} = 'localization';
+    $attributes->{'+select'} = [
+        {
+            coalesce => [qw( localization.translation me.lib )],
+            -as      => 'translated_description'
+        }
+    ];
+    $self->search( $params, $attributes );
+}
+
+
 =head3 type
 
 =cut
diff --git a/Koha/Schema/Result/AuthorisedValue.pm b/Koha/Schema/Result/AuthorisedValue.pm
index 1a65d388c9..09acafc5e4 100644
--- a/Koha/Schema/Result/AuthorisedValue.pm
+++ b/Koha/Schema/Result/AuthorisedValue.pm
@@ -148,6 +148,21 @@ __PACKAGE__->has_many(
 # Created by DBIx::Class::Schema::Loader v0.07046 @ 2019-02-22 14:32:48
 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hDlebhEn+f+thqwBo/LOqQ
 
+# Use the ItemtypeLocalization view to create the join on localization
+our $LANGUAGE;
+__PACKAGE__->has_many(
+  "localization" => "Koha::Schema::Result::AuthorisedValueLocalization",
+    sub {
+        my $args = shift;
+
+        die "no lang specified!" unless $LANGUAGE;
+
+        return ({
+            "$args->{self_alias}.authorised_value" => { -ident => "$args->{foreign_alias}.code" },
+            "$args->{foreign_alias}.lang" => $LANGUAGE,
+        });
+
+    }
+);
 
-# You can replace this text with custom code or comments, and it will be preserved on regeneration
 1;
diff --git a/Koha/Schema/Result/AuthorisedValueLocalization.pm b/Koha/Schema/Result/AuthorisedValueLocalization.pm
new file mode 100644
index 0000000000..fa2c69662b
--- /dev/null
+++ b/Koha/Schema/Result/AuthorisedValueLocalization.pm
@@ -0,0 +1,32 @@
+package Koha::Schema::Result::AuthorisedValueLocalization;
+
+use base 'DBIx::Class::Core';
+
+use Modern::Perl;
+
+__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
+
+__PACKAGE__->table('authorised_value_localizations');
+__PACKAGE__->result_source_instance->is_virtual(1);
+__PACKAGE__->result_source_instance->view_definition(
+    "SELECT localization_id, code, lang, translation FROM localization WHERE entity='avs'"
+);
+
+__PACKAGE__->add_columns(
+  "localization_id",
+  { data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
+  "code",
+  { data_type => "varchar", is_nullable => 0, size => 64 },
+  "lang",
+  { data_type => "varchar", is_nullable => 0, size => 25 },
+  "translation",
+  { data_type => "text", is_nullable => 1 },
+);
+
+__PACKAGE__->belongs_to(
+    "authorised_value",
+    "Koha::Schema::Result::AuthorisedValue",
+    { code => 'authorised_value' }
+);
+
+1;
diff --git a/admin/authorised_values.pl b/admin/authorised_values.pl
index 4f951291e4..4fa66bf33c 100755
--- a/admin/authorised_values.pl
+++ b/admin/authorised_values.pl
@@ -24,6 +24,7 @@ use C4::Auth;
 use C4::Context;
 use C4::Koha;
 use C4::Output;
+use Carp::Always;
 
 use Koha::AuthorisedValues;
 use Koha::AuthorisedValueCategories;
@@ -91,8 +92,11 @@ if ($op eq 'add_form') {
             imagesets => C4::Koha::getImageSets(),
         );
     }
+
+    my $translated_languages = C4::Languages::getTranslatedLanguages( undef , C4::Context->preference('template') );
     $template->param(
         branches_loop    => \@branches_loop,
+        can_be_translated => ( scalar(@$translated_languages) > 1 ? 1 : 0 ),
     );
 
 } elsif ($op eq 'add') {
@@ -220,23 +224,10 @@ if ( $op eq 'list' ) {
 
     $searchfield ||= $category_list[0];
 
-    my @avs_by_category = Koha::AuthorisedValues->new->search( { category => $searchfield } );
-    my @loop_data = ();
-    # builds value list
-    for my $av ( @avs_by_category ) {
-        my %row_data;  # get a fresh hash for the row data
-        $row_data{category}              = $av->category;
-        $row_data{authorised_value}      = $av->authorised_value;
-        $row_data{lib}                   = $av->lib;
-        $row_data{lib_opac}              = $av->lib_opac;
-        $row_data{imageurl}              = getitemtypeimagelocation( 'intranet', $av->imageurl );
-        $row_data{branches}              = $av->branch_limitations;
-        $row_data{id}                    = $av->id;
-        push(@loop_data, \%row_data);
-    }
+    my $avs_by_category = Koha::AuthorisedValues->search_with_localization( { category => $searchfield } );
 
     $template->param(
-        loop     => \@loop_data,
+        authorised_values => $avs_by_category,
         category => $searchfield,
         categories => \@category_list,
     );
diff --git a/admin/localization.pl b/admin/localization.pl
index f8bc553c05..368a3f5292 100755
--- a/admin/localization.pl
+++ b/admin/localization.pl
@@ -40,25 +40,17 @@ my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
 
 my $entity = $query->param('entity');
 my $code   = $query->param('code');
-my $rs     = Koha::Localizations->search( { entity => $entity, code => $code } );
-my @translations;
-while ( my $s = $rs->next ) {
-    push @translations,
-      { id          => $s->localization_id,
-        entity      => $s->entity,
-        code        => $s->code,
-        lang        => $s->lang,
-        translation => $s->translation,
-      };
-}
+my $interface = $query->param('interface');
+my $translations = Koha::Localizations->search( { entity => $entity, code => $code, interface => $interface } );
 
 my $translated_languages = C4::Languages::getTranslatedLanguages( 'intranet', C4::Context->preference('template') );
 
 $template->param(
-    translations => \@translations,
+    translations => $translations,
     languages    => $translated_languages,
     entity       => $entity,
     code         => $code,
+    interface_side => $interface, # "interface" conflicts with existing variable's name
 );
 
 output_html_with_http_headers $query, $cookie, $template->output;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt
index 6ec9973a20..04c25bf536 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/authorised_values.tt
@@ -74,11 +74,16 @@
         </li>
         <li>
             <label for="lib">Description: </label>
-            <input type="text" name="lib" id="lib" value="[% lib | html %]" maxlength="200" />
+            [% IF can_be_translated %]
+                <a href="/cgi-bin/koha/admin/localization.pl?entity=avs&code=[% authorised_value | uri %]&interface=intranet"" title="Translate description" rel="gb_page_center[600,500]"><i class="fa fa-pencil"></i> Translate into other languages</a>
+            [% END %]
         </li>
 	<li>
             <label for="lib_opac">Description (OPAC): </label>
             <input type="text" name="lib_opac" id="lib_opac" value="[% lib_opac | html %]" maxlength="200" />
+            [% IF can_be_translated %]
+                <a href="/cgi-bin/koha/admin/localization.pl?entity=avs&code=[% authorised_value | uri %]&interface=opac" title="Translate OPAC description" rel="gb_page_center[600,500]"><i class="fa fa-pencil"></i> Translate into other languages</a>
+            [% END %]
         </li>
         <li><label for="branches">Libraries limitation: </label>
             <select id="branches" name="branches" multiple size="10">
@@ -207,7 +212,7 @@
         </p>
     </form>
 
-    [% IF loop %]
+    [% IF authorised_values.count %]
 
     <table id="table_authorized_values" class="authorized_values_table">
     <thead><tr>
@@ -219,30 +224,43 @@
         <th>Actions</th>
         </tr>
     </thead><tbody>
-    [% FOREACH loo IN loop %]
+    [% FOREACH av IN authorised_values %]
     <tr>
-        <td>[% loo.authorised_value | html %]</td>
-        <td>[% loo.lib | html %]</td>
-        <td>[% loo.lib_opac | html %]</td>
-        <td>[% IF ( loo.imageurl ) %]<img src="[% loo.imageurl | url %]" alt=""/>[% ELSE %]&nbsp;[% END %]</td>
+        <td>[% av.authorised_value | html %]</td>
+        [% IF av.translated_descriptions.size %]
+            [% av.lib | html %] (default)<br/>
+            [% FOR description IN av.translated_descriptions %]
+                [% IF description.translation == av.translated_description %]
+                    <b>[% description.translation | html %]</b>
+                [% ELSE %]
+                    [% description.translation | html %] ([% description.lang | html %])
+                [% END %]
+                <br/>
+            [% END %]
+        [% ELSE %]
+            [% av.lib |html %]
+        [% END %]
+
+        <td>[% av.lib_opac | html %]</td>
+        <td>[% IF ( av.imageurl ) %]<img src="[% av.imageurl | url %]" alt=""/>[% ELSE %]&nbsp;[% END %]</td>
         <td>
-            [% IF loo.branches.size > 0 %]
+            [% IF av.branch_limitations.size > 0 %]
                 [% branches_str = "" %]
-                [% FOREACH branch IN loo.branches %]
+                [% FOREACH branch IN av.branches_limitation %]
                     [% branches_str = branches_str _ " " _ branch.branchname _ "(" _ branch.branchcode _ ")" %]
                 [% END %]
                 <span href="#" title="[% branches_str | html %]">
-                    [% IF loo.branches.size > 1 %]
-                        [% loo.branches.size | html %] branches limitations
+                    [% IF av.branches.size > 1 %]
+                        [% av.branches_limitaion.size | html %] branches limitations
                     [% ELSE %]
-                        [% loo.branches.size | html %] branch limitation
+                        [% av.branches_limitation.size | html %] branch limitation
                     [% END %]
             [% ELSE %]
                 No limitation
             [% END %]
         </td>
-        <td class="actions"><a href="/cgi-bin/koha/admin/authorised_values.pl?op=add_form&amp;id=[% loo.id | uri %]" class="btn btn-default btn-xs"><i class="fa fa-pencil"></i> Edit</a>
-        <a class="delete btn btn-default btn-xs" href="/cgi-bin/koha/admin/authorised_values.pl?op=delete&amp;searchfield=[% searchfield | uri %]&amp;id=[% loo.id | uri %]"><i class="fa fa-trash"></i> Delete</a></td>
+        <td class="actions"><a href="/cgi-bin/koha/admin/authorised_values.pl?op=add_form&amp;id=[% av.id | uri %]" class="btn btn-default btn-xs"><i class="fa fa-pencil"></i> Edit</a>
+        <a class="delete btn btn-default btn-xs" href="/cgi-bin/koha/admin/authorised_values.pl?op=delete&amp;searchfield=[% searchfield | uri %]&amp;id=[% av.id | uri %]"><i class="fa fa-trash"></i> Delete</a></td>
     </tr>
     [% END # /FOREACH loop %]
     </tbody></table>
@@ -297,6 +315,7 @@
 
 [% MACRO jsinclude BLOCK %]
     [% Asset.js("js/admin-menu.js") | $raw %]
+    [% INCLUDE 'greybox.inc' %]
     [% INCLUDE 'datatables.inc' %]
     <script>
         $(document).ready(function() {
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt
index 6952ba03ab..918670fd9e 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/localization.tt
@@ -11,6 +11,7 @@
 <form id="add_translation" method="post">
     <input type="hidden" name="entity" value="[% entity | html %]" />
     <input type="hidden" name="code" value="[% code | html %]" />
+    <input type="hidden" name="interface" value="[% interface_side | html %]" />
     Lang: <select name="lang">
         [% FOR language IN languages %]
             [% FOR sublanguage IN language.sublanguages_loop %]
@@ -211,9 +212,10 @@
                 e.preventDefault();
                 var entity = $(this).find('input[name="entity"]').val();
                 var code = $(this).find('input[name="code"]').val();
+                var interface = $(this).find('input[name="interface"]').val();
                 var lang = $(this).find('select[name="lang"] option:selected').val();
                 var translation = $(this).find('input[name="translation"]').val();
-                var data = "entity=" + encodeURIComponent(entity) + "&code=" + encodeURIComponent(code) + "&lang=" + encodeURIComponent(lang) + "&translation=" + encodeURIComponent(translation);
+                var data = "entity=" + encodeURIComponent(entity) + "&code=" + encodeURIComponent(code) + "&interface=" + encodeURIComponent(interface) + "&lang=" + encodeURIComponent(lang) + "&translation=" + encodeURIComponent(translation);
                 $.ajax({
                     data: data,
                     type: 'POST',
diff --git a/svc/localization b/svc/localization
index 6eed60632c..02ec33f7d5 100755
--- a/svc/localization
+++ b/svc/localization
@@ -9,18 +9,14 @@ use Koha::Localizations;
 our ( $query, $response ) = C4::Service->init( parameters => 'manage_itemtypes' );
 
 sub get_translations {
-    my $rs = Koha::Localizations->search({ entity => $query->param('entity'), code => $query->param('code') });
-    my @translations;
-    while ( my $s = $rs->next ) {
-        push @translations, {
-              id          => $s->localization_id,
-              entity      => $s->entity,
-              code        => $s->code,
-              lang        => $s->lang,
-              translation => $s->translation,
+    my $translations = Koha::Localizations->search(
+        {
+            entity    => $query->param('entity'),
+            code      => $query->param('code'),
+            interface => $query->param('interface')
         }
-    }
-    $response->param( translations => \@translations );
+    );
+    $response->param( translations => $translations );
     C4::Service->return_success( $response );
 }
 
@@ -64,13 +60,15 @@ sub add_translation {
     my $code = $query->param('code');
     my $lang = $query->param('lang');
     my $translation = $query->param('translation');
+    my $interface = $query->param('interface') || undef;
 
-    unless ( Koha::Localizations->search({entity => $entity, code => $code, lang => $lang, })->count ) {
+    unless ( Koha::Localizations->search({entity => $entity, code => $code, interface => $interface, lang => $lang })->count ) {
         my $localization = Koha::Localization->new(
             {
-                entity => $entity,
-                code => $code,
-                lang => $lang,
+                entity      => $entity,
+                interface   => $interface,
+                code        => $code,
+                lang        => $lang,
                 translation => $translation,
             }
         );
@@ -78,6 +76,7 @@ sub add_translation {
         $response->param(
             id          => $localization->localization_id,
             entity      => $localization->entity,
+            interface   => $localization->interface,
             code        => $localization->code,
             lang        => $localization->lang,
             translation => $localization->translation,
-- 
2.11.0