From 7050b9963048ce6908d790ee5e99b73465c42fd5 Mon Sep 17 00:00:00 2001 From: Hammat Wele Date: Thu, 21 Aug 2025 20:47:36 +0000 Subject: [PATCH] Bug 37680: inconsistencies with the search results when selecting the "Limit to records with available items" option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were inconsistencies in search results when selecting "Limit to records with available items". Records with items marked as «notforloan» or «withdrawn» were still being shown as available. This patch add two systems preferences UnavailableNotForLoan and UnavailableWithDrawn, these allow users to choose which notforloan or withdrawn values should be considered as unavailable items. Case : 1- Record with first item as «notforloan» (Ordered) - The second is «notforloan» (Ordered) 2- Record with first item as «notforloan» (Ordered) - The second is «withdrawn» 3- Record with first item as «itemlost» - The second is «notforloan» (Not for loan) 4- Record with first item as «itemlost» - The second is «withdrawn» 5- Record with first item «onloan» - The second is «notforloan» 6- Record with first item «onloan» - The second is «withdrawn» To reproduce: 1. Import "Test records for the cases described" records 2. Checkout the first item of «Bug 37680 Case 5 » and «Bug 37680 Case 6» 3. Make sure OpacHiddenItems is empty 4. In the OPAC, search for «Bug 37680» 5. Click on «Limit to records with available items» ----> Records for Case 2, 3 ,4, 5, 6 is still showing 6. Apply the patch 7. Run ./installer/data/mysql/updatedatabase.pl 8. Go to Administration -> search for UnavailableNotForLoan then select Not for loan that should be consider as not available (e.g. «Ordered» and «Not For Loan») 9. Go to Administration -> search for UnavailableWithDrawn then select Withdrawn that should be consider as not available (e.g. «Withdrawn») 10. Rebuild bibliographic index ./misc/search_tools/rebuild_elasticsearch.pl -d -v -r -b 11. Repeat step 4 and 5 ----> Records for Case 2, 3, 4, 5, and 6 no longer appear. --- Koha/SearchEngine/Elasticsearch.pm | 8 ++- .../data/mysql/atomicupdate/bug_37680.pl | 31 +++++++++ installer/data/mysql/mandatory/sysprefs.sql | 2 + .../admin/preferences/cataloguing.pref | 15 +++++ .../Koha/SearchEngine/Elasticsearch.t | 67 ++++++++++++++++++- 5 files changed, 119 insertions(+), 4 deletions(-) create mode 100755 installer/data/mysql/atomicupdate/bug_37680.pl diff --git a/Koha/SearchEngine/Elasticsearch.pm b/Koha/SearchEngine/Elasticsearch.pm index 3111ea306a6..b693b588314 100644 --- a/Koha/SearchEngine/Elasticsearch.pm +++ b/Koha/SearchEngine/Elasticsearch.pm @@ -952,11 +952,15 @@ sub marc_records_to_documents { my ( $tag, $code ) = C4::Biblio::GetMarcFromKohaField('biblio.biblionumber'); my $field = $record->field($tag); if ($field) { - my $biblionumber = $field->is_control_field ? $field->data : $field->subfield($code); - my $avail_items = Koha::Items->search( + my $biblionumber = $field->is_control_field ? $field->data : $field->subfield($code); + my $unavailable_notforloan = [ split ',', C4::Context->preference('UnavailableNotForLoan') ]; + my $unavailable_withdrawn = [ split ',', C4::Context->preference('UnavailableWithDrawn') ]; + my $avail_items = Koha::Items->search( { biblionumber => $biblionumber, onloan => undef, + notforloan => { 'not in' => $unavailable_notforloan }, + withdrawn => { 'not in' => $unavailable_withdrawn }, itemlost => 0, } )->count; diff --git a/installer/data/mysql/atomicupdate/bug_37680.pl b/installer/data/mysql/atomicupdate/bug_37680.pl new file mode 100755 index 00000000000..b851f26c1c3 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_37680.pl @@ -0,0 +1,31 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "37680", + description => "Adds new system preferences 'UnavailableNotForLoan' and 'UnavailableWithDrawn'", + up => sub { + my ($args) = @_; + my ( $dbh, $out ) = @$args{qw(dbh out)}; + + # Do you stuffs here + $dbh->do( + q{ + INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES + ('UnavailableNotForLoan', '', NULL,'Choose which notforloan values should be considered as NOT available.', 'Choice') + } + ); + + # Do you stuffs here + $dbh->do( + q{ + INSERT IGNORE INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES + ('UnavailableWithDrawn', '', NULL,'Choose which withdrawn values should be considered as NOT available.', 'Choice') + } + ); + + # sysprefs + say $out "Added new system preference 'UnavailableNotForLoan'"; + say $out "Added new system preference 'UnavailableWithDrawn'"; + }, +}; diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index 67cd533dafb..bbaab0baa0e 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -831,6 +831,8 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('TranslateNotices','0',NULL, 'Allow notices to be translated','YesNo'), ('TrapHoldsOnOrder','1',NULL,'If enabled, Koha will trap holds for on order items ( notforloan < 0 )','YesNo'), ('TwoFactorAuthentication', 'disabled', 'enforced|enabled|disabled', 'Enables two-factor authentication', 'Choice'), +('UnavailableNotForLoan', '', NULL, 'Choose which notforloan values should be considered as NOT available.','Choice'), +('UnavailableWithDrawn', '', NULL, 'Choose which withdrawn values should be considered as NOT available.','Choice'), ('UNIMARCAuthorityField100','afrey50 ba0',NULL,'Define the contents of UNIMARC authority control field 100 position 08-35','Textarea'), ('UNIMARCAuthorsFacetsSeparator',', ',NULL,'UNIMARC authors facets separator','short'), ('UNIMARCField100Language','fre',NULL,'UNIMARC field 100 default language','short'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref index 9c62cae0688..b90404193d1 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref @@ -359,6 +359,21 @@ Cataloging: dsc: descending. az: from A to Z. za: from Z to A. + - + - pref: UnavailableNotForLoan + choices: authval + source: NOT_LOAN + class: multiple + - Should be considered as not available. + - Rebuild the bibliographic index after making changes. + - + - pref: UnavailableWithDrawn + choices: authval + source: WITHDRAWN + class: multiple + - Should be considered as not available. + - Rebuild the bibliographic index after making changes. + Importing: - - When matching on ISBN with the record import tool, diff --git a/t/db_dependent/Koha/SearchEngine/Elasticsearch.t b/t/db_dependent/Koha/SearchEngine/Elasticsearch.t index 66b267fc343..35e1d559d97 100755 --- a/t/db_dependent/Koha/SearchEngine/Elasticsearch.t +++ b/t/db_dependent/Koha/SearchEngine/Elasticsearch.t @@ -1216,9 +1216,10 @@ subtest 'Koha::SearchEngine::Elasticsearch::marc_records_to_documents with Inclu }; subtest 'marc_records_to_documents should set the "available" field' => sub { - plan tests => 8; + plan tests => 14; - t::lib::Mocks::mock_preference( 'marcflavour', 'MARC21' ); + t::lib::Mocks::mock_preference( 'marcflavour', 'MARC21' ); + t::lib::Mocks::mock_preference( 'UnavailableNotForLoan', undef ); my $dbh = C4::Context->dbh; my $se = Test::MockModule->new('Koha::SearchEngine::Elasticsearch'); @@ -1276,6 +1277,68 @@ subtest 'marc_records_to_documents should set the "available" field' => sub { $docs->[0]->{available}, \1, 'a biblio with at least one item that has no particular status is available' ); + + t::lib::Mocks::mock_preference( 'UnavailableNotForLoan', join( ',', '-1', '1' ) ); + $biblio = $builder->build_sample_biblio; + $marc_record_1 = $biblio->metadata->record; + + $item = $builder->build_sample_item( + { + biblionumber => $biblio->biblionumber, + } + ); + + $item->notforloan(-1)->store(); + $docs = $see->marc_records_to_documents( [$marc_record_1] ); + is_deeply( + $docs->[0]->{available}, \0, + 'A biblio with one item whose notforloan value is selected in UnavailableNotForLoan should be considered not available' + ); + + $item->set( { notforloan => 1 } )->store(); + $docs = $see->marc_records_to_documents( [$marc_record_1] ); + is_deeply( + $docs->[0]->{available}, \0, + 'A biblio with one item whose notforloan value is selected in UnavailableNotForLoan should be considered not available' + ); + + $item->set( { notforloan => 2 } )->store(); + $docs = $see->marc_records_to_documents( [$marc_record_1] ); + is_deeply( + $docs->[0]->{available}, \1, + 'A biblio with one item whose notforloan value is not selected in UnavailableNotForLoan should be considered available' + ); + + t::lib::Mocks::mock_preference( 'UnavailableWithDrawn', join( ',', '-1', '1' ) ); + $biblio = $builder->build_sample_biblio; + $marc_record_1 = $biblio->metadata->record; + + $item = $builder->build_sample_item( + { + biblionumber => $biblio->biblionumber, + } + ); + + $item->withdrawn(-1)->store(); + $docs = $see->marc_records_to_documents( [$marc_record_1] ); + is_deeply( + $docs->[0]->{available}, \0, + 'A biblio with one item whose withdrawn value is selected in UnavailableWithDrawn should be considered not available' + ); + + $item->set( { withdrawn => 1 } )->store(); + $docs = $see->marc_records_to_documents( [$marc_record_1] ); + is_deeply( + $docs->[0]->{available}, \0, + 'A biblio with one item whose withdrawn value is selected in UnavailableWithDrawn should be considered not available' + ); + + $item->set( { withdrawn => 2 } )->store(); + $docs = $see->marc_records_to_documents( [$marc_record_1] ); + is_deeply( + $docs->[0]->{available}, \1, + 'A biblio with one item whose withdrawn value is not selected in UnavailableWithDrawn should be considered available' + ); }; $schema->storage->txn_rollback; -- 2.34.1