From f192f248faa67da7f05ad8fde16b03303d23c002 Mon Sep 17 00:00:00 2001 From: Ere Maijala Date: Mon, 27 Aug 2018 15:07:12 +0300 Subject: [PATCH] Bug 20447: Include basic summary holdings in the OAI-PMH responses. https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=20447 If include_items is set in oai conf, also basic location information from holdings records is included in the returned MARC records. --- C4/Biblio.pm | 6 ++++ C4/Holdings.pm | 75 +++++++++++++++++++++++++++++++++++++++++++ Koha/OAI/Server/ListBase.pm | 10 ++++-- Koha/OAI/Server/Repository.pm | 1 + 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/C4/Biblio.pm b/C4/Biblio.pm index d9b30c4..a9f8bca 100644 --- a/C4/Biblio.pm +++ b/C4/Biblio.pm @@ -2791,6 +2791,12 @@ sub EmbedItemsInMarcBiblio { $itemnumbers = [] unless defined $itemnumbers; + if ( C4::Context->preference('SummaryHoldings') && !@$itemnumbers ) { + require C4::Holdings; + my $holdings_fields = C4::Holdings::GetMarcHoldingsFields( $biblionumber ); + $marc->append_fields(@$holdings_fields) if ( @$holdings_fields ); + } + my $frameworkcode = GetFrameworkCode($biblionumber); _strip_item_fields($marc, $frameworkcode); diff --git a/C4/Holdings.pm b/C4/Holdings.pm index c3d4446..5fbcc0b 100644 --- a/C4/Holdings.pm +++ b/C4/Holdings.pm @@ -414,6 +414,35 @@ sub GetMarcHoldingsByBiblionumber { return \@records; } +=head2 GetMarcHoldingsFields + + my @marc_fields = GetMarcHoldingsFields($biblionumber); + +Returns an array of MARC::Record objects of the holdings for the biblio. + +=cut + +sub GetMarcHoldingsFields { + my ( $biblionumber ) = @_; + # This is so much faster than using Koha::Holdings->search that it makes sense even if it's ugly. + my $sth = C4::Context->dbh->prepare( 'SELECT * FROM holdings WHERE biblionumber = ?' ); + $sth->execute( $biblionumber ); + my $holdings = $sth->fetchall_arrayref({}); + $sth->finish(); + my @holdings_fields; + my ( $holdingstag, $holdingssubfield ) = GetMarcHoldingFromKohaField( 'holdings.holdingbranch' ); + ITEMLOOP: foreach my $holding (@$holdings) { + my $mungedholding = { + map { + defined($holding->{$_}) && $holding->{$_} ne '' ? ("holdings.$_" => $holding->{$_}) : () + } keys %{ $holding } + }; + my $marc = TransformKohaHoldingToMarc($mungedholding); + push @holdings_fields, $marc->field( $holdingstag ); + } + return \@holdings_fields; +} + =head2 GetHoldingFrameworkCode $frameworkcode = GetFrameworkCode( $holding_id ) @@ -775,6 +804,52 @@ sub TransformMarcHoldingToKohaOneField { return $retval; } +=head2 TransformKohaToMarc + + $record = TransformKohaToMarc( $hash [, $params ] ) + +This function builds partial MARC::Record from holdings hash entries. +This function is called when embedding holdings into a biblio record. + +=cut + +sub TransformKohaHoldingToMarc { + my ( $hash, $params ) = @_; + my $record = MARC::Record->new(); + SetMarcUnicodeFlag( $record, C4::Context->preference("marcflavour") ); + + # In the next call we use the Default holdings framework, since it is considered + # authoritative for Koha to Marc mappings. + my $mss = C4::Biblio::GetMarcSubfieldStructure( 'HLD', { unsafe => 1 } ); # do not change framewok + my $tag_hr = {}; + while ( my ($kohafield, $value) = each %$hash ) { + foreach my $fld ( @{ $mss->{$kohafield} } ) { + my $tagfield = $fld->{tagfield}; + my $tagsubfield = $fld->{tagsubfield}; + next if !$tagfield; + my @values = $params->{no_split} + ? ( $value ) + : split(/\s?\|\s?/, $value, -1); + foreach my $value ( @values ) { + next if $value eq ''; + $tag_hr->{$tagfield} //= []; + push @{$tag_hr->{$tagfield}}, [($tagsubfield, $value)]; + } + } + } + foreach my $tag (sort keys %$tag_hr) { + my @sfl = @{$tag_hr->{$tag}}; + @sfl = sort { $a->[0] cmp $b->[0]; } @sfl; + @sfl = map { @{$_}; } @sfl; + # Special care for control fields: remove the subfield indication @ + # and do not insert indicators. + my @ind = $tag < 10 ? () : ( " ", " " ); + @sfl = grep { $_ ne '@' } @sfl if $tag < 10; + $record->insert_fields_ordered( MARC::Field->new($tag, @ind, @sfl) ); + } + return $record; +} + 1; diff --git a/Koha/OAI/Server/ListBase.pm b/Koha/OAI/Server/ListBase.pm index 92af1c3..dbaa492 100644 --- a/Koha/OAI/Server/ListBase.pm +++ b/Koha/OAI/Server/ListBase.pm @@ -69,8 +69,9 @@ sub GetRecords { if ($include_items) { $sql .= " OR biblionumber IN (SELECT biblionumber from deleteditems WHERE timestamp >= ? AND timestamp <= ?) + OR biblionumber IN (SELECT biblionumber from holdings WHERE timestamp >= ? AND timestamp <= ?) "; - push @bind_params, ($token->{'from_arg'}, $token->{'until_arg'}); + push @bind_params, ($token->{'from_arg'}, $token->{'until_arg'}, $token->{'from_arg'}, $token->{'until_arg'}); if (!$deleted) { $sql .= " OR biblionumber IN (SELECT biblionumber from items WHERE timestamp >= ? AND timestamp <= ?) @@ -106,6 +107,8 @@ sub GetRecords { SELECT timestamp FROM deletedbiblio_metadata WHERE biblionumber = ? UNION SELECT timestamp FROM deleteditems WHERE biblionumber = ? + UNION + SELECT timestamp FROM holdings WHERE biblionumber = ? ) bis "; } else { @@ -117,6 +120,8 @@ sub GetRecords { SELECT timestamp FROM deleteditems WHERE biblionumber = ? UNION SELECT timestamp FROM items WHERE biblionumber = ? + UNION + SELECT timestamp FROM holdings WHERE biblionumber = ? ) bi "; } @@ -139,7 +144,8 @@ sub GetRecords { ); last STAGELOOP; } - my @params = $deleted ? ( $biblionumber, $biblionumber ) : ( $biblionumber, $biblionumber, $biblionumber ); + my @params = $deleted ? ( $biblionumber, $biblionumber, $biblionumber ) + : ( $biblionumber, $biblionumber, $biblionumber, $biblionumber ); $record_sth->execute( @params ) || die( 'Could not execute statement: ' . $sth->errstr ); my ($timestamp) = $record_sth->fetchrow; diff --git a/Koha/OAI/Server/Repository.pm b/Koha/OAI/Server/Repository.pm index 30ace36..e95200d 100644 --- a/Koha/OAI/Server/Repository.pm +++ b/Koha/OAI/Server/Repository.pm @@ -93,6 +93,7 @@ mode. A configuration file koha-oai.conf can look like that: xsl_file: /usr/local/koha/koha-tmpl/intranet-tmpl/xslt/UNIMARCslim2OAIDC.xsl Note the 'include_items' parameter which is the only mean to return item-level info. +If summary holdings are enabled, 'include_items' includes their location information too. =cut -- 2.7.4