From 7416eb409fdfbeb37d89747bbd47866ce49fbe69 Mon Sep 17 00:00:00 2001 From: Paul Derscheid Date: Tue, 24 Feb 2026 15:07:37 +0100 Subject: [PATCH] Bug 41917: Add parent itemtype fallback to Items::filter_by_bookable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Include children of bookable parent itemtypes in the bookable filter - Add explicit Koha::ItemTypes import To test: - Run t/db_dependent/Koha/Items.t - Verify filter_by_bookable includes items whose child itemtype has a bookable parent (both itype modes) - Verify items with explicit bookable=0 are excluded even when parent is bookable Sponsored-by: Büchereizentrale Schleswig-Holstein Signed-off-by: Martin Renvoize --- Koha/Items.pm | 17 ++++++++++++++--- t/db_dependent/Koha/Items.t | 32 +++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Koha/Items.pm b/Koha/Items.pm index 862631fbfb3..8ac159c696c 100644 --- a/Koha/Items.pm +++ b/Koha/Items.pm @@ -32,6 +32,7 @@ use Koha::SearchEngine::Indexer; use Koha::Item::Attributes; use Koha::Item; use Koha::CirculationRules; +use Koha::ItemTypes; use base qw(Koha::Objects); @@ -200,14 +201,24 @@ Returns a new resultset, containing only those items that are allowed to be book sub filter_by_bookable { my ($self) = @_; + my $bookable_itypes = [ Koha::ItemTypes->search( { bookable => 1 } )->get_column('itemtype') ]; + my $child_itypes = [ + Koha::ItemTypes->search( + { + bookable => 0, + parent_type => { -in => $bookable_itypes }, + } + )->get_column('itemtype') + ]; + my $all_bookable_itypes = [ @$bookable_itypes, @$child_itypes ]; + if ( !C4::Context->preference('item-level_itypes') ) { return $self->search( [ { bookable => 1 }, { bookable => undef, - 'biblioitem.itemtype' => - { -in => [ Koha::ItemTypes->search( { bookable => 1 } )->get_column('itemtype') ] } + 'biblioitem.itemtype' => { -in => $all_bookable_itypes } }, ], { join => 'biblioitem' } @@ -219,7 +230,7 @@ sub filter_by_bookable { { bookable => 1 }, { bookable => undef, - itype => { -in => [ Koha::ItemTypes->search( { bookable => 1 } )->get_column('itemtype') ] } + itype => { -in => $all_bookable_itypes } }, ] ); diff --git a/t/db_dependent/Koha/Items.t b/t/db_dependent/Koha/Items.t index 3e74ac1fb6c..68800215827 100755 --- a/t/db_dependent/Koha/Items.t +++ b/t/db_dependent/Koha/Items.t @@ -2540,7 +2540,7 @@ subtest 'filter_by_for_hold' => sub { }; subtest 'filter_by_bookable' => sub { - plan tests => 4; + plan tests => 7; $schema->storage->txn_begin; @@ -2584,6 +2584,36 @@ subtest 'filter_by_bookable' => sub { "filter_by_bookable returns the correct number of items when not set at item level and using item level itemtypes" ); + note("Parent itemtype fallback tests for filter_by_bookable"); + + my $parent_itype = + $builder->build_object( { class => 'Koha::ItemTypes', value => { bookable => 1, parent_type => undef } } ); + my $child_itype = $builder->build_object( + { class => 'Koha::ItemTypes', value => { bookable => 0, parent_type => $parent_itype->itemtype } } ); + + my $biblio2 = $builder->build_sample_biblio( { itemtype => $child_itype->itemtype } ); + my $child_item = $builder->build_sample_item( + { biblionumber => $biblio2->biblionumber, itype => $child_itype->itemtype, bookable => undef } ); + + t::lib::Mocks::mock_preference( 'item-level_itypes', 1 ); + is( + $biblio2->items->filter_by_bookable->count, 1, + "filter_by_bookable includes child of bookable parent (item-level_itypes=1)" + ); + + t::lib::Mocks::mock_preference( 'item-level_itypes', 0 ); + is( + $biblio2->items->filter_by_bookable->count, 1, + "filter_by_bookable includes child of bookable parent (item-level_itypes=0)" + ); + + $child_item->bookable(0)->store(); + $child_item->discard_changes; + is( + $biblio2->items->filter_by_bookable->count, 0, + "filter_by_bookable excludes item with explicit bookable=0 even if parent is bookable" + ); + $schema->storage->txn_rollback; }; -- 2.53.0