Bug 19386: Prevent t/db_dependent/SIP/Patron.t to fail randomly
[koha.git] / C4 / AuthoritiesMarc.pm
index 8c6c273..6859041 100644 (file)
@@ -1,4 +1,5 @@
 package C4::AuthoritiesMarc;
+
 # Copyright 2000-2002 Katipo Communications
 #
 # This file is part of Koha.
@@ -31,6 +32,7 @@ use Koha::Authorities;
 use Koha::Authority::MergeRequest;
 use Koha::Authority::Types;
 use Koha::Authority;
+use Koha::Libraries;
 use Koha::SearchEngine;
 use Koha::SearchEngine::Search;
 
@@ -50,8 +52,6 @@ BEGIN {
        &GetAuthority
        &GetAuthorityXML
 
-       &CountUsage
-       &CountUsageChildren
        &SearchAuthorities
     
         &BuildSummary
@@ -239,7 +239,7 @@ sub SearchAuthorities {
         $query="\@or $orderstring $query" if $orderstring;
     }
 
-    $offset=0 unless $offset;
+    $offset = 0 if not defined $offset or $offset < 0;
     my $counter = $offset;
     $length=10 unless $length;
     my @oAuth;
@@ -326,7 +326,7 @@ sub SearchAuthorities {
         ###
         if (! $skipmetadata) {
             for (my $z=0; $z<@finalresult; $z++){
-                my  $count=CountUsage($finalresult[$z]{authid});
+                my $count = Koha::Authorities->get_usage_count({ authid => $finalresult[$z]{authid} });
                 $finalresult[$z]{used}=$count;
             }# all $z's
         }
@@ -339,43 +339,6 @@ sub SearchAuthorities {
     return (\@finalresult, $nbresults);
 }
 
-=head2 CountUsage 
-
-  $count= &CountUsage($authid)
-
-counts Usage of Authid in bibliorecords. 
-
-=cut
-
-sub CountUsage {
-    my ($authid) = @_;
-        ### ZOOM search here
-        my $query;
-        $query= "an:".$authid;
-        # Should really be replaced with a real count call, this is a
-        # bad way.
-        my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
-        my ($err,$res,$result) = $searcher->simple_search_compat($query,0,1);
-        if ($err) {
-            warn "Error: $err from search $query";
-            $result = 0;
-        }
-
-        return $result;
-}
-
-=head2 CountUsageChildren 
-
-  $count= &CountUsageChildren($authid)
-
-counts Usage of narrower terms of Authid in bibliorecords.
-
-=cut
-
-sub CountUsageChildren {
-  my ($authid) = @_;
-}
-
 =head2 GuessAuthTypeCode
 
   my $authtypecode = GuessAuthTypeCode($record);
@@ -604,12 +567,19 @@ sub AddAuthority {
 
     SetUTF8Flag($record);
        if ($format eq "MARC21") {
+        my $userenv = C4::Context->userenv;
+        my $library;
+        my $marcorgcode = C4::Context->preference('MARCOrgCode');
+        if ( $userenv && $userenv->{'branch'} ) {
+            $library = Koha::Libraries->find( $userenv->{'branch'} );
+            $marcorgcode = $library->get_effective_marcorgcode;
+        }
                if (!$record->leader) {
                        $record->leader($leader);
                }
                if (!$record->field('003')) {
                        $record->insert_fields_ordered(
-                               MARC::Field->new('003',C4::Context->preference('MARCOrgCode'))
+                MARC::Field->new('003', $marcorgcode),
                        );
                }
                my $date=POSIX::strftime("%y%m%d",localtime);
@@ -628,8 +598,8 @@ sub AddAuthority {
                if (!$record->field('040')) {
                 $record->insert_fields_ordered(
         MARC::Field->new('040','','',
-                               'a' => C4::Context->preference('MARCOrgCode'),
-                               'c' => C4::Context->preference('MARCOrgCode')
+            'a' => $marcorgcode,
+            'c' => $marcorgcode,
                                ) 
                        );
     }
@@ -683,17 +653,20 @@ sub AddAuthority {
 
 =head2 DelAuthority
 
-    DelAuthority({ authid => $authid });
+    DelAuthority({ authid => $authid, [ skip_merge => 1 ] });
 
-Deletes $authid and calls merge to cleanup in linked biblio records
+Deletes $authid and calls merge to cleanup linked biblio records.
+Parameter skip_merge is used in authorities/merge.pl. You should normally not
+use it.
 
 =cut
 
 sub DelAuthority {
     my ( $params ) = @_;
     my $authid = $params->{authid} || return;
-    my $dbh=C4::Context->dbh;
-    merge({ mergefrom => $authid, MARCfrom => GetAuthority($authid) });
+    my $skip_merge = $params->{skip_merge};
+    my $dbh = C4::Context->dbh;
+    merge({ mergefrom => $authid }) if !$skip_merge;
     $dbh->do( "DELETE FROM auth_header WHERE authid=?", undef, $authid );
     logaction( "AUTHORITIES", "DELETE", $authid, "authority" ) if C4::Context->preference("AuthoritiesLog");
     ModZebra( $authid, "recordDelete", "authorityserver", undef);
@@ -1370,19 +1343,24 @@ sub AddAuthorityTrees{
 =head2 merge
 
     $count = merge({
-        mergefrom => mergefrom,
-        MARCfrom => $MARCfrom,
+        mergefrom => $mergefrom,
+        [ MARCfrom => $MARCfrom, ]
         [ mergeto => $mergeto, ]
         [ MARCto => $MARCto, ]
         [ biblionumbers => [ $a, $b, $c ], ]
         [ override_limit => 1, ]
     });
 
-Merge biblios linked to authority $mergefrom.
+Merge biblios linked to authority $mergefrom (mandatory parameter).
 If $mergeto equals mergefrom, the linked biblio field is updated.
 If $mergeto is different, the biblio field will be linked to $mergeto.
 If $mergeto is missing, the biblio field is deleted.
 
+MARCfrom is used to determine if a cleared subfield in the authority record
+should be removed from a biblio. MARCto is used to populate the biblio
+record with the updated values; if you do not pass it, the biblio field
+will be deleted (same as missing mergeto).
+
 Normally all biblio records linked to $mergefrom, will be considered. But
 you can pass specific numbers via the biblionumbers parameter.
 
@@ -1434,17 +1412,31 @@ sub merge {
 
     my @record_to;
     @record_to = $MARCto->field($auth_tag_to_report_to)->subfields() if $auth_tag_to_report_to && $MARCto && $MARCto->field($auth_tag_to_report_to);
+    # Exceptional: If MARCto and authtypeto exist but $auth_tag_to_report_to
+    # is empty, make sure that $9 and $a remain (instead of clearing the
+    # reference) in order to allow for data recovery.
+    # Note: We need $a too, since a single $9 does not pass ModBiblio.
+    if( $MARCto && $authtypeto && !@record_to  ) {
+        push @record_to, [ 'a', ' ' ]; # do not remove the space
+    }
+
     my @record_from;
-    @record_from = $MARCfrom->field($auth_tag_to_report_from)->subfields() if $auth_tag_to_report_from && $MARCfrom && $MARCfrom->field($auth_tag_to_report_from);
+    if( !$authfrom && $MARCfrom && $MARCfrom->field('1..','2..') ) {
+    # postponed merge, authfrom was deleted and MARCfrom only contains the old reporting tag (and possibly a 100 for UNIMARC)
+    # 2XX is for UNIMARC; we use -1 in order to skip 100 in UNIMARC; this will not impact MARC21, since there is only one tag
+        @record_from = ( $MARCfrom->field('1..','2..') )[-1]->subfields;
+    } elsif( $auth_tag_to_report_from && $MARCfrom && $MARCfrom->field($auth_tag_to_report_from) ) {
+        @record_from = $MARCfrom->field($auth_tag_to_report_from)->subfields;
+    }
 
-    # Get All candidate Tags for the change 
+    # Get all candidate tags for the change
     # (This will reduce the search scope in marc records).
     # For a deleted authority record, we scan all auth controlled fields
     my $dbh = C4::Context->dbh;
     my $sql = "SELECT DISTINCT tagfield FROM marc_subfield_structure WHERE authtypecode=?";
-    my $tags_using_authtype = $authtypefrom ? $dbh->selectcol_arrayref( $sql, undef, ( $authtypefrom->authtypecode )) : $dbh->selectcol_arrayref( "SELECT DISTINCT tagfield FROM marc_subfield_structure WHERE authtypecode IS NOT NULL AND authtypecode<>''" );
+    my $tags_using_authtype = $authtypefrom && $authtypefrom->authtypecode ? $dbh->selectcol_arrayref( $sql, undef, ( $authtypefrom->authtypecode )) : $dbh->selectcol_arrayref( "SELECT DISTINCT tagfield FROM marc_subfield_structure WHERE authtypecode IS NOT NULL AND authtypecode<>''" );
     my $tags_new;
-    if( $authtypefrom && $authtypeto && $authtypeto->authtypecode ne $authtypefrom->authtypecode ) {
+    if( $authtypeto && ( !$authtypefrom || $authtypeto->authtypecode ne $authtypefrom->authtypecode )) {
         $tags_new = $dbh->selectcol_arrayref( $sql, undef, ( $authtypeto->authtypecode ));
     }  
 
@@ -1460,7 +1452,7 @@ sub merge {
 
     my $counteditedbiblio = 0;
     foreach my $biblionumber ( @biblionumbers ) {
-        my $marcrecord = GetMarcBiblio( $biblionumber );
+        my $marcrecord = GetMarcBiblio({ biblionumber => $biblionumber });
         next if !$marcrecord;
         my $update = 0;
         foreach my $tagfield (@$tags_using_authtype) {
@@ -1470,14 +1462,15 @@ sub merge {
                 my $tag         = $field->tag();
                 next if !defined($auth_number) || $auth_number ne $mergefrom;
                 $countfrom++;
-                if ( !$mergeto || ( $overwrite && $countfrom > 1 ) ) {
-                    # if mergeto is missing, this indicates a delete
-                    # Or: remove this duplicate in strict mode
+                if ( !$mergeto || !@record_to ||
+                  ( $overwrite && $countfrom > 1 ) ) {
+                    # !mergeto or !record_to indicates a delete
+                    # Other condition: remove this duplicate in strict mode
                     $marcrecord->delete_field($field);
                     $update = 1;
                     next;
                 }
-                my $newtag = $tags_new
+                my $newtag = $tags_new && @$tags_new
                   ? _merge_newtag( $tag, $tags_new )
                   : $tag;
                 my $field_to = MARC::Field->new(
@@ -1496,7 +1489,7 @@ sub merge {
                         $field_to->add_subfields( $subfield->[0], $subfield->[1] );
                     }
                 }
-                if ($tags_new) {
+                if ($tags_new && @$tags_new) {
                     $marcrecord->delete_field($field);
                     append_fields_ordered( $marcrecord, $field_to );
                 } else {