@@ -, +, @@ --- C4/Biblio.pm | 48 ++++--- C4/HoldsQueue.pm | 17 +-- C4/Overdues.pm | 4 + C4/Search.pm | 2 +- C4/ShelfBrowser.pm | 7 +- Koha/Biblio.pm | 11 +- Koha/Schema/Result/Holding.pm | 242 +++++++++++++++++++++++++++++++++ Koha/Schema/Result/HoldingsMetadata.pm | 138 +++++++++++++++++++ acqui/neworderbiblio.pl | 2 +- basket/basket.pl | 4 +- catalogue/detail.pl | 2 +- catalogue/moredetail.pl | 2 +- circ/branchoverdues.pl | 8 +- circ/reserveratios.pl | 9 +- circ/transferstoreceive.pl | 7 +- circ/waitingreserves.pl | 8 +- opac/opac-basket.pl | 2 +- opac/opac-detail.pl | 2 +- opac/opac-readingrecord.pl | 3 +- opac/opac-reserve.pl | 6 +- opac/opac-sendshelf.pl | 2 +- opac/opac-shelves.pl | 2 +- opac/opac-showreviews.pl | 6 +- opac/opac-tags.pl | 5 +- opac/opac-user.pl | 13 +- svc/checkouts | 14 +- svc/holds | 17 +-- t/Biblio.t | 2 +- t/Biblio2.t | 16 +++ tags/list.pl | 5 +- tools/batch_delete_records.pl | 2 +- virtualshelves/sendshelf.pl | 3 +- virtualshelves/shelves.pl | 2 +- 33 files changed, 515 insertions(+), 98 deletions(-) create mode 100644 Koha/Schema/Result/Holding.pm create mode 100644 Koha/Schema/Result/HoldingsMetadata.pm --- a/C4/Biblio.pm +++ a/C4/Biblio.pm @@ -632,39 +632,33 @@ sub _check_valid_auth_link { =head2 GetRecordValue - my $values = GetRecordValue($field, $record, $frameworkcode); + my $values = GetRecordValue($field, $record); -Get MARC fields from a keyword defined in fieldmapping table. +Get MARC fields from the record using the framework mappings for biblio fields. =cut sub GetRecordValue { - my ( $field, $record, $frameworkcode ) = @_; + my ( $field, $record ) = @_; if (!$record) { carp 'GetRecordValue called with undefined record'; return; } - my $dbh = C4::Context->dbh; - - my $sth = $dbh->prepare('SELECT fieldcode, subfieldcode FROM fieldmapping WHERE frameworkcode = ? AND field = ?'); - $sth->execute( $frameworkcode, $field ); - - my @result = (); - - while ( my $row = $sth->fetchrow_hashref ) { - foreach my $field ( $record->field( $row->{fieldcode} ) ) { - if ( ( $row->{subfieldcode} ne "" && $field->subfield( $row->{subfieldcode} ) ) ) { - foreach my $subfield ( $field->subfield( $row->{subfieldcode} ) ) { - push @result, { 'subfield' => $subfield }; - } - } elsif ( $row->{subfieldcode} eq "" ) { - push @result, { 'subfield' => $field->as_string() }; + my @result; + my @mss = GetMarcSubfieldStructureFromKohaField("biblio.$field"); + foreach my $fldhash ( @mss ) { + my $tag = $fldhash->{tagfield}; + my $sub = $fldhash->{tagsubfield}; + foreach my $fld ( $record->field($tag) ) { + if( $sub eq '@' || $fld->is_control_field ) { + push @result, $fld->data if $fld->data; + } else { + push @result, grep { $_ } $fld->subfield($sub); } } } - return \@result; } @@ -3599,6 +3593,22 @@ sub RemoveAllNsb { return $record; } +=head2 SplitSubtitle + + $subtitles = SplitSubtitle($subtitle); + +Splits a subtitle field to an array of hashes like the one GetRecordValue returns + +=cut + +sub SplitSubtitle { + my $subtitle = shift; + + my @subtitles = map( { 'subfield' => $_ }, split(/ \| /, $subtitle // '' ) ); + + return \@subtitles; +} + 1; --- a/C4/HoldsQueue.pm +++ a/C4/HoldsQueue.pm @@ -131,7 +131,12 @@ sub GetHoldsQueueItems { my $dbh = C4::Context->dbh; my @bind_params = (); - my $query = q/SELECT tmp_holdsqueue.*, biblio.author, items.ccode, items.itype, biblioitems.itemtype, items.location, items.enumchron, items.cn_sort, biblioitems.publishercode,biblio.copyrightdate,biblioitems.publicationyear,biblioitems.pages,biblioitems.size,biblioitems.publicationyear,biblioitems.isbn,items.copynumber + my $query = q/SELECT tmp_holdsqueue.*, biblio.author, items.ccode, items.itype, biblioitems.itemtype, items.location, + items.enumchron, items.cn_sort, biblioitems.publishercode, + biblio.copyrightdate, biblio.subtitle, biblio.part_number as numbers, + biblio.part_name as parts, + biblioitems.publicationyear, biblioitems.pages, biblioitems.size, biblioitems.publicationyear, + biblioitems.isbn, items.copynumber FROM tmp_holdsqueue JOIN biblio USING (biblionumber) LEFT JOIN biblioitems USING (biblionumber) @@ -146,19 +151,15 @@ sub GetHoldsQueueItems { $sth->execute(@bind_params); my $items = []; while ( my $row = $sth->fetchrow_hashref ){ - my $record = GetMarcBiblio({ biblionumber => $row->{biblionumber} }); - if ($record){ - $row->{subtitle} = [ map { $_->{subfield} } @{ GetRecordValue( 'subtitle', $record, '' ) } ]; - $row->{parts} = GetRecordValue('parts',$record,'')->[0]->{subfield}; - $row->{numbers} = GetRecordValue('numbers',$record,'')->[0]->{subfield}; - } - # return the bib-level or item-level itype per syspref if (!C4::Context->preference('item-level_itypes')) { $row->{itype} = $row->{itemtype}; } delete $row->{itemtype}; + my @subtitles = split(/ \| /, $row->{'subtitle'} // '' ); + $row->{'subtitle'} = \@subtitles; + push @$items, $row; } return $items; --- a/C4/Overdues.pm +++ a/C4/Overdues.pm @@ -750,6 +750,10 @@ sub GetOverduesForBranch { borrowers.phone, borrowers.email, biblio.title, + biblio.subtitle, + biblio.medium, + biblio.part_number, + biblio.part_name, biblio.author, biblio.biblionumber, issues.date_due, --- a/C4/Search.pm +++ a/C4/Search.pm @@ -1944,7 +1944,7 @@ sub searchResults { SetUTF8Flag($marcrecord); my $oldbiblio = TransformMarcToKoha( $marcrecord, $fw ); - $oldbiblio->{subtitle} = GetRecordValue('subtitle', $marcrecord, $fw); + $oldbiblio->{subtitle} = GetRecordValue('subtitle', $marcrecord); $oldbiblio->{result_number} = $i + 1; # add imageurl to itemtype if there is one --- a/C4/ShelfBrowser.pm +++ a/C4/ShelfBrowser.pm @@ -223,12 +223,15 @@ sub GetShelfInfo { my $this_biblio = GetBibData($item->{biblionumber}); next unless defined $this_biblio; $item->{'title'} = $this_biblio->{'title'}; + $item->{'subtitle'} = C4::Biblio::SplitSubtitle($this_biblio->{'subtitle'}), + $item->{'medium'} = $this_biblio->{'medium'}; + $item->{'part_number'} = $this_biblio->{'part_number'}; + $item->{'part_name'} = $this_biblio->{'part_name'}; my $this_record = GetMarcBiblio({ biblionumber => $this_biblio->{'biblionumber'} }); $item->{'browser_normalized_upc'} = GetNormalizedUPC($this_record,$marcflavour); $item->{'browser_normalized_oclc'} = GetNormalizedOCLCNumber($this_record,$marcflavour); $item->{'browser_normalized_isbn'} = GetNormalizedISBN(undef,$this_record,$marcflavour); $item->{'browser_normalized_ean'} = GetNormalizedEAN($this_record,$marcflavour); - $item->{'subtitle'} = GetRecordValue('subtitle', $this_record, GetFrameworkCode( $item->{biblionumber} )); push @valid_items, $item; } return @valid_items; @@ -239,7 +242,7 @@ sub GetBibData { my ($bibnum) = @_; my $dbh = C4::Context->dbh; - my $sth = $dbh->prepare("SELECT biblionumber, title FROM biblio WHERE biblionumber=?"); + my $sth = $dbh->prepare("SELECT biblionumber, title, subtitle, medium, part_number, part_name FROM biblio WHERE biblionumber=?"); $sth->execute($bibnum); my $bib = $sth->fetchrow_hashref(); return $bib; --- a/Koha/Biblio.pm +++ a/Koha/Biblio.pm @@ -65,20 +65,15 @@ sub store { my @subtitles = $biblio->subtitles(); -Returns list of subtitles for a record. - -Keyword to MARC mapping for subtitle must be set for this method to return any possible values. +Returns list of subtitles for a record according to the framework. =cut sub subtitles { my ( $self ) = @_; - return map { $_->{subfield} } @{ - C4::Biblio::GetRecordValue( - 'subtitle', - C4::Biblio::GetMarcBiblio({ biblionumber => $self->id }), - $self->frameworkcode ) }; + my @subtitles = split( / \| /, $self->subtitle // '' ); + return @subtitles; } =head3 can_article_request --- a/Koha/Schema/Result/Holding.pm +++ a/Koha/Schema/Result/Holding.pm @@ -0,0 +1,242 @@ +use utf8; +package Koha::Schema::Result::Holding; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::Holding + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("holdings"); + +=head1 ACCESSORS + +=head2 holding_id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 biblionumber + + data_type: 'integer' + default_value: 0 + is_foreign_key: 1 + is_nullable: 0 + +=head2 biblioitemnumber + + data_type: 'integer' + default_value: 0 + is_foreign_key: 1 + is_nullable: 0 + +=head2 frameworkcode + + data_type: 'varchar' + default_value: (empty string) + is_nullable: 0 + size: 4 + +=head2 holdingbranch + + data_type: 'varchar' + is_foreign_key: 1 + is_nullable: 1 + size: 10 + +=head2 location + + data_type: 'varchar' + is_nullable: 1 + size: 80 + +=head2 callnumber + + data_type: 'varchar' + is_nullable: 1 + size: 255 + +=head2 suppress + + data_type: 'tinyint' + is_nullable: 1 + +=head2 timestamp + + data_type: 'timestamp' + datetime_undef_if_invalid: 1 + default_value: 'current_timestamp()' + is_nullable: 0 + +=head2 datecreated + + data_type: 'date' + datetime_undef_if_invalid: 1 + is_nullable: 0 + +=head2 deleted_on + + data_type: 'datetime' + datetime_undef_if_invalid: 1 + is_nullable: 1 + +=cut + +__PACKAGE__->add_columns( + "holding_id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "biblionumber", + { + data_type => "integer", + default_value => 0, + is_foreign_key => 1, + is_nullable => 0, + }, + "biblioitemnumber", + { + data_type => "integer", + default_value => 0, + is_foreign_key => 1, + is_nullable => 0, + }, + "frameworkcode", + { data_type => "varchar", default_value => "", is_nullable => 0, size => 4 }, + "holdingbranch", + { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 }, + "location", + { data_type => "varchar", is_nullable => 1, size => 80 }, + "callnumber", + { data_type => "varchar", is_nullable => 1, size => 255 }, + "suppress", + { data_type => "tinyint", is_nullable => 1 }, + "timestamp", + { + data_type => "timestamp", + datetime_undef_if_invalid => 1, + default_value => "current_timestamp()", + is_nullable => 0, + }, + "datecreated", + { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 0 }, + "deleted_on", + { + data_type => "datetime", + datetime_undef_if_invalid => 1, + is_nullable => 1, + }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("holding_id"); + +=head1 RELATIONS + +=head2 biblioitemnumber + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "biblioitemnumber", + "Koha::Schema::Result::Biblioitem", + { biblioitemnumber => "biblioitemnumber" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); + +=head2 biblionumber + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "biblionumber", + "Koha::Schema::Result::Biblio", + { biblionumber => "biblionumber" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); + +=head2 holdingbranch + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "holdingbranch", + "Koha::Schema::Result::Branch", + { branchcode => "holdingbranch" }, + { + is_deferrable => 1, + join_type => "LEFT", + on_delete => "RESTRICT", + on_update => "CASCADE", + }, +); + +=head2 holdings_metadatas + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "holdings_metadatas", + "Koha::Schema::Result::HoldingsMetadata", + { "foreign.holding_id" => "self.holding_id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + +=head2 items + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "items", + "Koha::Schema::Result::Item", + { "foreign.holding_id" => "self.holding_id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07048 @ 2018-10-26 12:34:01 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:iCl1nPLIbzMbSIHTDYHVcA + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; --- a/Koha/Schema/Result/HoldingsMetadata.pm +++ a/Koha/Schema/Result/HoldingsMetadata.pm @@ -0,0 +1,138 @@ +use utf8; +package Koha::Schema::Result::HoldingsMetadata; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Koha::Schema::Result::HoldingsMetadata + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("holdings_metadata"); + +=head1 ACCESSORS + +=head2 id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 holding_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +=head2 format + + data_type: 'varchar' + is_nullable: 0 + size: 16 + +=head2 marcflavour + + data_type: 'varchar' + is_nullable: 0 + size: 16 + +=head2 metadata + + data_type: 'longtext' + is_nullable: 0 + +=head2 deleted_on + + data_type: 'datetime' + datetime_undef_if_invalid: 1 + is_nullable: 1 + +=cut + +__PACKAGE__->add_columns( + "id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "holding_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, + "format", + { data_type => "varchar", is_nullable => 0, size => 16 }, + "marcflavour", + { data_type => "varchar", is_nullable => 0, size => 16 }, + "metadata", + { data_type => "longtext", is_nullable => 0 }, + "deleted_on", + { + data_type => "datetime", + datetime_undef_if_invalid => 1, + is_nullable => 1, + }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("id"); + +=head1 UNIQUE CONSTRAINTS + +=head2 C + +=over 4 + +=item * L + +=item * L + +=item * L + +=back + +=cut + +__PACKAGE__->add_unique_constraint( + "holdings_metadata_uniq_key", + ["holding_id", "format", "marcflavour"], +); + +=head1 RELATIONS + +=head2 holding + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "holding", + "Koha::Schema::Result::Holding", + { holding_id => "holding_id" }, + { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07048 @ 2018-10-26 12:34:01 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:oUc/EZTrVGoRcM1885DOkw + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; --- a/acqui/neworderbiblio.pl +++ a/acqui/neworderbiblio.pl @@ -129,8 +129,8 @@ my @results; foreach my $result ( @{$marcresults} ) { my $marcrecord = C4::Search::new_record_from_zebra( 'biblioserver', $result ); my $biblio = TransformMarcToKoha( $marcrecord, '' ); - $biblio->{subtitles} = GetRecordValue( 'subtitle', GetMarcBiblio({ biblionumber => $biblio->{biblionumber} }), GetFrameworkCode( $biblio->{biblionumber} ) ); + $biblio->{subtitles} = C4::Biblio::SplitSubtitle($biblio->{'subtitle'}); $biblio->{booksellerid} = $booksellerid; push @results, $biblio; --- a/basket/basket.pl +++ a/basket/basket.pl @@ -59,12 +59,10 @@ if (C4::Context->preference('TagsEnabled')) { foreach my $biblionumber ( @bibs ) { $template->param( biblionumber => $biblionumber ); - my $fw = GetFrameworkCode($biblionumber); - my $dat = &GetBiblioData($biblionumber); next unless $dat; my $record = &GetMarcBiblio({ biblionumber => $biblionumber }); - $dat->{subtitle} = GetRecordValue('subtitle', $record, $fw); + $dat->{subtitle} = GetRecordValue('subtitle', $record); my $marcnotesarray = GetMarcNotes( $record, $marcflavour ); my $marcauthorsarray = GetMarcAuthors( $record, $marcflavour ); my $marcsubjctsarray = GetMarcSubjects( $record, $marcflavour ); --- a/catalogue/detail.pl +++ a/catalogue/detail.pl @@ -141,7 +141,7 @@ my $marcsubjctsarray = GetMarcSubjects( $record, $marcflavour ); my $marcseriesarray = GetMarcSeries($record,$marcflavour); my $marcurlsarray = GetMarcUrls ($record,$marcflavour); my $marchostsarray = GetMarcHosts($record,$marcflavour); -my $subtitle = GetRecordValue('subtitle', $record, $fw); +my $subtitle = GetRecordValue('subtitle', $record); my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search->unblessed } }; --- a/catalogue/moredetail.pl +++ a/catalogue/moredetail.pl @@ -110,7 +110,7 @@ if (@hostitems){ push (@items,@hostitems); } -my $subtitle = GetRecordValue('subtitle', $record, $fw); +my $subtitle = GetRecordValue('subtitle', $record); my $totalcount=@all_items; my $showncount=@items; --- a/circ/branchoverdues.pl +++ a/circ/branchoverdues.pl @@ -74,13 +74,13 @@ if ($tagslib->{$tag}->{$subfield}->{authorised_value}) { # now display infos foreach my $num (@getoverdues) { my %overdueforbranch; - my $record = GetMarcBiblio({ biblionumber => $num->{biblionumber} }); - if ($record){ - $overdueforbranch{'subtitle'} = GetRecordValue('subtitle',$record,'')->[0]->{subfield}; - } my $dt = dt_from_string($num->{date_due}, 'sql'); $overdueforbranch{'date_due'} = output_pref($dt); $overdueforbranch{'title'} = $num->{'title'}; + $overdueforbranch{'subtitle'} = $num->{'subtitle'}; + $overdueforbranch{'medium'} = $num->{'medium'}; + $overdueforbranch{'part_number'} = $num->{'part_number'}; + $overdueforbranch{'part_name'} = $num->{'part_name'}; $overdueforbranch{'description'} = $num->{'description'}; $overdueforbranch{'barcode'} = $num->{'barcode'}; $overdueforbranch{'biblionumber'} = $num->{'biblionumber'}; --- a/circ/reserveratios.pl +++ a/circ/reserveratios.pl @@ -27,7 +27,6 @@ use C4::Context; use C4::Output; use C4::Auth; use C4::Debug; -use C4::Biblio qw/GetMarcBiblio GetRecordValue GetFrameworkCode/; use C4::Acquisition qw/GetOrdersByBiblionumber/; use Koha::DateUtils; use Koha::Acquisition::Baskets; @@ -125,6 +124,10 @@ my $strsth = reserves.found, biblio.title, + biblio.subtitle, + biblio.medium, + biblio.part_number, + biblio.part_name, biblio.author, count(DISTINCT reserves.borrowernumber) as reservecount, count(DISTINCT items.itemnumber) $include_aqorders_qty as itemcount @@ -154,8 +157,6 @@ while ( my $data = $sth->fetchrow_hashref ) { my $thisratio = $data->{reservecount} / $data->{itemcount}; my $ratiocalc = ($thisratio / $ratio); ($thisratio / $ratio) >= 1 or next; # TODO: tighter targeting -- get ratio limit into SQL using HAVING clause - my $record = GetMarcBiblio({ biblionumber => $data->{biblionumber} }); - $data->{subtitle} = GetRecordValue('subtitle', $record, GetFrameworkCode($data->{biblionumber})); push( @reservedata, { @@ -163,7 +164,7 @@ while ( my $data = $sth->fetchrow_hashref ) { priority => $data->{priority}, name => $data->{borrower}, title => $data->{title}, - subtitle => $data->{subtitle}, + subtitle => C4::Biblio::SplitSubtitle($data->{'subtitle'}); author => $data->{author}, itemnum => $data->{itemnumber}, biblionumber => $data->{biblionumber}, --- a/circ/transferstoreceive.pl +++ a/circ/transferstoreceive.pl @@ -99,6 +99,10 @@ while ( my $library = $libraries->next ) { %getransf = ( %getransf, title => $biblio->title, + subtitle => C4::Biblio::SplitSubtitle($biblio->{'subtitle'}), + medium => $biblio->medium, + part_number => $biblio->part_number, + part_name => $biblio->part_name, author => $biblio->author, biblionumber => $biblio->biblionumber, itemnumber => $item->itemnumber, @@ -108,9 +112,6 @@ while ( my $library = $libraries->next ) { itemcallnumber => $item->itemcallnumber, ); - my $record = GetMarcBiblio({ biblionumber => $biblio->biblionumber }); - $getransf{'subtitle'} = GetRecordValue('subtitle', $record, $biblio->frameworkcode); - # we check if we have a reserv for this transfer my $holds = $item->current_holds; if ( my $first_hold = $holds->next ) { --- a/circ/waitingreserves.pl +++ a/circ/waitingreserves.pl @@ -101,6 +101,10 @@ while ( my $hold = $holds->next ) { my %getreserv = ( title => $biblio->title, + subtitle => C4::Biblio::SplitSubtitle($biblio->subtitle), + medium => $biblio->medium, + part_number => $biblio->part_number, + part_name => $biblio->part_name, itemnumber => $item->itemnumber, waitingdate => $hold->waitingdate, reservedate => $hold->reservedate, @@ -122,10 +126,6 @@ while ( my $hold = $holds->next ) { my $calcDate = Date_to_Days( $expire_year, $expire_month, $expire_day ); $getreserv{'itemtype'} = $itemtype->description; # FIXME Should not it be translated_description? - $getreserv{'subtitle'} = GetRecordValue( - 'subtitle', - GetMarcBiblio({ biblionumber => $biblio->biblionumber }), - $biblio->frameworkcode); if ( $homebranch ne $holdingbranch ) { $getreserv{'dotransfer'} = 1; } --- a/opac/opac-basket.pl +++ a/opac/opac-basket.pl @@ -105,7 +105,7 @@ foreach my $biblionumber ( @bibs ) { } } - my $subtitle = GetRecordValue('subtitle', $record, GetFrameworkCode($biblionumber)); + my $subtitle = GetRecordValue('subtitle', $record); my $hasauthors = 0; if($dat->{'author'} || @$marcauthorsarray) { --- a/opac/opac-detail.pl +++ a/opac/opac-detail.pl @@ -767,7 +767,7 @@ if (!C4::Context->preference("OPACXSLTDetailsDisplay") ) { } my $marcnotesarray = GetMarcNotes ($record,$marcflavour); -my $subtitle = GetRecordValue('subtitle', $record, GetFrameworkCode($biblionumber)); +my $subtitle = GetRecordValue('subtitle', $record); if( C4::Context->preference('ArticleRequests') ) { my $patron = $borrowernumber ? Koha::Patrons->find($borrowernumber) : undef; --- a/opac/opac-readingrecord.pl +++ a/opac/opac-readingrecord.pl @@ -97,8 +97,7 @@ foreach my $issue ( @{$issues} ) { my $marc_rec = MARC::Record::new_from_xml( $marcxml, 'utf8', C4::Context->preference('marcflavour') ); - $issue->{subtitle} = - GetRecordValue( 'subtitle', $marc_rec, $issue->{frameworkcode} ); + $issue->{subtitle} = GetRecordValue( 'subtitle', $marc_rec ); $issue->{normalized_upc} = GetNormalizedUPC( $marc_rec, C4::Context->preference('marcflavour') ); } # My Summary HTML --- a/opac/opac-reserve.pl +++ a/opac/opac-reserve.pl @@ -390,7 +390,6 @@ $template->param('item_level_itypes' => $itemLevelTypes); foreach my $biblioNum (@biblionumbers) { my @not_available_at = (); - my $record = GetMarcBiblio({ biblionumber => $biblioNum }); # Init the bib item with the choices for branch pickup my %biblioLoopIter; @@ -404,7 +403,10 @@ foreach my $biblioNum (@biblionumbers) { my $frameworkcode = GetFrameworkCode( $biblioData->{biblionumber} ); $biblioLoopIter{biblionumber} = $biblioData->{biblionumber}; $biblioLoopIter{title} = $biblioData->{title}; - $biblioLoopIter{subtitle} = GetRecordValue('subtitle', $record, $frameworkcode); + $biblioLoopIter{subtitle} = C4::Biblio::SplitSubtitle($biblioData->{'subtitle'}); + $biblioLoopIter{medium} = $biblioData->{medium}; + $biblioLoopIter{part_number} = $biblioData->{part_number}; + $biblioLoopIter{part_name} = $biblioData->{part_name}; $biblioLoopIter{author} = $biblioData->{author}; $biblioLoopIter{rank} = $biblioData->{rank}; $biblioLoopIter{reservecount} = $biblioData->{reservecount}; --- a/opac/opac-sendshelf.pl +++ a/opac/opac-sendshelf.pl @@ -101,7 +101,7 @@ if ( $email ) { my $marcauthorsarray = GetMarcAuthors( $record, $marcflavour ); my $marcsubjctsarray = GetMarcSubjects( $record, $marcflavour ); - my $subtitle = GetRecordValue('subtitle', $record, $fw); + my $subtitle = GetRecordValue('subtitle', $record); my @items = GetItemsInfo( $biblionumber ); --- a/opac/opac-shelves.pl +++ a/opac/opac-shelves.pl @@ -295,7 +295,7 @@ if ( $op eq 'view' ) { $this_item->{notforloan} = $itemtype->notforloan; } $this_item->{'coins'} = GetCOinSBiblio($record); - $this_item->{'subtitle'} = GetRecordValue( 'subtitle', $record, GetFrameworkCode( $biblionumber ) ); + $this_item->{'subtitle'} = GetRecordValue( 'subtitle', $record ), $this_item->{'normalized_upc'} = GetNormalizedUPC( $record, $marcflavour ); $this_item->{'normalized_ean'} = GetNormalizedEAN( $record, $marcflavour ); $this_item->{'normalized_oclc'} = GetNormalizedOCLCNumber( $record, $marcflavour ); --- a/opac/opac-showreviews.pl +++ a/opac/opac-showreviews.pl @@ -91,13 +91,15 @@ for my $result (@$reviews){ my $biblio = Koha::Biblios->find( $biblionumber ); my $biblioitem = $biblio->biblioitem; my $record = GetMarcBiblio({ biblionumber => $biblionumber }); - my $frameworkcode = GetFrameworkCode($biblionumber); $result->{normalized_upc} = GetNormalizedUPC($record,$marcflavour); $result->{normalized_ean} = GetNormalizedEAN($record,$marcflavour); $result->{normalized_oclc} = GetNormalizedOCLCNumber($record,$marcflavour); $result->{normalized_isbn} = GetNormalizedISBN(undef,$record,$marcflavour); $result->{title} = $biblio->title; - $result->{subtitle} = GetRecordValue('subtitle', $record, $frameworkcode); + $result->{subtitle} = GetRecordValue('subtitle', $record ); + $result->{medium} = $biblio->medium; + $result->{part_number} = $biblio->part_number; + $result->{part_name} = $biblio->part_name; $result->{author} = $biblio->author; $result->{place} = $biblioitem->place; $result->{publishercode} = $biblioitem->publishercode; --- a/opac/opac-tags.pl +++ a/opac/opac-tags.pl @@ -256,8 +256,11 @@ if ($loggedinuser) { $hidden_items = \@hidden_itemnumbers; } next if ( $should_hide && scalar @all_items == scalar @hidden_itemnumbers ); - $tag->{subtitle} = GetRecordValue( 'subtitle', $record, GetFrameworkCode( $tag->{biblionumber} ) ); $tag->{title} = $biblio->title; + $tag->{subtitle} = C4::Biblio::SplitSubtitle($biblio->subtitle); + $tag->{medium} = $biblio->medium; + $tag->{part_number} = $biblio->part_number; + $tag->{part_name} = $biblio->part_name; $tag->{author} = $biblio->author; my $xslfile = C4::Context->preference('OPACXSLTResultsDisplay'); --- a/opac/opac-user.pl +++ a/opac/opac-user.pl @@ -212,12 +212,8 @@ if ( $pending_checkouts->count ) { # Useless test ); $issue->{rentalfines} = $rental_fines->total_outstanding; - my $marcrecord = GetMarcBiblio({ - biblionumber => $issue->{'biblionumber'}, - embed_items => 1, - opac => 1, - borcat => $borcat }); - $issue->{'subtitle'} = GetRecordValue('subtitle', $marcrecord, GetFrameworkCode($issue->{'biblionumber'})); + $issue->{'subtitle'} = C4::Biblio::SplitSubtitle($issue->{'subtitle'}); + # check if item is renewable my ($status,$renewerror) = CanBookBeRenewed( $borrowernumber, $issue->{'itemnumber'} ); ($issue->{'renewcount'},$issue->{'renewsallowed'},$issue->{'renewsleft'}) = GetRenewCount($borrowernumber, $issue->{'itemnumber'}); @@ -267,6 +263,11 @@ if ( $pending_checkouts->count ) { # Useless test my $isbn = GetNormalizedISBN($issue->{'isbn'}); $issue->{normalized_isbn} = $isbn; + my $marcrecord = GetMarcBiblio({ + biblionumber => $issue->{'biblionumber'}, + embed_items => 1, + opac => 1, + borcat => $borcat }); $issue->{normalized_upc} = GetNormalizedUPC( $marcrecord, C4::Context->preference('marcflavour') ); # My Summary HTML --- a/svc/checkouts +++ a/svc/checkouts @@ -23,7 +23,7 @@ use CGI; use JSON qw(to_json); use C4::Auth qw(check_cookie_auth haspermission get_session); -use C4::Biblio qw(GetMarcBiblio GetFrameworkCode GetRecordValue ); +use C4::Biblio qw(SplitSubtitle); use C4::Circulation qw(GetIssuingCharges CanBookBeRenewed GetRenewCount GetSoonestRenewDate); use C4::Overdues qw(GetFine); use C4::Context; @@ -74,6 +74,10 @@ my $sql = ' biblionumber, biblio.title, + biblio.subtitle, + biblio.medium, + biblio.part_number, + biblio.part_name, author, itemnumber, @@ -174,6 +178,10 @@ while ( my $c = $sth->fetchrow_hashref() ) { my $checkout = { DT_RowId => $c->{itemnumber} . '-' . $c->{borrowernumber}, title => $c->{title}, + subtitle => C4::Biblio::SplitSubtitle($c->{'subtitle'}), + medium => $c->{medium}, + part_number => $c->{part_number}, + part_name => $c->{part_name}, author => $c->{author}, barcode => $c->{barcode}, itemtype => $item_level_itypes ? $c->{itype} : $c->{itemtype}, @@ -216,10 +224,6 @@ while ( my $c = $sth->fetchrow_hashref() ) { as_due_date => 1 } ), - subtitle => GetRecordValue( - 'subtitle', - GetMarcBiblio({ biblionumber => $c->{biblionumber} }), - GetFrameworkCode( $c->{biblionumber} ) ), lost => $lost, damaged => $damaged, borrower => { --- a/svc/holds +++ a/svc/holds @@ -23,7 +23,7 @@ use CGI; use JSON qw(to_json); use C4::Auth qw(check_cookie_auth); -use C4::Biblio qw(GetMarcBiblio GetFrameworkCode GetRecordValue ); +use C4::Biblio qw(SplitSubtitle); use C4::Charset; use C4::Circulation qw(GetTransfers); use C4::Context; @@ -84,11 +84,17 @@ while ( my $h = $holds_rs->next() ) { for my $library ( @$libraries ) { $library->{selected} = 1 if $library->{branchcode} eq $h->branchcode(); } + + my $biblio = $h->biblio(); my $hold = { DT_RowId => $h->reserve_id(), biblionumber => $biblionumber, - title => $h->biblio()->title(), - author => $h->biblio()->author(), + title => $biblio->title(), + subtitle => C4::Biblio::SplitSubtitles($biblio->subtitle()), + medium => $biblio->medium(), + part_number => $biblio->part_number(), + part_name => $biblio->part_name(), + author => $biblio->author(), reserve_id => $h->reserve_id(), branchcode => $h->branch()->branchname(), branches => $libraries, @@ -102,11 +108,6 @@ while ( my $h = $holds_rs->next() ) { waiting_here => $h->branch()->branchcode() eq $branch, priority => $h->priority(), itemtype_limit => $itemtype_limit, - subtitle => GetRecordValue( - 'subtitle', - GetMarcBiblio({ biblionumber => $biblionumber }), - GetFrameworkCode($biblionumber) - ), reservedate_formatted => $h->reservedate() ? output_pref( { dt => dt_from_string( $h->reservedate() ), dateonly => 1 } ) --- a/t/Biblio.t +++ a/t/Biblio.t @@ -51,7 +51,7 @@ warning_is { $ret = BiblioAutoLink(undef, q{}) } is( $ret, 0, 'BiblioAutoLink returns zero if not passed rec'); -warning_is { $ret = GetRecordValue('100', undef, q{}) } +warning_is { $ret = GetRecordValue('100', undef) } { carped => 'GetRecordValue called with undefined record'}, "GetRecordValue returns carped warning on undef record"; --- a/t/Biblio2.t +++ a/t/Biblio2.t @@ -52,4 +52,20 @@ sub _koha_marc_update_bib_ids_control { is($r->field('004')->data(), 20, 'Biblioitemnumber to control field'); } +subtest 'SplitSubtitle' => sub { + plan tests => 4; + + my $res = C4::Biblio::SplitSubtitle(undef); + is_deeply($res, [], 'undef returned as an array'); + + $res = C4::Biblio::SplitSubtitle(''); + is_deeply($res, [], 'Empty string returned as an array'); + + $res = C4::Biblio::SplitSubtitle('Single'); + is_deeply($res, [{'subfield' => 'Single'}], 'Single subtitle returns an array'); + + $res = C4::Biblio::SplitSubtitle('First | Second'); + is_deeply($res, [{'subfield' => 'First'}, {'subfield' => 'Second'}], 'Two subtitles returns an array'); +}; + done_testing(); --- a/tags/list.pl +++ a/tags/list.pl @@ -61,10 +61,7 @@ else { my $taglist = get_tag_rows( { term => $tag } ); for ( @{$taglist} ) { my $dat = &GetBiblioData( $_->{biblionumber} ); - my $record = &GetMarcBiblio({ biblionumber => $_->{biblionumber} }); - $dat->{'subtitle'} = - GetRecordValue( 'subtitle', $record, - GetFrameworkCode( $_->{biblionumber} ) ); + $dat->{'subtitle'} = C4::Biblio::SplitSubtitles($dat->{'subtitle'}), my @items = GetItemsInfo( $_->{biblionumber} ); $dat->{biblionumber} = $_->{biblionumber}; $dat->{tag_id} = $_->{tag_id}; --- a/tools/batch_delete_records.pl +++ a/tools/batch_delete_records.pl @@ -84,7 +84,7 @@ if ( $op eq 'form' ) { my $holds_count = $biblio->holds->count; $biblio = $biblio->unblessed; my $record = &GetMarcBiblio({ biblionumber => $record_id }); - $biblio->{subtitle} = GetRecordValue( 'subtitle', $record, GetFrameworkCode( $record_id ) ); + $biblio->{subtitle} = C4::Biblio::SplitSubtitle( $biblio->{subtitle} ); $biblio->{itemnumbers} = [Koha::Items->search({ biblionumber => $record_id })->get_column('itemnumber')]; $biblio->{holds_count} = $holds_count; $biblio->{issues_count} = C4::Biblio::CountItemsIssued( $record_id ); --- a/virtualshelves/sendshelf.pl +++ a/virtualshelves/sendshelf.pl @@ -77,14 +77,13 @@ if ($email) { while ( my $content = $contents->next ) { my $biblionumber = $content->biblionumber; - my $fw = GetFrameworkCode($biblionumber); my $dat = GetBiblioData($biblionumber); my $record = GetMarcBiblio({ biblionumber => $biblionumber, embed_items => 1 }); my $marcauthorsarray = GetMarcAuthors( $record, $marcflavour ); my $marcsubjctsarray = GetMarcSubjects( $record, $marcflavour ); - my $subtitle = GetRecordValue( 'subtitle', $record, $fw ); + my $subtitle = GetRecordValue( 'subtitle', $record ); my @items = GetItemsInfo($biblionumber); --- a/virtualshelves/shelves.pl +++ a/virtualshelves/shelves.pl @@ -279,7 +279,7 @@ if ( $op eq 'view' ) { $this_item->{description} = $itemtype ? $itemtype->description : q{}; #FIXME Should this be translated_description ? $this_item->{notforloan} = $itemtype->notforloan if $itemtype; $this_item->{'coins'} = GetCOinSBiblio($record); - $this_item->{'subtitle'} = GetRecordValue( 'subtitle', $record, GetFrameworkCode( $biblionumber ) ); + $this_item->{'subtitle'} = GetRecordValue( 'subtitle', $record ); $this_item->{'normalized_upc'} = GetNormalizedUPC( $record, $marcflavour ); $this_item->{'normalized_ean'} = GetNormalizedEAN( $record, $marcflavour ); $this_item->{'normalized_oclc'} = GetNormalizedOCLCNumber( $record, $marcflavour ); --