Bug 30848: Add an ExpandCodedFields RecordProcessor filter

This patch introduces a RecordProcessor filter for MARC::Record objects
that replaces Koha codes with descriptions in the MARC::Record passed to the processor.

Target usage:

  my $biblio = Koha::Biblios->find(
      $biblio_id,
      { prefetch => [ metadata ] }
  );

  my $record = $biblio->metadata->record;

  my $processor = Koha::RecordProcessor->new(
    {
        filters => ('ExpandCodedFields'),
        options => {
            interface     => 'opac',
            frameworkcode => $biblio->frameworkcode
        }
    }
  );

  $processor->process( $record );

Test plan
* Read the included unit test and confirm it makes sense and passes

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>
Signed-off-by: Tomas Cohen Arazi <tomascohen@theke.io>
(cherry picked from commit 62bba6d9e1)

Signed-off-by: Lucas Gass <lucas@bywatersolutions.com>
(cherry picked from commit 0a86104294)
Signed-off-by: Arthur Suzuki <arthur.suzuki@biblibre.com>
(cherry picked from commit 52dd29792e)
Signed-off-by: Victor Grousset/tuxayo <victor@tuxayo.net>
This commit is contained in:
Martin Renvoize 2022-05-26 10:24:50 +01:00 committed by Victor Grousset/tuxayo
parent 1d4dbdab06
commit 26e2f2c11a
5 changed files with 243 additions and 0 deletions

View File

@ -0,0 +1,140 @@
package Koha::Filter::MARC::ExpandCodedFields;
# Copyright 2022 PTFS Europe
#
# 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 3 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, see <http://www.gnu.org/licenses>.
=head1 NAME
Koha::Filter::MARC::ExpandCodedFields - Replaces AV codes with descriptions in MARC::Record objects.
=head1 SYNOPSIS
my $biblio = Koha::Biblios->find(
$biblio_id,
{ prefetch => [ metadata ] }
);
my $record = $biblio->metadata->record;
my $record_processor = Koha::RecordProcessor->new(
{
filters => ['ExpandCodedFields'],
options => {
interface => 'opac',
}
}
);
$record_processor->process($record);
=head1 DESCRIPTION
Filter to replace Koha AV codes in MARC::Records with their Koha AV descriptions.
=cut
use Modern::Perl;
use C4::Biblio qw( GetAuthorisedValueDesc );
use Koha::Caches;
use base qw(Koha::RecordProcessor::Base);
our $NAME = 'ExpandCodedFields';
=head2 filter
Embed items into the MARC::Record object.
=cut
sub filter {
my $self = shift;
my $record = shift;
return unless defined $record and ref($record) eq 'MARC::Record';
my $params = $self->params;
my $interface = $params->{options}->{interface} // 'opac';
my $opac = $interface eq 'opac' ? 1 : 0;
my $frameworkcode = $params->{options}->{frameworkcode} // q{};
my $marcflavour = C4::Context->preference('marcflavour');
my $coded_fields = _getCodedFields($frameworkcode);
for my $tag ( keys %$coded_fields ) {
for my $field ( $record->field($tag) ) {
my @new_subfields = ();
for my $subfield ( $field->subfields() ) {
my ( $letter, $value ) = @$subfield;
# Replace the field value with the authorised value
# *except* for MARC21 field 942$n (suppression in opac)
if ( !( $tag eq '942' && $subfield->[0] eq 'n' )
|| $marcflavour eq 'UNIMARC' )
{
$value =
GetAuthorisedValueDesc( $tag, $letter, $value, '',
$coded_fields, undef, $opac )
if $coded_fields->{$tag}->{$letter};
}
push( @new_subfields, $letter, $value );
}
$field->replace_with(
MARC::Field->new(
$tag, $field->indicator(1),
$field->indicator(2), @new_subfields
)
);
}
}
return $record;
}
sub _getCodedFields {
my ($frameworkcode) = @_;
$frameworkcode //= "";
my $cache = Koha::Caches->get_instance();
my $cache_key = "MarcCodedFields-$frameworkcode";
my $cached = $cache->get_from_cache( $cache_key, { unsafe => 1 } );
return $cached if $cached;
my $coded_fields = {
map {
$_->tagfield => {
$_->tagsubfield => {
'authorised_value' => $_->authorised_value
}
}
} Koha::MarcSubfieldStructures->search(
{
frameworkcode => $frameworkcode,
authorised_value => { '>' => '' }
},
{
columns => [ 'tagfield', 'tagsubfield', 'authorised_value' ],
order_by => [ 'tagfield', 'tagsubfield' ]
}
)->as_list
};
$cache->set_in_cache( $cache_key, $coded_fields );
return $coded_fields;
}
1;

View File

@ -81,6 +81,7 @@ if ( $op eq 'add_form' ) {
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
$op = 'list';
} elsif ( $op eq 'delete_confirm' ) {
my $framework = Koha::BiblioFrameworks->find($frameworkcode);
@ -112,6 +113,7 @@ if ( $op eq 'add_form' ) {
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
$op = 'list';
}

View File

@ -310,6 +310,7 @@ elsif ( $op eq 'add_validate' ) {
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
print $input->redirect("/cgi-bin/koha/admin/marc_subfields_structure.pl?tagfield=$tagfield&amp;frameworkcode=$frameworkcode");
exit;
@ -348,6 +349,7 @@ elsif ( $op eq 'delete_confirmed' ) {
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
print $input->redirect("/cgi-bin/koha/admin/marc_subfields_structure.pl?tagfield=$tagfield&amp;frameworkcode=$frameworkcode");
exit;

View File

@ -157,6 +157,7 @@ if ($op eq 'add_form') {
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
print $input->redirect("/cgi-bin/koha/admin/marctagstructure.pl?searchfield=$tagfield&frameworkcode=$frameworkcode");
exit;
# END $OP eq ADD_VALIDATE
@ -182,6 +183,7 @@ if ($op eq 'add_form') {
$cache->clear_from_cache("MarcStructure-1-$frameworkcode");
$cache->clear_from_cache("default_value_for_mod_marc-");
$cache->clear_from_cache("MarcSubfieldStructure-$frameworkcode");
$cache->clear_from_cache("MarcCodedFields-$frameworkcode");
$template->param( searchfield => $searchfield );
# END $OP eq DELETE_CONFIRMED
################## ITEMTYPE_CREATE ##################################

View File

@ -0,0 +1,97 @@
#!/usr/bin/perl
# 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 3 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, see <http://www.gnu.org/licenses>.
use Modern::Perl;
use Test::More tests => 1;
use t::lib::TestBuilder;
use C4::Biblio qw( GetMarcSubfieldStructure );
use Koha::Database;
use Koha::AuthorisedValueCategory;
use Koha::Caches;
use Koha::RecordProcessor;
my $schema = Koha::Database->schema();
my $builder = t::lib::TestBuilder->new();
subtest 'ExpandCodedFields tests' => sub {
plan tests => 10;
$schema->storage->txn_begin();
# Add a biblio
my $biblio = $builder->build_sample_biblio;
my $record = $biblio->metadata->record;
$record->field('942')->update( n => 1 );
$record->append_fields(
MARC::Field->new( '590', '', '', a => 'CODE' ),
);
Koha::AuthorisedValueCategory->new({ category_name => 'TEST' })->store;
Koha::AuthorisedValue->new(
{
category => 'TEST',
authorised_value => 'CODE',
lib => 'Description should show',
lib_opac => 'Description should show OPAC'
}
)->store;
my $mss = Koha::MarcSubfieldStructures->find({tagfield => "590", tagsubfield => "a", frameworkcode => $biblio->frameworkcode });
$mss->update({ authorised_value => "TEST" });
my $cache = Koha::Caches->get_instance;
$cache->clear_from_cache("MarcCodedFields-");
C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
$biblio = Koha::Biblios->find( $biblio->biblionumber);
$record = $biblio->metadata->record;
is( $record->field('590')->subfield('a'), 'CODE', 'Record prior to filtering contains AV Code' );
is( $record->field('942')->subfield('n'), 1, 'Record suppression is numeric prior to filtering' );
my $processor = Koha::RecordProcessor->new(
{
schema => 'MARC',
filters => ['ExpandCodedFields'],
}
);
is( ref($processor), 'Koha::RecordProcessor', 'Created record processor with ExpandCodedFields filter' );
my $result = $processor->process( $record );
is( ref($result), 'MARC::Record', 'It returns a reference to a MARC::Record object' );
is( $result->field('590')->subfield('a'), 'Description should show OPAC', 'Returned record contains AV OPAC description (interface defaults to opac)' );
is( $record->field('590')->subfield('a'), 'Description should show OPAC', 'Original record now contains AV OPAC description (interface defaults to opac)' );
is( $record->field('942')->subfield('n'), 1, 'Record suppression is still numeric after filtering' );
# reset record for next test
$record = $biblio->metadata->record;
is( $record->field('590')->subfield('a'), 'CODE', 'Record reset contains AV Code' );
# set interface
$processor->options({ interface => 'intranet' });
$result = $processor->process( $record );
is( $record->field('590')->subfield('a'), 'Description should show', 'Original record now contains AV description (interface set to intranet)' );
is( $record->field('942')->subfield('n'), 1, 'Item suppression field remains numeric after filtering' );
$schema->storage->txn_rollback();
};