Bug 9356: Show Dissertation note (MARC21 502) in XSLT
[koha.git] / C4 / Biblio.pm
index c479502..2c7170c 100644 (file)
@@ -28,6 +28,7 @@ use MARC::Record;
 use MARC::File::USMARC;
 use MARC::File::XML;
 use POSIX qw(strftime);
+use Module::Load::Conditional qw(can_load);
 
 use C4::Koha;
 use C4::Dates qw/format_date/;
@@ -89,6 +90,7 @@ BEGIN {
       &GetAuthorisedValueDesc
       &GetMarcStructure
       &GetMarcFromKohaField
+      &GetMarcSubfieldStructureFromKohaField
       &GetFrameworkCode
       &TransformKohaToMarc
       &PrepHostMarcField
@@ -491,13 +493,11 @@ sub BiblioAutoLink {
 
     my $linker_module =
       "C4::Linker::" . ( C4::Context->preference("LinkerModule") || 'Default' );
-    eval { eval "require $linker_module"; };
-    if ($@) {
+    unless ( can_load( modules => { $linker_module => undef } ) ) {
         $linker_module = 'C4::Linker::Default';
-        eval "require $linker_module";
-    }
-    if ($@) {
-        return 0, 0;
+        unless ( can_load( modules => { $linker_module => undef } ) ) {
+            return 0, 0;
+        }
     }
 
     my $linker = $linker_module->new(
@@ -568,21 +568,27 @@ sub LinkBibHeadingsToAuthorities {
                 $results{'fuzzy'}->{ $heading->display_form() }++;
             }
             elsif ( C4::Context->preference('AutoCreateAuthorities') ) {
-                my $authtypedata =
-                  C4::AuthoritiesMarc::GetAuthType( $heading->auth_type() );
-                my $marcrecordauth = MARC::Record->new();
-                if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
-                    $marcrecordauth->leader('     nz  a22     o  4500');
-                    SetMarcUnicodeFlag( $marcrecordauth, 'MARC21' );
+                if ( _check_valid_auth_link( $current_link, $field ) ) {
+                    $results{'linked'}->{ $heading->display_form() }++;
                 }
-                my $authfield =
-                  MARC::Field->new( $authtypedata->{auth_tag_to_report},
-                    '', '', "a" => "" . $field->subfield('a') );
-                map {
-                    $authfield->add_subfields( $_->[0] => $_->[1] )
-                      if ( $_->[0] =~ /[A-z]/ && $_->[0] ne "a" )
-                } $field->subfields();
-                $marcrecordauth->insert_fields_ordered($authfield);
+                else {
+                    my $authtypedata =
+                      C4::AuthoritiesMarc::GetAuthType( $heading->auth_type() );
+                    my $marcrecordauth = MARC::Record->new();
+                    if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
+                        $marcrecordauth->leader('     nz  a22     o  4500');
+                        SetMarcUnicodeFlag( $marcrecordauth, 'MARC21' );
+                    }
+                    $field->delete_subfield( code => '9' )
+                      if defined $current_link;
+                    my $authfield =
+                      MARC::Field->new( $authtypedata->{auth_tag_to_report},
+                        '', '', "a" => "" . $field->subfield('a') );
+                    map {
+                        $authfield->add_subfields( $_->[0] => $_->[1] )
+                          if ( $_->[0] =~ /[A-z]/ && $_->[0] ne "a" )
+                    } $field->subfields();
+                    $marcrecordauth->insert_fields_ordered($authfield);
 
 # bug 2317: ensure new authority knows it's using UTF-8; currently
 # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
@@ -591,41 +597,47 @@ sub LinkBibHeadingsToAuthorities {
 # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
 # of change to a core API just before the 3.0 release.
 
-                if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
-                    $marcrecordauth->insert_fields_ordered(
-                        MARC::Field->new(
-                            '667', '', '',
-                            'a' => "Machine generated authority record."
-                        )
-                    );
-                    my $cite =
-                        $bib->author() . ", "
-                      . $bib->title_proper() . ", "
-                      . $bib->publication_date() . " ";
-                    $cite =~ s/^[\s\,]*//;
-                    $cite =~ s/[\s\,]*$//;
-                    $cite =
-                        "Work cat.: ("
-                      . C4::Context->preference('MARCOrgCode') . ")"
-                      . $bib->subfield( '999', 'c' ) . ": "
-                      . $cite;
-                    $marcrecordauth->insert_fields_ordered(
-                        MARC::Field->new( '670', '', '', 'a' => $cite ) );
-                }
+                    if ( C4::Context->preference('marcflavour') eq 'MARC21' ) {
+                        $marcrecordauth->insert_fields_ordered(
+                            MARC::Field->new(
+                                '667', '', '',
+                                'a' => "Machine generated authority record."
+                            )
+                        );
+                        my $cite =
+                            $bib->author() . ", "
+                          . $bib->title_proper() . ", "
+                          . $bib->publication_date() . " ";
+                        $cite =~ s/^[\s\,]*//;
+                        $cite =~ s/[\s\,]*$//;
+                        $cite =
+                            "Work cat.: ("
+                          . C4::Context->preference('MARCOrgCode') . ")"
+                          . $bib->subfield( '999', 'c' ) . ": "
+                          . $cite;
+                        $marcrecordauth->insert_fields_ordered(
+                            MARC::Field->new( '670', '', '', 'a' => $cite ) );
+                    }
 
            #          warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
 
-                $authid =
-                  C4::AuthoritiesMarc::AddAuthority( $marcrecordauth, '',
-                    $heading->auth_type() );
-                $field->add_subfields( '9', $authid );
-                $num_headings_changed++;
-                $results{'added'}->{ $heading->display_form() }++;
+                    $authid =
+                      C4::AuthoritiesMarc::AddAuthority( $marcrecordauth, '',
+                        $heading->auth_type() );
+                    $field->add_subfields( '9', $authid );
+                    $num_headings_changed++;
+                    $results{'added'}->{ $heading->display_form() }++;
+                }
             }
             elsif ( defined $current_link ) {
-                $field->delete_subfield( code => '9' );
-                $num_headings_changed++;
-                $results{'unlinked'}->{ $heading->display_form() }++;
+                if ( _check_valid_auth_link( $current_link, $field ) ) {
+                    $results{'linked'}->{ $heading->display_form() }++;
+                }
+                else {
+                    $field->delete_subfield( code => '9' );
+                    $num_headings_changed++;
+                    $results{'unlinked'}->{ $heading->display_form() }++;
+                }
             }
             else {
                 $results{'unlinked'}->{ $heading->display_form() }++;
@@ -636,6 +648,30 @@ sub LinkBibHeadingsToAuthorities {
     return $num_headings_changed, \%results;
 }
 
+=head2 _check_valid_auth_link
+
+    if ( _check_valid_auth_link($authid, $field) ) {
+        ...
+    }
+
+Check whether the specified heading-auth link is valid without reference
+to Zebra/Solr. Ideally this code would be in C4::Heading, but that won't be
+possible until we have de-cycled C4::AuthoritiesMarc, so this is the
+safest place.
+
+=cut
+
+sub _check_valid_auth_link {
+    my ( $authid, $field ) = @_;
+
+    require C4::AuthoritiesMarc;
+
+    my $authorized_heading =
+      C4::AuthoritiesMarc::GetAuthorizedHeading( { 'authid' => $authid } );
+
+   return ($field->as_string('abcdefghijklmnopqrstuvwxyz') eq $authorized_heading);
+}
+
 =head2 GetRecordValue
 
   my $values = GetRecordValue($field, $record, $frameworkcode);
@@ -890,7 +926,7 @@ Return the ISBD view which can be included in opac and intranet
 sub GetISBDView {
     my ( $biblionumber, $template ) = @_;
     my $record   = GetMarcBiblio($biblionumber, 1);
-    return undef unless defined $record;
+    return unless defined $record;
     my $itemtype = &GetFrameworkCode($biblionumber);
     my ( $holdingbrtagf, $holdingbrtagsubf ) = &GetMarcFromKohaField( "items.holdingbranch", $itemtype );
     my $tagslib = &GetMarcStructure( 1, $itemtype );
@@ -920,6 +956,10 @@ sub GetISBDView {
             #         warn "ERROR IN ISBD DEFINITION at : $isbdfield" unless $fieldvalue;
             #             warn "FV : $fieldvalue";
             if ( $subfvalue ne "" ) {
+                # OPAC hidden subfield
+                next
+                  if ( ( $template eq 'opac' )
+                    && ( $tagslib->{$fieldvalue}->{$subfvalue}->{'hidden'} || 0 ) > 0 );
                 foreach my $field (@fieldslist) {
                     foreach my $subfield ( $field->subfield($subfvalue) ) {
                         my $calculated = $analysestring;
@@ -955,6 +995,10 @@ sub GetISBDView {
                         for my $i ( 0 .. $#subf ) {
                             my $valuecode     = $subf[$i][1];
                             my $subfieldcode  = $subf[$i][0];
+                            # OPAC hidden subfield
+                            next
+                              if ( ( $template eq 'opac' )
+                                && ( $tagslib->{$fieldvalue}->{$subfieldcode}->{'hidden'} || 0 ) > 0 );
                             my $subfieldvalue = GetAuthorisedValueDesc( $tag, $subf[$i][0], $subf[$i][1], '', $tagslib );
                             my $tagsubf       = $tag . $subfieldcode;
 
@@ -999,7 +1043,7 @@ sub GetISBDView {
 
 =head2 GetBiblio
 
-  ( $count, @results ) = &GetBiblio($biblionumber);
+  my $biblio = &GetBiblio($biblionumber);
 
 =cut
 
@@ -1010,12 +1054,10 @@ sub GetBiblio {
     my $count          = 0;
     my @results;
     $sth->execute($biblionumber);
-    while ( my $data = $sth->fetchrow_hashref ) {
-        $results[$count] = $data;
-        $count++;
-    }    # while
-    $sth->finish;
-    return ( $count, @results );
+    if ( my $data = $sth->fetchrow_hashref ) {
+        return $data;
+    }
+    return;
 }    # sub GetBiblio
 
 =head2 GetBiblioItemInfosOf
@@ -1147,7 +1189,7 @@ C<$frameworkcode> is the framework code.
 
 =cut
 
-sub GetUsedMarcStructure($) {
+sub GetUsedMarcStructure {
     my $frameworkcode = shift || '';
     my $query = qq/
         SELECT *
@@ -1166,13 +1208,14 @@ sub GetUsedMarcStructure($) {
   ($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
 
 Returns the MARC fields & subfields mapped to the koha field 
-for the given frameworkcode
+for the given frameworkcode or default framework if $frameworkcode is missing
 
 =cut
 
 sub GetMarcFromKohaField {
-    my ( $kohafield, $frameworkcode ) = @_;
-    return (0, undef) unless $kohafield and defined $frameworkcode;
+    my $kohafield = shift;
+    my $frameworkcode = shift || '';
+    return (0, undef) unless $kohafield;
     my $relations = C4::Context->marcfromkohafield;
     if ( my $mf = $relations->{$frameworkcode}->{$kohafield} ) {
         return @$mf;
@@ -1180,6 +1223,38 @@ sub GetMarcFromKohaField {
     return (0, undef);
 }
 
+=head2 GetMarcSubfieldStructureFromKohaField
+
+    my $subfield_structure = &GetMarcSubfieldStructureFromKohaField($kohafield, $frameworkcode);
+
+Returns a hashref where keys are marc_subfield_structure column names for the
+row where kohafield=$kohafield for the given framework code.
+
+$frameworkcode is optional. If not given, then the default framework is used.
+
+=cut
+
+sub GetMarcSubfieldStructureFromKohaField {
+    my ($kohafield, $frameworkcode) = @_;
+
+    return undef unless $kohafield;
+    $frameworkcode //= '';
+
+    my $dbh = C4::Context->dbh;
+    my $query = qq{
+        SELECT *
+        FROM marc_subfield_structure
+        WHERE kohafield = ?
+          AND frameworkcode = ?
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute($kohafield, $frameworkcode);
+    my $result = $sth->fetchrow_hashref;
+    $sth->finish;
+
+    return $result;
+}
+
 =head2 GetMarcBiblio
 
   my $record = GetMarcBiblio($biblionumber, [$embeditems]);
@@ -1212,7 +1287,7 @@ sub GetMarcBiblio {
 
         return $record;
     } else {
-        return undef;
+        return;
     }
 }
 
@@ -1221,7 +1296,7 @@ sub GetMarcBiblio {
   my $marcxml = GetXmlBiblio($biblionumber);
 
 Returns biblioitems.marcxml of the biblionumber passed in parameter.
-The XML contains both biblio & item datas
+The XML should only contain biblio information (item information is no longer stored in marcxml field)
 
 =cut
 
@@ -1652,15 +1727,19 @@ sub GetMarcNotes {
     my $note = "";
     my $tag  = "";
     my $marcnote;
+    my %blacklist = map { $_ => 1 } split(/,/,C4::Context->preference('NotesBlacklist'));
     foreach my $field ( $record->field($scope) ) {
-        my $value = $field->as_string();
-        if ( $note ne "" ) {
-            $marcnote = { marcnote => $note, };
-            push @marcnotes, $marcnote;
-            $note = $value;
-        }
-        if ( $note ne $value ) {
-            $note = $note . " " . $value;
+        my $tag = $field->tag();
+        if (!$blacklist{$tag}) {
+            my $value = $field->as_string();
+            if ( $note ne "" ) {
+                $marcnote = { marcnote => $note, };
+                push @marcnotes, $marcnote;
+                $note = $value;
+            }
+            if ( $note ne $value ) {
+                $note = $note . " " . $value;
+            }
         }
     }
 
@@ -1682,65 +1761,75 @@ The subjects are stored in different fields depending on MARC flavour
 
 sub GetMarcSubjects {
     my ( $record, $marcflavour ) = @_;
-    my ( $mintag, $maxtag );
+    my ( $mintag, $maxtag, $fields_filter );
     if ( $marcflavour eq "UNIMARC" ) {
         $mintag = "600";
         $maxtag = "611";
-    } else {    # assume marc21 if not unimarc
+        $fields_filter = '6..';
+    } else { # marc21/normarc
         $mintag = "600";
         $maxtag = "699";
+        $fields_filter = '6..';
     }
 
     my @marcsubjects;
-    my $subject  = "";
-    my $subfield = "";
-    my $marcsubject;
 
     my $subject_limit = C4::Context->preference("TraceCompleteSubfields") ? 'su,complete-subfield' : 'su';
+    my $authoritysep = C4::Context->preference('authoritysep');
 
-    foreach my $field ( $record->field('6..') ) {
-        next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
+    foreach my $field ( $record->field($fields_filter) ) {
+        next unless ($field->tag() >= $mintag && $field->tag() <= $maxtag);
         my @subfields_loop;
         my @subfields = $field->subfields();
-        my $counter   = 0;
         my @link_loop;
 
-        # if there is an authority link, build the link with an= subfield9
-        my $found9 = 0;
+        # if there is an authority link, build the links with an= subfield9
+        my $subfield9 = $field->subfield('9');
+        my $authoritylink;
+        if ($subfield9) {
+            my $linkvalue = $subfield9;
+            $linkvalue =~ s/(\(|\))//g;
+            @link_loop = ( { limit => 'an', 'link' => $linkvalue } );
+            $authoritylink = $linkvalue
+        }
+
+        # other subfields
         for my $subject_subfield (@subfields) {
+            next if ( $subject_subfield->[0] eq '9' );
 
             # don't load unimarc subfields 3,4,5
             next if ( ( $marcflavour eq "UNIMARC" ) and ( $subject_subfield->[0] =~ /2|3|4|5/ ) );
-
             # don't load MARC21 subfields 2 (FIXME: any more subfields??)
             next if ( ( $marcflavour eq "MARC21" ) and ( $subject_subfield->[0] =~ /2/ ) );
+
             my $code      = $subject_subfield->[0];
             my $value     = $subject_subfield->[1];
             my $linkvalue = $value;
             $linkvalue =~ s/(\(|\))//g;
-            my $operator;
-            if ( $counter != 0 ) {
-                $operator = ' and ';
-            }
-            if ( $code eq 9 ) {
-                $found9 = 1;
-                @link_loop = ( { 'limit' => 'an', link => "$linkvalue" } );
-            }
-            if ( not $found9 ) {
-                push @link_loop, { 'limit' => $subject_limit, link => $linkvalue, operator => $operator };
-            }
-            my $separator;
-            if ( $counter != 0 ) {
-                $separator = C4::Context->preference('authoritysep');
+            # if no authority link, build a search query
+            unless ($subfield9) {
+                push @link_loop, {
+                    limit    => $subject_limit,
+                    'link'   => $linkvalue,
+                    operator => (scalar @link_loop) ? ' and ' : undef
+                };
             }
-
-            # ignore $9
             my @this_link_loop = @link_loop;
-            push @subfields_loop, { code => $code, value => $value, link_loop => \@this_link_loop, separator => $separator } unless ( $subject_subfield->[0] eq 9 || $subject_subfield->[0] eq '0' );
-            $counter++;
+            # do not display $0
+            unless ( $code eq '0' ) {
+                push @subfields_loop, {
+                    code      => $code,
+                    value     => $value,
+                    link_loop => \@this_link_loop,
+                    separator => (scalar @subfields_loop) ? $authoritysep : ''
+                };
+            }
         }
 
-        push @marcsubjects, { MARCSUBJECT_SUBFIELDS_LOOP => \@subfields_loop };
+        push @marcsubjects, {
+            MARCSUBJECT_SUBFIELDS_LOOP => \@subfields_loop,
+            authoritylink => $authoritylink,
+        };
 
     }
     return \@marcsubjects;
@@ -1757,7 +1846,7 @@ The authors are stored in different fields depending on MARC flavour
 
 sub GetMarcAuthors {
     my ( $record, $marcflavour ) = @_;
-    my ( $mintag, $maxtag );
+    my ( $mintag, $maxtag, $fields_filter );
 
     # tagslib useful for UNIMARC author reponsabilities
     my $tagslib =
@@ -1765,15 +1854,17 @@ sub GetMarcAuthors {
     if ( $marcflavour eq "UNIMARC" ) {
         $mintag = "700";
         $maxtag = "712";
-    } elsif ( $marcflavour eq "MARC21" || $marcflavour eq "NORMARC" ) { # assume marc21 or normarc if not unimarc
+        $fields_filter = '7..';
+    } else { # marc21/normarc
         $mintag = "700";
         $maxtag = "720";
-    } else {
-        return;
+        $fields_filter = '7..';
     }
+
     my @marcauthors;
+    my $authoritysep = C4::Context->preference('authoritysep');
 
-    foreach my $field ( $record->fields ) {
+    foreach my $field ( $record->field($fields_filter) ) {
         next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
         my @subfields_loop;
         my @link_loop;
@@ -1782,48 +1873,52 @@ sub GetMarcAuthors {
 
         # if there is an authority link, build the link with Koha-Auth-Number: subfield9
         my $subfield9 = $field->subfield('9');
+        if ($subfield9) {
+            my $linkvalue = $subfield9;
+            $linkvalue =~ s/(\(|\))//g;
+            @link_loop = ( { 'limit' => 'an', 'link' => $linkvalue } );
+        }
+
+        # other subfields
         for my $authors_subfield (@subfields) {
+            next if ( $authors_subfield->[0] eq '9' );
 
             # don't load unimarc subfields 3, 5
             next if ( $marcflavour eq 'UNIMARC' and ( $authors_subfield->[0] =~ /3|5/ ) );
-            my $subfieldcode = $authors_subfield->[0];
+
+            my $code = $authors_subfield->[0];
             my $value        = $authors_subfield->[1];
             my $linkvalue    = $value;
             $linkvalue =~ s/(\(|\))//g;
-            my $operator;
-            if ( $count_auth != 0 ) {
-                $operator = ' and ';
-            }
-
-            # if we have an authority link, use that as the link, otherwise use standard searching
-            if ($subfield9) {
-                @link_loop = ( { 'limit' => 'an', link => "$subfield9" } );
-            } else {
-
-                # reset $linkvalue if UNIMARC author responsibility
-                if ( $marcflavour eq 'UNIMARC' and ( $authors_subfield->[0] eq "4" ) ) {
-                    $linkvalue = "(" . GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ) . ")";
-                }
-                push @link_loop, { 'limit' => 'au', link => $linkvalue, operator => $operator };
+            # UNIMARC author responsibility
+            if ( $marcflavour eq 'UNIMARC' and $code eq '4' ) {
+                $value = GetAuthorisedValueDesc( $field->tag(), $code, $value, '', $tagslib );
+                $linkvalue = "($value)";
+            }
+            # if no authority link, build a search query
+            unless ($subfield9) {
+                push @link_loop, {
+                    limit    => 'au',
+                    'link'   => $linkvalue,
+                    operator => (scalar @link_loop) ? ' and ' : undef
+                };
             }
-            $value = GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib )
-              if ( $marcflavour eq 'UNIMARC' and ( $authors_subfield->[0] =~ /4/ ) );
             my @this_link_loop = @link_loop;
-            my $separator;
-            if ( $count_auth != 0 ) {
-                $separator = C4::Context->preference('authoritysep');
+            # do not display $0
+            unless ( $code eq '0') {
+                push @subfields_loop, {
+                    tag       => $field->tag(),
+                    code      => $code,
+                    value     => $value,
+                    link_loop => \@this_link_loop,
+                    separator => (scalar @subfields_loop) ? $authoritysep : ''
+                };
             }
-            push @subfields_loop,
-              { tag       => $field->tag(),
-                code      => $subfieldcode,
-                value     => $value,
-                link_loop => \@this_link_loop,
-                separator => $separator
-              }
-              unless ( $authors_subfield->[0] eq '9' || $authors_subfield->[0] eq '0');
-            $count_auth++;
-        }
-        push @marcauthors, { MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop };
+        }
+        push @marcauthors, {
+            MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop,
+            authoritylink => $subfield9,
+        };
     }
     return \@marcauthors;
 }
@@ -1894,76 +1989,63 @@ The series are stored in different fields depending on MARC flavour
 
 sub GetMarcSeries {
     my ( $record, $marcflavour ) = @_;
-    my ( $mintag, $maxtag );
+    my ( $mintag, $maxtag, $fields_filter );
     if ( $marcflavour eq "UNIMARC" ) {
         $mintag = "600";
         $maxtag = "619";
-    } else {    # assume marc21 if not unimarc
+        $fields_filter = '6..';
+    } else {    # marc21/normarc
         $mintag = "440";
         $maxtag = "490";
+        $fields_filter = '4..';
     }
 
     my @marcseries;
-    my $subjct   = "";
-    my $subfield = "";
-    my $marcsubjct;
+    my $authoritysep = C4::Context->preference('authoritysep');
 
-    foreach my $field ( $record->field('440'), $record->field('490') ) {
+    foreach my $field ( $record->field($fields_filter) ) {
+        next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
         my @subfields_loop;
-
-        #my $value = $field->subfield('a');
-        #$marcsubjct = {MARCSUBJCT => $value,};
         my @subfields = $field->subfields();
-
-        #warn "subfields:".join " ", @$subfields;
-        my $counter = 0;
         my @link_loop;
+
         for my $series_subfield (@subfields) {
-            my $volume_number;
-            undef $volume_number;
 
-            # see if this is an instance of a volume
-            if ( $series_subfield->[0] eq 'v' ) {
-                $volume_number = 1;
-            }
+            # ignore $9, used for authority link
+            next if ( $series_subfield->[0] eq '9' );
 
+            my $volume_number;
             my $code      = $series_subfield->[0];
             my $value     = $series_subfield->[1];
             my $linkvalue = $value;
             $linkvalue =~ s/(\(|\))//g;
-            if ( $counter != 0 ) {
-                push @link_loop, { link => $linkvalue, operator => ' and ', };
-            } else {
-                push @link_loop, { link => $linkvalue, operator => undef, };
-            }
-            my $separator;
-            if ( $counter != 0 ) {
-                $separator = C4::Context->preference('authoritysep');
+
+            # see if this is an instance of a volume
+            if ( $code eq 'v' ) {
+                $volume_number = 1;
             }
+
+            push @link_loop, {
+                'link' => $linkvalue,
+                operator => (scalar @link_loop) ? ' and ' : undef
+            };
+
             if ($volume_number) {
                 push @subfields_loop, { volumenum => $value };
             } else {
-                if ( $series_subfield->[0] ne '9' ) {
-                    push @subfields_loop, {
-                        code      => $code,
-                        value     => $value,
-                        link_loop => \@link_loop,
-                        separator => $separator,
-                        volumenum => $volume_number,
-                    };
+                push @subfields_loop, {
+                    code      => $code,
+                    value     => $value,
+                    link_loop => \@link_loop,
+                    separator => (scalar @subfields_loop) ? $authoritysep : '',
+                    volumenum => $volume_number,
                 }
             }
-            $counter++;
         }
         push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
 
-        #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
-        #push @marcsubjcts, $marcsubjct;
-        #$subjct = $value;
-
     }
-    my $marcseriessarray = \@marcseries;
-    return $marcseriessarray;
+    return \@marcseries;
 }    #end getMARCseriess
 
 =head2 GetMarcHosts
@@ -2791,18 +2873,21 @@ sub GetNoZebraIndexes {
 
 =head2 EmbedItemsInMarcBiblio
 
-    EmbedItemsInMarcBiblio($marc, $biblionumber);
+    EmbedItemsInMarcBiblio($marc, $biblionumber, $itemnumbers);
 
 Given a MARC::Record object containing a bib record,
 modify it to include the items attached to it as 9XX
 per the bib's MARC framework.
+if $itemnumbers is defined, only specified itemnumbers are embedded
 
 =cut
 
 sub EmbedItemsInMarcBiblio {
-    my ($marc, $biblionumber) = @_;
+    my ($marc, $biblionumber, $itemnumbers) = @_;
     croak "No MARC record" unless $marc;
 
+    $itemnumbers = [] unless defined $itemnumbers;
+
     my $frameworkcode = GetFrameworkCode($biblionumber);
     _strip_item_fields($marc, $frameworkcode);
 
@@ -2813,6 +2898,7 @@ sub EmbedItemsInMarcBiblio {
     my @item_fields;
     my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
     while (my ($itemnumber) = $sth->fetchrow_array) {
+        next if @$itemnumbers and not grep { $_ == $itemnumber } @$itemnumbers;
         require C4::Items;
         my $item_marc = C4::Items::GetMarcItem($biblionumber, $itemnumber);
         push @item_fields, $item_marc->field($itemtag);
@@ -3104,7 +3190,7 @@ sub _koha_marc_update_bib_ids {
     my ( $biblio_tag,     $biblio_subfield )     = GetMarcFromKohaField( "biblio.biblionumber",          $frameworkcode );
     die qq{No biblionumber tag for framework "$frameworkcode"} unless $biblio_tag;
     my ( $biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField( "biblioitems.biblioitemnumber", $frameworkcode );
-    die qq{No biblioitemnumber tag for framework "$frameworkcode"} unless $biblio_tag;
+    die qq{No biblioitemnumber tag for framework "$frameworkcode"} unless $biblioitem_tag;
 
     if ( $biblio_tag == $biblioitem_tag ) {
 
@@ -3319,7 +3405,8 @@ sub _koha_modify_biblioitem_nonmarc {
         cn_suffix       = ?,
         cn_sort         = ?,
         totalissues     = ?,
-    ean             = ?
+        ean             = ?,
+        agerestriction  = ?
         where biblioitemnumber = ?
         ";
     my $sth = $dbh->prepare($query);
@@ -3331,8 +3418,7 @@ sub _koha_modify_biblioitem_nonmarc {
         $biblioitem->{'pages'},            $biblioitem->{'bnotes'},           $biblioitem->{'size'},                  $biblioitem->{'place'},
         $biblioitem->{'lccn'},             $biblioitem->{'url'},              $biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'},
         $biblioitem->{'cn_item'},          $biblioitem->{'cn_suffix'},        $cn_sort,                               $biblioitem->{'totalissues'},
-    $biblioitem->{'ean'},
-        $biblioitem->{'biblioitemnumber'}
+        $biblioitem->{'ean'},              $biblioitem->{'agerestriction'},   $biblioitem->{'biblioitemnumber'}
     );
     if ( $dbh->errstr ) {
         $error .= "ERROR in _koha_modify_biblioitem_nonmarc $query" . $dbh->errstr;
@@ -3384,7 +3470,8 @@ sub _koha_add_biblioitem {
         cn_suffix       = ?,
         cn_sort         = ?,
         totalissues     = ?,
-    ean             = ?
+        ean             = ?,
+        agerestriction  = ?
         ";
     my $sth = $dbh->prepare($query);
     $sth->execute(
@@ -3395,7 +3482,7 @@ sub _koha_add_biblioitem {
         $biblioitem->{'pages'},            $biblioitem->{'bnotes'},           $biblioitem->{'size'},                  $biblioitem->{'place'},
         $biblioitem->{'lccn'},             $biblioitem->{'marc'},             $biblioitem->{'url'},                   $biblioitem->{'biblioitems.cn_source'},
         $biblioitem->{'cn_class'},         $biblioitem->{'cn_item'},          $biblioitem->{'cn_suffix'},             $cn_sort,
-        $biblioitem->{'totalissues'},      $biblioitem->{'ean'}
+        $biblioitem->{'totalissues'},      $biblioitem->{'ean'},              $biblioitem->{'agerestriction'}
     );
     my $bibitemnum = $dbh->{'mysql_insertid'};
 
@@ -3454,7 +3541,7 @@ sub _koha_delete_biblio {
         $sth2->finish;
     }
     $sth->finish;
-    return undef;
+    return;
 }
 
 =head2 _koha_delete_biblioitems
@@ -3503,7 +3590,7 @@ sub _koha_delete_biblioitems {
         $sth2->finish;
     }
     $sth->finish;
-    return undef;
+    return;
 }
 
 =head1 UNEXPORTED FUNCTIONS
@@ -3537,6 +3624,8 @@ sub ModBiblioMarc {
 
     # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
     if ( $encoding eq "UNIMARC" ) {
+       my $defaultlanguage = C4::Context->preference("UNIMARCField100Language");
+        $defaultlanguage = "fre" if (!$defaultlanguage || length($defaultlanguage) != 3);
         my $string = $record->subfield( 100, "a" );
         if ( ($string) && ( length( $record->subfield( 100, "a" ) ) == 36 ) ) {
             my $f100 = $record->field(100);
@@ -3545,8 +3634,9 @@ sub ModBiblioMarc {
             $string = POSIX::strftime( "%Y%m%d", localtime );
             $string =~ s/\-//g;
             $string = sprintf( "%-*s", 35, $string );
+           substr ( $string, 22, 3, $defaultlanguage);
         }
-        substr( $string, 22, 6, "frey50" );
+        substr( $string, 25, 3, "y50" );
         unless ( $record->subfield( 100, "a" ) ) {
             $record->insert_fields_ordered( MARC::Field->new( 100, "", "", "a" => $string ) );
         }