Bug 5202: merge authorities from the authority file and reservoir
authorJared Camins-Esakov <jcamins@cpbibliography.com>
Sat, 11 May 2013 20:11:38 +0000 (16:11 -0400)
committerGalen Charlton <gmc@esilibrary.com>
Thu, 10 Oct 2013 21:32:27 +0000 (21:32 +0000)
This patch gives Koha the ability to merge authority records using the
same interface used by bibliographic records, though slightly different
methods for selecting which records to merge. The two ways to select
records are as follows:

1) Records can be selected from authority search results by clicking
   the "Merge" link for two records.
2) Authority records can be merged from the reservoir by clicking the
   merge-related links in the Manage staged MARC batch screen.

To test:
1) Apply patch.
2) Do a search for an authority record that will turn up multiple
   identical records (or at least two records that you don't mind
   merging).
3) Click the "Merge" link for the first record.
4) Click the "Merge" link for the second record.
5) Choose which fields from which record you want to appear in the
   resulting record.
6) Confirm that those are the fields that exist in the resulting record.
7) Stage an authority record (for example, an authority record you
   saved from your catalog.
8) Search for a record to merge with it using the "Search for a record
   to merge in a new window" link.
9) Merge these records, confirming that the resulting record (after
   going through the entire merging process) matches your expectations.
10) Set up a matching rule for authorities, and export an authority from
    your catalog that will match based on that rule. For MARC21, the
    following is a good choice for a rule:
    Matching rule code:  AUTHPER
    Description:         Personal name main entry
    Match threshold:     999
    Record type:         Authority record
    [Match point 1:]
    Search index:   mainmainentry
    Score:          1000
    Tag:            100
    Subfields:      a
11) Stage the record you just exported, choosing the matching rule you
    just created.
12) Merge the record using the "Merge" link, confirming that the
    resulting record (after going through the entire merging process)
    matches your expectations.

Signed-off-by: Chris Cormack <chrisc@catalyst.net.nz>
Signed-off-by: Katrin Fischer <Katrin.Fischer.83@web.de>
Testing notes on last patch in series.

Signed-off-by: Galen Charlton <gmc@esilibrary.com>

Koha/Authority.pm
Koha/Util/MARC.pm
authorities/merge.pl [new file with mode: 0755]
authorities/merge_ajax.pl [new file with mode: 0755]
koha-tmpl/intranet-tmpl/prog/en/includes/authorities_js.inc [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/authorities/authorities-home.tt
koha-tmpl/intranet-tmpl/prog/en/modules/authorities/merge.tt [new file with mode: 0644]
koha-tmpl/intranet-tmpl/prog/en/modules/authorities/searchresultlist.tt
koha-tmpl/intranet-tmpl/prog/en/modules/tools/manage-marc-import.tt
t/Koha_Util_MARC.t
t/db_dependent/Koha_Authority.t

index 509fe3f..7405936 100644 (file)
@@ -37,6 +37,7 @@ use C4::Context;
 use MARC::Record;
 use MARC::File::XML;
 use C4::Charset;
+use Koha::Util::MARC;
 
 use base qw(Koha::MetadataRecord);
 
@@ -53,7 +54,12 @@ sub new {
     my $class = shift;
     my $record = shift;
 
-    my $self = $class->SUPER::new( { record => $record });
+    my $self = $class->SUPER::new(
+        {
+            'record' => $record,
+            'schema' => lc C4::Context->preference("marcflavour")
+        }
+    );
 
     bless $self, $class;
     return $self;
@@ -84,6 +90,13 @@ sub get_from_authid {
     return if ($@);
     $record->encoding('UTF-8');
 
+    # NOTE: GuessAuthTypeCode has no business in Koha::Authority, which is an
+    #       object-oriented class. Eventually perhaps there will be utility
+    #       classes in the Koha:: namespace, but there are not at the moment,
+    #       so this shim seems like the best option all-around.
+    require C4::AuthoritiesMarc;
+    $authtypecode ||= C4::AuthoritiesMarc::GuessAuthTypeCode($record);
+
     my $self = $class->SUPER::new( { authid => $authid,
                                      authtype => $authtypecode,
                                      schema => $marcflavour,
@@ -93,4 +106,49 @@ sub get_from_authid {
     return $self;
 }
 
+=head2 get_from_breeding
+
+    my $auth = Koha::Authority->get_from_authid($authid);
+
+Create the Koha::Authority object associated with the provided authid.
+
+=cut
+sub get_from_breeding {
+    my $class = shift;
+    my $import_record_id = shift;
+    my $marcflavour = lc C4::Context->preference("marcflavour");
+
+    my $dbh=C4::Context->dbh;
+    my $sth=$dbh->prepare("select marcxml from import_records where import_record_id=? and record_type='auth';");
+    $sth->execute($import_record_id);
+    my $marcxml = $sth->fetchrow;
+    my $record=eval {MARC::Record->new_from_xml(StripNonXmlChars($marcxml),'UTF-8',
+        (C4::Context->preference("marcflavour") eq "UNIMARC"?"UNIMARCAUTH":C4::Context->preference("marcflavour")))};
+    return if ($@);
+    $record->encoding('UTF-8');
+
+    # NOTE: GuessAuthTypeCode has no business in Koha::Authority, which is an
+    #       object-oriented class. Eventually perhaps there will be utility
+    #       classes in the Koha:: namespace, but there are not at the moment,
+    #       so this shim seems like the best option all-around.
+    require C4::AuthoritiesMarc;
+    my $authtypecode = C4::AuthoritiesMarc::GuessAuthTypeCode($record);
+
+    my $self = $class->SUPER::new( {
+                                     schema => $marcflavour,
+                                     authtype => $authtypecode,
+                                     record => $record });
+
+    bless $self, $class;
+    return $self;
+}
+
+sub authorized_heading {
+    my ($self) = @_;
+    if ($self->schema =~ m/marc/) {
+        return Koha::Util::MARC::getAuthorityAuthorizedHeading($self->record, $self->schema);
+    }
+    return;
+}
+
 1;
index fc3c9f2..500ba53 100644 (file)
@@ -106,4 +106,73 @@ sub _createKey {
     return int(rand(1000000));
 }
 
+=head2 getAuthorityAuthorizedHeading
+
+Retrieve the authorized heading from a MARC authority record
+
+=cut
+
+sub getAuthorityAuthorizedHeading {
+    my ( $record, $schema ) = @_;
+    return unless ( ref $record eq 'MARC::Record' );
+    if ( $schema eq 'unimarc' ) {
+
+        # construct UNIMARC summary, that is quite different from MARC21 one
+        # accepted form
+        foreach my $field ( $record->field('2..') ) {
+            return $field->as_string('abcdefghijlmnopqrstuvwxyz');
+        }
+    }
+    else {
+        foreach my $field ( $record->field('1..') ) {
+            my $tag = $field->tag();
+            next if "152" eq $tag;
+
+            # FIXME - 152 is not a good tag to use
+            # in MARC21 -- purely local tags really ought to be
+            # 9XX
+            if ( $tag eq '100' ) {
+                return $field->as_string('abcdefghjklmnopqrstvxyz68');
+            }
+            elsif ( $tag eq '110' ) {
+                return $field->as_string('abcdefghklmnoprstvxyz68');
+            }
+            elsif ( $tag eq '111' ) {
+                return $field->as_string('acdefghklnpqstvxyz68');
+            }
+            elsif ( $tag eq '130' ) {
+                return $field->as_string('adfghklmnoprstvxyz68');
+            }
+            elsif ( $tag eq '148' ) {
+                return $field->as_string('abvxyz68');
+            }
+            elsif ( $tag eq '150' ) {
+                return $field->as_string('abvxyz68');
+            }
+            elsif ( $tag eq '151' ) {
+                return $field->as_string('avxyz68');
+            }
+            elsif ( $tag eq '155' ) {
+                return $field->as_string('abvxyz68');
+            }
+            elsif ( $tag eq '180' ) {
+                return $field->as_string('vxyz68');
+            }
+            elsif ( $tag eq '181' ) {
+                return $field->as_string('vxyz68');
+            }
+            elsif ( $tag eq '182' ) {
+                return $field->as_string('vxyz68');
+            }
+            elsif ( $tag eq '185' ) {
+                return $field->as_string('vxyz68');
+            }
+            else {
+                return $field->as_string();
+            }
+        }
+    }
+    return;
+}
+
 1;
diff --git a/authorities/merge.pl b/authorities/merge.pl
new file mode 100755 (executable)
index 0000000..0e3fb6d
--- /dev/null
@@ -0,0 +1,186 @@
+#!/usr/bin/perl
+
+# Copyright 2013 C & P Bibliography Services
+#
+# 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 2 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+use CGI;
+use C4::Output;
+use C4::Auth;
+use C4::AuthoritiesMarc;
+use Koha::Authority;
+use C4::Koha;
+use C4::Biblio;
+
+my $input  = new CGI;
+my @authid = $input->param('authid');
+my $merge  = $input->param('merge');
+
+my @errors;
+
+my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+    {
+        template_name   => "authorities/merge.tt",
+        query           => $input,
+        type            => "intranet",
+        authnotrequired => 0,
+        flagsrequired   => { editauthorities => 1 },
+    }
+);
+
+#------------------------
+# Merging
+#------------------------
+if ($merge) {
+
+    # Creating a new record from the html code
+    my $record   = TransformHtmlToMarc($input);
+    my $recordid1   = $input->param('recordid1');
+    my $recordid2   = $input->param('recordid2');
+    my $typecode = $input->param('frameworkcode');
+
+    # Rewriting the leader
+    $record->leader( GetAuthority($recordid1)->leader() );
+
+    # Modifying the reference record
+    ModAuthority( $recordid1, $record, $typecode );
+
+    # Deleting the other record
+    if ( scalar(@errors) == 0 ) {
+
+        my $error;
+        if ($input->param('mergereference') eq 'breeding') {
+            require C4::ImportBatch;
+            C4::ImportBatch::SetImportRecordStatus( $recordid2, 'imported' );
+        } else {
+            $error = (DelAuthority($recordid2) == 0);
+        }
+        push @errors, $error if ($error);
+    }
+
+    # Parameters
+    $template->param(
+        result  => 1,
+        recordid1 => $recordid1
+    );
+
+    #-------------------------
+    # Show records to merge
+    #-------------------------
+}
+else {
+    my $mergereference = $input->param('mergereference');
+    $template->{'VARS'}->{'mergereference'} = $mergereference;
+
+    if ( scalar(@authid) != 2 ) {
+        push @errors, { code => "WRONG_COUNT", value => scalar(@authid) };
+    }
+    else {
+        my $recordObj1 = Koha::Authority->get_from_authid($authid[0]) || Koha::Authority->new();
+        my $recordObj2;
+
+        if ($mergereference eq 'breeding') {
+            $recordObj2 =  Koha::Authority->get_from_breeding($authid[1]) || Koha::Authority->new();
+            $mergereference = $authid[0];
+        } else {
+            $recordObj2 =  Koha::Authority->get_from_authid($authid[1]) || Koha::Authority->new();
+        }
+
+        if ($mergereference) {
+
+            my $framework;
+            if ( $recordObj1->authtype ne $recordObj2->authtype && $mergereference ne 'breeding' ) {
+                $framework = $input->param('frameworkcode')
+                  or push @errors, "Framework not selected.";
+            }
+            else {
+                $framework = $recordObj1->authtype;
+            }
+
+            # Getting MARC Structure
+            my $tagslib = GetTagsLabels( 1, $framework );
+
+            my $notreference =
+              ( $authid[0] == $mergereference )
+              ? $authid[1]
+              : $authid[0];
+
+            # Creating a loop for display
+
+            my @record1 = $recordObj1->createMergeHash($tagslib);
+            my @record2 = $recordObj2->createMergeHash($tagslib);
+
+            # Parameters
+            $template->param(
+                recordid1        => $mergereference,
+                recordid2        => $notreference,
+                record1        => @record1,
+                record2        => @record2,
+                framework      => $framework,
+            );
+        }
+        else {
+
+            # Ask the user to choose which record will be the kept
+            $template->param(
+                choosereference => 1,
+                recordid1         => $authid[0],
+                recordid2         => $authid[1],
+                title1          => $recordObj1->authorized_heading,
+                title2          => $recordObj2->authorized_heading,
+            );
+            if ( $recordObj1->authtype ne $recordObj2->authtype ) {
+                my $frameworks = getauthtypes;
+                my @frameworkselect;
+                foreach my $thisframeworkcode ( keys %$frameworks ) {
+                    my %row = (
+                        value => $thisframeworkcode,
+                        frameworktext =>
+                          $frameworks->{$thisframeworkcode}->{'authtypetext'},
+                    );
+                    if ( $recordObj1->authtype eq $thisframeworkcode ) {
+                        $row{'selected'} = 1;
+                    }
+                    push @frameworkselect, \%row;
+                }
+                $template->param(
+                    frameworkselect => \@frameworkselect,
+                    frameworkcode1  => $recordObj1->authtype,
+                    frameworkcode2  => $recordObj2->authtype,
+                );
+            }
+        }
+    }
+}
+
+if (@errors) {
+
+    # Errors
+    $template->param( errors => \@errors );
+}
+
+output_html_with_http_headers $input, $cookie, $template->output;
+exit;
+
+=head1 FUNCTIONS
+
+=cut
+
+# ------------------------
+# Functions
+# ------------------------
diff --git a/authorities/merge_ajax.pl b/authorities/merge_ajax.pl
new file mode 100755 (executable)
index 0000000..dd716a7
--- /dev/null
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use CGI;
+use CGI::Session;
+use C4::Context;
+use C4::Auth qw/check_cookie_auth/;
+use C4::AuthoritiesMarc;
+use JSON;
+use CGI::Cookie; # need to check cookies before
+                 # having CGI parse the POST request
+
+my %cookies = fetch CGI::Cookie;
+my ($auth_status, $sessionID) = check_cookie_auth($cookies{'CGISESSID'}->value, { editcatalogue => 'edit_catalogue' });
+if ($auth_status ne "ok") {
+    my $reply = CGI->new("");
+    print $reply->header(-type => 'text/html');
+    exit 0;
+}
+
+my $reply = new CGI;
+my $framework = $reply->param('frameworkcode');
+my $tagslib = GetTagsLabels(1, $framework);
+print $reply->header(-type => 'text/html');
+print encode_json $tagslib;
diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/authorities_js.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/authorities_js.inc
new file mode 100644 (file)
index 0000000..d1964d1
--- /dev/null
@@ -0,0 +1,38 @@
+function mergeAuth(authid, summary) {
+    var alreadySelected = $.cookie('auth_to_merge');
+    if (alreadySelected !== null) {
+        alreadySelected = JSON.parse(alreadySelected);
+        $.cookie('auth_to_merge', '', { 'path': '/', 'expires': -1 });
+        var refstring = "";
+        if (typeof alreadySelected.mergereference !== 'undefined') {
+            refstring = "&mergereference=" + alreadySelected.mergereference;
+        }
+        window.location.href = "/cgi-bin/koha/authorities/merge.pl?authid=" + authid + "&authid=" + alreadySelected.authid + refstring;
+    } else {
+        $.cookie('auth_to_merge', JSON.stringify({ 'authid': authid, 'summary': summary }), { 'path' : '/' });
+        showMergingInProgress();
+    }
+}
+
+function showMergingInProgress() {
+    var alreadySelected = $.cookie('auth_to_merge');
+    if (alreadySelected !== null) {
+        alreadySelected = JSON.parse(alreadySelected);
+        $('#merge_in_progress').html(_("Merging with authority: ") + "<a href='detail.pl?authid=" + alreadySelected.authid + "'><span class='authorizedheading'>" + alreadySelected.summary + "</span> (" + alreadySelected.authid + ")</a> <a href='#' id='cancel_merge'>" + _("Cancel merge") + "</a>");
+        $('#cancel_merge').click(function(event) {
+            event.preventDefault();
+            $.cookie('auth_to_merge', '', { 'path': '/', 'expires': -1 });
+            $('#merge_in_progress').empty();
+        });
+    } else {
+        $('#merge_in_progress').empty();
+    }
+}
+
+$(document).ready(function () {
+    showMergingInProgress();
+    $('.merge_auth').click(function (event) {
+        event.preventDefault();
+        mergeAuth($(this).parents('tr').attr('data-authid'), $(this).parents('tr').find('div.authorizedheading').text());
+    });
+});
index 7d138ff..558746e 100644 (file)
@@ -19,6 +19,7 @@ function searchauthority() {
 function confirm_deletion() {   // not really implemented, but required by phantom delAuthButton code in authorities-toolbar.inc
     return true;
 }
+[% INCLUDE 'authorities_js.inc' %]
 //]]>
 </script>
 </head>
@@ -35,6 +36,8 @@ function confirm_deletion() {   // not really implemented, but required by phant
     
     [% INCLUDE 'authorities-toolbar.inc' %]
 
+    <div id="merge_in_progress"></div>
+
     </div>
     </div>
   </div>
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/authorities/merge.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/authorities/merge.tt
new file mode 100644 (file)
index 0000000..d201a22
--- /dev/null
@@ -0,0 +1,143 @@
+[% PROCESS 'merge-record.inc' %]
+[% INCLUDE 'doc-head-open.inc' %]
+<title>Koha &rsaquo; Cataloging &rsaquo; Merging records</title>
+[% INCLUDE 'greybox.inc' %]
+[% INCLUDE 'doc-head-close.inc' %]
+<style type="text/css">
+div.record ul, div.record li { float:none; display:block; }
+div#result { margin-top: 1em; }
+/* We use this style "against" the li ui-tabs-nav style automatically applied */
+</style>
+<script type="text/javascript">
+//<![CDATA[
+
+    // When submiting the form
+    function mergeformsubmit() {
+        $("ul#ulrecord1").remove();
+        $("ul#ulrecord2").remove();
+}
+
+$(document).ready(function(){
+    // Getting marc structure via ajax
+    tagslib = [];
+    $.getJSON("/cgi-bin/koha/authorities/merge_ajax.pl", {frameworkcode : "[% framework %]" }, function(json) {
+        tagslib = json;
+    });
+    [% PROCESS mergejs %]
+});
+
+
+function changeFramework(fw) {
+    $("#Frameworks").val(fw);
+}
+
+//]]>
+</script>
+</head>
+<body id="auth_merge" class="cat">
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'authorities-search.inc' %]
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/authorities/authorities-home.pl">Authorities</a>  &rsaquo; Merging records</div>
+
+<div id="doc" class="yui-t7">
+
+<div id="bd">
+        <div id="yui-main">
+
+
+<h1>Merging records</h1>
+[% IF ( result ) %]
+    [% IF ( errors ) %]
+
+    [% FOREACH error IN errors %]
+        <div class="dialog alert">
+
+                [% IF error.code == 'CANNOT_MOVE' %]
+                    The following items could not be moved from the old record to the new one: [% error.value %]
+                [% ELSE %]
+                    [% error %]
+                [% END %]
+
+            <br />Therefore, the record to be merged has not been deleted.</div>
+    [% END %]
+
+    [% ELSE %]
+        <script type="text/javascript">window.location.href="/cgi-bin/koha/authorities/detail.pl?authid=[% recordid1 %]"</script>
+        <p>The merging was successful. <a href="/cgi-bin/koha/authorities/detail.pl?authid=[% recordid1 %]">Click here to see the merged record.</a></p>
+    [% END %]
+
+[% ELSE %]
+
+[% IF ( choosereference ) %]
+<p>Please choose which record will be the reference for the merge. The record chosen as reference will be kept, and the other will be deleted.</p>
+<form id="mergeform" action="/cgi-bin/koha/authorities/merge.pl" method="post">
+    <fieldset class="rows">
+    <legend>Merge reference</legend>
+    <ol>
+    <li class="radio"><input type="radio" value="[% recordid1 %]" checked="checked" id="mergereference1" name="mergereference" onclick="changeFramework('[% frameworkcode1 %]')" /><label for="mergereference1">[% title1 %] [% FOREACH subtitl1 IN subtitle1 %] [% subtitl1.subfield %][% END %] (<a href="/cgi-bin/koha/catalogue/showmarc.pl?id=[% recordid1 %]" title="MARC" rel="gb_page_center[600,500]">[% recordid1 %]</a>)</label></li>
+    <li class="radio"><input type="radio" value="[% recordid2 %]" id="mergereference2" name="mergereference" onclick="changeFramework('[% frameworkcode2 %]')" /><label for="mergereference2">[% title2 %] [% FOREACH subtitl2 IN subtitle2 %] [% subtitl2.subfield %][% END %] (<a href="/cgi-bin/koha/catalogue/showmarc.pl?id=[% recordid2 %]" title="MARC" rel="gb_page_center[600,500]">[% recordid2 %]</a>)</label></li>
+
+    [% IF frameworkselect %]
+          <li><label for="frameworkcode">Using framework:</label>
+                      <select name="frameworkcode" id="frameworkcode">
+                                      <option value="Default">Default</option>
+                                      [% FOREACH frameworkcodeloo IN frameworkselect %]
+                                          [% IF ( frameworkcodeloo.selected ) %]
+                                              <option value="[% frameworkcodeloo.value %]" selected="selected">
+                                          [% ELSE %]
+                                              <option value="[% frameworkcodeloo.value %]">
+                                          [% END %]
+                                           [% frameworkcodeloo.frameworktext %]
+                                           </option>
+                                      [% END %]
+                      </select></li>
+    [% END %]
+</ol>
+
+    <input type="hidden" name="authid" value="[% recordid1 %]" />
+    <input type="hidden" name="authid" value="[% recordid2 %]" />
+    <fieldset class="action"><input type="submit" value="Next" /></fieldset>
+    </fieldset>
+</form>
+[% ELSE %]
+[% IF ( errors ) %]
+    <div class="dialog alert">
+    [% FOREACH error IN errors %]
+        <p>
+                [% IF error.code == 'WRONG_COUNT' %]
+                    Number of records provided for merging: [% error.value %]. Currently only 2 records can be merged at a time.
+                [% ELSE %]
+                    [% error %]
+                [% END %]
+
+            </p>
+    [% END %]
+    </div>
+[% ELSE %]
+<form id="mergeform" action="/cgi-bin/koha/authorities/merge.pl" method="post" onsubmit="return mergeformsubmit()">
+
+<div class="yui-g">
+<div class="yui-u first">
+[% PROCESS mergesource %]
+</div>
+<div class="yui-u">
+[% PROCESS mergetarget %]
+</div> <!-- .yui-u -->
+
+<input type="hidden" name="recordid1" value="[% recordid1 %]" />
+<input type="hidden" name="recordid2" value="[% recordid2 %]" />
+<input type="hidden" name="mergereference" value="[% mergereference %]" />
+<input type="hidden" name="frameworkcode" value="[% framework %]" />
+
+<fieldset class="action"><input type="submit" name="merge" value="Merge" /></fieldset>
+</div>
+</form>
+[% END %]
+[% END %]
+[% END %]
+
+</div>
+</div>
+</div>
+
+[% INCLUDE 'intranet-bottom.inc' %]
index ea16505..f73b819 100644 (file)
@@ -35,6 +35,8 @@ function searchauthority() {
     Y = document.forms[0].value.value;
     window.location="/cgi-bin/koha/authorities/authorities-home.pl?op=do_search&type=intranet&authtypecode="+X+"&value="+Y+"&marclist=&and_or=and&excluding=&operator=contains";
 }
+
+[% INCLUDE 'authorities_js.inc' %]
 //]]>
 </script>
 </head>
@@ -53,6 +55,7 @@ function searchauthority() {
     [% INCLUDE 'authorities-toolbar.inc' %]
 <h1>Authority search results</h1>
 
+<div id="merge_in_progress"></div>
 [% IF ( total ) %]
 <div class="pages">[% pagination_bar %]</div>
 
@@ -73,9 +76,9 @@ function searchauthority() {
     </tr>
 [% FOREACH resul IN result %]
     [% UNLESS ( loop.odd ) %]
-    <tr class="highlight">
+    <tr data-authid="[% resul.authid %]" class="highlight">
     [% ELSE %]
-    <tr>
+    <tr data-authid="[% resul.authid %]">
     [% END %]
       <td>[% PROCESS authresult summary=resul.summary link="/cgi-bin/koha/authorities/authorities-home.pl?op=do_search&type=intranet&marclist=any&operator=contains&orderby=HeadingAsc&value=" %]</td>
       <td><a href="detail.pl?authid=[% resul.authid %]">Details</a></td>
@@ -87,6 +90,7 @@ function searchauthority() {
       [% IF ( CAN_user_editauthorities ) %]
           <td>
               <a href="/cgi-bin/koha/authorities/authorities.pl?authid=[% resul.authid %]">Edit</a>
+              | <a class="merge_auth" href="#merge">Merge</a>
               [% UNLESS ( resul.used ) %]
                    | <a href="javascript:confirm_deletion([% resul.authid %])">Delete</a>
               [% END %]
index 789b02a..c1d7060 100644 (file)
             [% IF ( record.record_type == 'biblio' ) %]
                 <td class="highlight" colspan="4">Matches biblio [% record_lis.match_id %] (score = [% record_lis.match_score %]): <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% record_lis.match_id %]">[% record_lis.match_citation %]</a></td>
             [% ELSIF ( record.record_type == 'auth' ) %]
-                <td class="highlight" colspan="4">Matches authority [% record_lis.match_id %] (score = [% record_lis.match_score %]): <a href="/cgi-bin/koha/authorities/detail.pl?authid=[% record_lis.match_id %]">[% record_lis.match_citation %]</a></td>
+                <td class="highlight" colspan="4">Matches authority [% record_lis.match_id %] (score = [% record_lis.match_score %]): <a href="/cgi-bin/koha/authorities/detail.pl?authid=[% record_lis.match_id %]">[% record_lis.match_citation %]</a>
+        <a href="/cgi-bin/koha/authorities/merge.pl?mergereference=breeding&authid=[% record_lis.match_id %]&authid=[% record_lis.import_record_id %]">Merge</a>
+                </td>
             [% END %]
         </tr>
+    [% ELSIF ( record.record_type == 'auth') %]
+        <tr data-authid="[% record_lis.import_record_id %]">
+            <td />
+            <td class="highlight" colspan="4"><a href="#" class="merge_auth">Search for a record to merge in a new window</a></td>
+        </tr>
     [% END %]
 [% END %]
 [% INCLUDE 'doc-head-open.inc' %]
@@ -41,6 +48,13 @@ $(document).ready(function(){
       $("#"+str+" option[selected='selected']").attr("selected","selected");
       $(this).parent().hide();
   });
+
+  $('.merge_auth').click(function(event) {
+      event.preventDefault();
+      var authid = $(this).parents('tr').attr('data-authid');
+      $.cookie('auth_to_merge', JSON.stringify({ 'authid': authid, 'summary': $('tr[data-id="' + authid + '"] .citation').text(), 'mergereference': 'breeding' }), { 'path': '/' });
+      window.open("/cgi-bin/koha/authorities/authorities-home.pl");
+  });
 });
 //]]>
 </script>
@@ -383,9 +397,9 @@ Page
 
   </tr>
   [% FOREACH record_lis IN record_list %]
-  [% UNLESS ( loop.odd ) %]<tr class="highlight">[% ELSE %]<tr>[% END %]
+  [% UNLESS ( loop.odd ) %]<tr data-id="[% record_lis.import_record_id %]" class="highlight">[% ELSE %]<tr data-id="[% record_lis.import_record_id %]">[% END %]
     <td>[% record_lis.record_sequence %]</td>
-    <td><a href="/cgi-bin/koha/catalogue/showmarc.pl?importid=[% record_lis.import_record_id %]" rel="gb_page_center[600,500]">[% record_lis.citation %]</a></td>
+    <td><a class="citation" href="/cgi-bin/koha/catalogue/showmarc.pl?importid=[% record_lis.import_record_id %]" rel="gb_page_center[600,500]">[% record_lis.citation %]</a></td>
     <td>
         [% IF ( record_lis.status == 'imported' ) %]
             Imported
index 797fc34..daf91f0 100755 (executable)
@@ -23,7 +23,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 3;
+use Test::More tests => 4;
 
 BEGIN {
         use_ok('Koha::Util::MARC');
@@ -95,3 +95,5 @@ foreach my $field (@$hash) {
 is_deeply($hash, $samplehash, 'Generated hash correctly');
 my $dupkeys = grep { $_ > 1 } values %fieldkeys;
 is($dupkeys, 0, 'No duplicate keys');
+
+is(Koha::Util::MARC::getAuthorityAuthorizedHeading($marcrecord, 'marc21'), 'Cooking', 'Routine for retrieving authorized heading works');
index dc57774..6373fb7 100755 (executable)
@@ -38,6 +38,8 @@ my $authority = Koha::Authority->new($record);
 
 is(ref($authority), 'Koha::Authority', 'Created valid Koha::Authority object');
 
+is($authority->authorized_heading(), 'Cooking', 'Authorized heading was correct');
+
 is_deeply($authority->record, $record, 'Saved record');
 
 SKIP:
@@ -63,4 +65,28 @@ SKIP:
     is($authority, undef, 'No invalid record is retrieved');
 }
 
+SKIP:
+{
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT import_record_id FROM import_records WHERE record_type = 'auth' LIMIT 1;");
+    $sth->execute();
+
+    my $import_record_id;
+    for my $row ($sth->fetchrow_hashref) {
+        $import_record_id = $row->{'import_record_id'};
+    }
+
+    skip 'No authorities in reservoir', 3 unless $import_record_id;
+    $authority = Koha::Authority->get_from_breeding($import_record_id);
+
+    is(ref($authority), 'Koha::Authority', 'Retrieved valid Koha::Authority object');
+
+    is($authority->authid, undef, 'Records in reservoir do not have an authid');
+
+    is(ref($authority->record), 'MARC::Record', 'MARC record attached to authority');
+
+    $authority = Koha::Authority->get_from_breeding('alphabetsoup');
+    is($authority, undef, 'No invalid record is retrieved from reservoir');
+}
+
 done_testing();