Bug 31925: Don't override 008/11 when the heading's thesaurus wasn't identified

QA (comments 23-30) flagged a regression in the previous patches: the
guard around coding a new authority's 008/11 (and 040$f) from the source
heading's thesaurus was `if ( $heading->{thesaurus} )`, but
C4::Heading::MARC21::_get_subject_thesaurus() never returns a false
value - a heading with a blank/unrecognised indicator 2 (by far the
commonest real-world case) comes back as the placeholder string
"notdefined", and indicator 2 = 4 comes back as "notspecified". Both are
truthy, so the override always fired, unconditionally coding every new
authority's 008/11 as 'z' or '|' instead of respecting the site's
MARCAuthorityControlField008 default (which defaults to 'a'/LCSH) - a
disruptive behaviour change for the majority of headings, not just the
non-LCSH ones this bug is meant to fix.

Adds Koha::Authority::$MARC21_UNDEFINED_THESAURUS_VALUES, the subset of
the existing thesaurus table's keys ('notdefined', 'notspecified') that
mean "no thesaurus could be identified" rather than a genuine one, and
uses it in LinkBibHeadingsToAuthorities()'s guard so those two values now
fall through to the site's own syspref default, unchanged, exactly as
before this bug's patches.

Test plan:
1. prove t/db_dependent/Biblio.t
   Note the two new cases in the "codes new authorities with the source
   thesaurus" subtest: a blank-indicator-2 heading now keeps 008/11 at
   the syspref default ('a') instead of being forced to 'z', and an
   indicator-2=4 heading respects a customised syspref default instead
   of being forced to '|'.
2. Librarian-facing regression check: with AutoLinkBiblios and
   AutoCreateAuthorities on, catalogue a 650 with a blank/space
   indicator 2 (e.g. `650 __ $a Some topic`, no $2) and save. The new
   authority's 008 position 11 should read whatever
   MARCAuthorityControlField008 says (LCSH 'a' by default), not 'z'.
3. Confirm the non-LCSH cases from the earlier patches are unaffected:
   a FAST heading (ind2=7, $2=fast) still codes 008/11='z' with
   040$f=fast, and a MeSH heading (ind2=2) still codes 008/11='c'.

Sponsored-by: Heythrop Library <https://heythroplibrary.co.uk/>
Signed-off-by: David Cook <dcook@prosentient.com.au>
Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
This commit is contained in:
Martin Renvoize 2026-09-01 11:12:57 +01:00 committed by Pedro Amorim
parent 65dac0fb94
commit c15b42c457
No known key found for this signature in database
GPG Key ID: 06B75BA7F3894D55
3 changed files with 71 additions and 4 deletions

View File

@ -824,8 +824,11 @@ sub LinkBibHeadingsToAuthorities {
# thesaurus instead of relying on AddAuthority()'s LCSH-only default.
# AddAuthority() only defaults 008/040 when they aren't already present
# on the record, so pre-populating them here is sufficient - no change
# to AddAuthority() itself is needed.
if ( $heading->{thesaurus} ) {
# to AddAuthority() itself is needed. Skip this when the heading's
# thesaurus couldn't actually be identified (bug 31925 comment 30) - in
# that case the site's own MARCAuthorityControlField008 default should
# apply, the same as it always has, rather than being overridden.
if ( Koha::Authority->has_known_thesaurus( $heading->{thesaurus} ) ) {
my $date = POSIX::strftime( '%y%m%d', localtime );
$marcrecordauth->insert_fields_ordered(
MARC::Field->new(

View File

@ -324,6 +324,41 @@ our $MARC21_THESAURUS_TO_CONTROL_FIELD_008_11 = {
notspecified => '|',
};
# The subset of $MARC21_THESAURUS_TO_CONTROL_FIELD_008_11 keys that
# C4::Heading uses to mean "no specific thesaurus could be identified from
# the source heading's indicators" (a blank/unrecognised indicator 2, or
# indicator 2 = 4), rather than a genuine, named thesaurus. Kept private -
# callers should go through has_known_thesaurus() rather than consulting
# this directly.
my $UNDEFINED_THESAURUS_VALUES = {
notdefined => 1,
notspecified => 1,
};
=head3 has_known_thesaurus
if ( Koha::Authority->has_known_thesaurus($thesaurus) ) { ... }
Returns true if C<$thesaurus> (as derived by C4::Heading from MARC
indicator 2 / subfield $2, e.g. 'lcsh', 'mesh', or a raw $2 code such as
'fast') identifies an actual thesaurus. Returns false if C<$thesaurus> is
undefined, or is one of the placeholder values C4::Heading returns when
no thesaurus could be identified from the source heading's indicators
('notdefined', 'notspecified').
Callers that want to code a new authority's 008/11 (and 040$f) from a
heading's thesaurus should check this first, and leave the site's own
default (I<MARCAuthorityControlField008>) in place otherwise.
=cut
sub has_known_thesaurus {
my ( $class, $thesaurus ) = @_;
return 0 unless defined $thesaurus;
return $UNDEFINED_THESAURUS_VALUES->{$thesaurus} ? 0 : 1;
}
=head3 default_marc21_008
my $default_008 = Koha::Authority->default_marc21_008;

View File

@ -17,7 +17,7 @@
use Modern::Perl;
use Test::More tests => 27;
use Test::More tests => 28;
use Test::NoWarnings;
use Test::MockModule;
use Test::Warn;
@ -1115,7 +1115,7 @@ subtest "LinkBibHeadingsToAuthorities record generation tests" => sub {
};
subtest "LinkBibHeadingsToAuthorities codes new authorities with the source thesaurus (bug 31925)" => sub {
plan tests => 7;
plan tests => 11;
my $biblio_mod = Test::MockModule->new('C4::Linker::Default');
$biblio_mod->mock(
@ -1171,6 +1171,35 @@ subtest "LinkBibHeadingsToAuthorities codes new authorities with the source thes
substr( $authority->field('008')->data(), 11, 1 ), 'a',
'Non-subject heading (700) keeps the default LCSH 008/11=a coding, unaffected by this fix'
);
# Case 5: blank ind2 (thesaurus not identified at all) - must respect the
# MARCAuthorityControlField008 syspref default, not be forced to 'z' (bug 31925 comment 30)
$biblio = $builder->build_sample_biblio();
$record = $biblio->metadata->record;
$field = MARC::Field->new( '650', '', ' ', 'a' => 'Unidentified thesaurus' );
$record->append_fields($field);
LinkBibHeadingsToAuthorities( $linker, $record, "", undef, 650 );
$authority = GetAuthority( $record->subfield( '650', '9' ) );
is(
substr( $authority->field('008')->data(), 11, 1 ), 'a',
'Blank ind2 (no thesaurus identified) keeps the syspref default 008/11=a, not forced to z'
);
is( $authority->subfield( '040', 'f' ), undef, 'Blank ind2 (no thesaurus identified) gets no 040$f' );
# Case 6: ind2=4 (explicitly "source not specified") - must also respect a customised
# MARCAuthorityControlField008 syspref default rather than being forced to '|'
t::lib::Mocks::mock_preference( 'MARCAuthorityControlField008', '|| acn||aabn | a|a d' );
$biblio = $builder->build_sample_biblio();
$record = $biblio->metadata->record;
$field = MARC::Field->new( '650', '', '4', 'a' => 'Source not specified' );
$record->append_fields($field);
LinkBibHeadingsToAuthorities( $linker, $record, "", undef, 650 );
$authority = GetAuthority( $record->subfield( '650', '9' ) );
is(
substr( $authority->field('008')->data(), 11, 1 ), 'n',
'ind2=4 (source not specified) respects a customised syspref default 008/11=n, not forced to |'
);
is( $authority->subfield( '040', 'f' ), undef, 'ind2=4 (source not specified) gets no 040$f' );
};
subtest 'autoControlNumber tests' => sub {