From c9bcc4130f480735e701836ec0a71b0df49c2d9f Mon Sep 17 00:00:00 2001 From: Eric Garcia Date: Wed, 9 Jul 2025 14:50:32 +0000 Subject: [PATCH] Bug 35211: Separate group holdings into individual tabs Added SeparateHoldingsByGroup system preference Adds new tabs to Holdings table if preference is enabled Separates by library groups Test Plan: 1. Apply patch, restart_all, updatedatabase 2. Koha Administration -> System preferences -> SeparateHoldingsByGroup 3. Change to "Separate holdings by library group in subsequent tabs..." and Save 4. Koha Administration -> Library Groups 5. Create multiple library groups and check the 'Use for staff search groups' box. 6. Add your logged in library to each group and other libraries to each group. 7. Do catalog searches where the location of the item is a library in a library group 8. Notice tabs in the Holdings table for each library group if it contains a library that has the item --- catalogue/detail.pl | 47 +++++++++++++++++++ .../bug_35211_separate_holdings_by_group.pl | 22 +++++++++ installer/data/mysql/mandatory/sysprefs.sql | 1 + .../tables/items/catalogue_detail.inc | 24 ++++++++++ .../admin/preferences/cataloguing.pref | 8 +++- .../prog/en/modules/catalogue/detail.tt | 30 +++++++++++- 6 files changed, 130 insertions(+), 2 deletions(-) create mode 100755 installer/data/mysql/atomicupdate/bug_35211_separate_holdings_by_group.pl diff --git a/catalogue/detail.pl b/catalogue/detail.pl index c6445d4a20..42d6704199 100755 --- a/catalogue/detail.pl +++ b/catalogue/detail.pl @@ -60,6 +60,8 @@ use Koha::Reviews; use Koha::SearchEngine::Search; use Koha::SearchEngine::QueryBuilder; use Koha::Serial::Items; +use Koha::Library::Group; +use Koha::Library::Groups; my $query = CGI->new(); @@ -336,6 +338,51 @@ if ( C4::Context->preference('SeparateHoldings') ) { $items_to_display->search( { $SeparateHoldingsBranch => { '!=' => C4::Context->userenv->{branch} } } )->count; $template->param( other_holdings_count => $other_holdings_count ); } + +if ( C4::Context->preference('SeparateHoldingsByGroup') ) { + my $branchcode = C4::Context->userenv->{branch}; + my @all_search_groups = Koha::Library::Groups->get_search_groups( { interface => 'staff' } ); + my @lib_groups; + my %branchcode_hash; + my %holdings_count; + + foreach my $search_group (@all_search_groups) { + while ( my $group = $search_group->next ) { + my @all_libs = $group->all_libraries; + + # Check if library is in group + if ( grep { $_->branchcode eq $branchcode } @all_libs ) { + + # Get other libraries in group + my @other_libs = grep { $_->branchcode ne $branchcode } @all_libs; + my @libs_branchcodes; + + foreach my $lib (@other_libs) { + push @libs_branchcodes, $lib->branchcode; + } + + # Push logged in branchcode + push @libs_branchcodes, $branchcode; + + # Build group branchcode hash + $branchcode_hash{ $group->id } = \@libs_branchcodes; + + my $group_holdings_count = + $items_to_display->search( { homebranch => { '-in' => \@libs_branchcodes } } )->count; + $holdings_count{ $group->id } = $group_holdings_count; + + push @lib_groups, $group; + } + } + } + + $template->param( + lib_groups => \@lib_groups, + branchcodes => \%branchcode_hash, + holdings_count => \%holdings_count, + ); +} + $template->param( count => $all_items->count, # FIXME 'count' is used in catalog-strings.inc # But it's not a meaningful variable, we should rename it there diff --git a/installer/data/mysql/atomicupdate/bug_35211_separate_holdings_by_group.pl b/installer/data/mysql/atomicupdate/bug_35211_separate_holdings_by_group.pl new file mode 100755 index 0000000000..bc41cec5c1 --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_35211_separate_holdings_by_group.pl @@ -0,0 +1,22 @@ +use Modern::Perl; +use Koha::Installer::Output qw(say_warning say_success say_info); + +return { + bug_number => "35211", + description => "", + 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 ('SeparateHoldingsByGroup',NULL,'','Separate current branch holdings and holdings from libraries in the same group','YesNo') + } + ); + + # Other information + say_success( $out, "Added new system preference 'SeparateHoldingsByGroup'" ); + }, +}; diff --git a/installer/data/mysql/mandatory/sysprefs.sql b/installer/data/mysql/mandatory/sysprefs.sql index f9f419c39d..b3d0ae4ea1 100644 --- a/installer/data/mysql/mandatory/sysprefs.sql +++ b/installer/data/mysql/mandatory/sysprefs.sql @@ -733,6 +733,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('SendAllEmailsTo','',NULL,'All emails will be redirected to this email if it is not empty','free'), ('SeparateHoldings','0',NULL,'Separate current branch holdings from other holdings','YesNo'), ('SeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings','Choice'), +('SeparateHoldingsByGroup','0',NULL,'Separate current branch holdings and holdings from libraries in the same library groups','YesNo'), ('SerialsDefaultEmailAddress', '', NULL, 'Default email address used as reply-to for notices sent by the serials module.', 'Free'), ('SerialsDefaultReplyTo', '', NULL, 'Default email address that serials notices are sent from.', 'Free'), ('SerialsSearchResultsLimit', NULL, NULL, 'Serials search results limit', 'integer'), diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc index 67440510e6..6e1cc46bbf 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers/tables/items/catalogue_detail.inc @@ -290,6 +290,17 @@ holdings: "[% PROCESS 'build_table' tab="holdings" | collapse | $tojson %]", otherholdings: "[% PROCESS 'build_table' tab="otherholdings" | collapse | $tojson %]", }; + + const branchcodes = { + [% FOREACH key IN branchcodes.keys %] + "[% key | html %]": [ + [% FOREACH code IN branchcodes.$key %] + "[% code | html %]"[% UNLESS loop.last %], [% END %] + [% END %] + ][% UNLESS loop.last %], [% END %] + [% END %] + }; + function build_items_table (tab_id, add_filters, dt_options, drawcallback) { let table_dt; @@ -315,6 +326,19 @@ } [% END %] + [% IF Koha.Preference('SeparateHoldingsByGroup') %] + if ( tab_id.includes('group_holdings') ) { + user_colvis[tab_id] = {}; + items_table_settings[tab_id] = [% TablesSettings.GetTableSettings('catalogue', 'detail','otherholdings_table','json') | $raw %]; + + const id = tab_id.replace("group_holdings_", ""); + + let branch = '[% IF SeparateHoldingsBranch == 'homebranch' %]me.home_library_id[% ELSE %]me.holding_library_id[% END %]'; + default_filters[branch] = branchcodes[id]; + + } + [% END %] + [% IF hidden_count %] default_filters.lost_status = "0"; [% END %] 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 9c62cae068..e1fae70811 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 @@ -301,6 +301,12 @@ Cataloging: homebranch: 'home library' holdingbranch: 'holding library' - "is the logged in user's library. The second tab will contain all other items." + - + - pref: SeparateHoldingsByGroup + choices: + 1: Separate + 0: "Don't separate" + - "holdings by library group in subsequent tabs that contain items whose home library is the logged in library branch." - - pref: AlwaysShowHoldingsTableFilters choices: @@ -408,4 +414,4 @@ Cataloging: - "
" - "All values of repeating tags and subfields will be printed with the given RIS tag." - "
" - - "Use of TY ( record type ) as a key will replace the default TY with the field value of your choosing." \ No newline at end of file + - "Use of TY ( record type ) as a key will replace the default TY with the field value of your choosing." diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt index 0fc818512a..3e2c3309d4 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt @@ -337,6 +337,16 @@ Holdings ([% items_to_display_count || 0 | html %]) [% END %] [% END %] + [% IF Koha.Preference('SeparateHoldingsByGroup') && lib_groups %] + [% FOREACH group IN lib_groups %] + [% IF ( holdings_count.${group.id} > 0 ) %] + [% WRAPPER tab_item tabname="group_holdings_" _ group.id %] + [% group.title | html %] - Group ([% holdings_count.${group.id} | html %]) + [% END %] + [% END %] + [% END %] + [% END %] + [% IF Koha.Preference('EnableItemGroups') %] [% WRAPPER tab_item tabname= "item_groups" %] Item groups @@ -476,6 +486,16 @@ [% PROCESS items_table tab="otherholdings" %] [% END # /tab_panel %] [% END %] + [% IF Koha.Preference('SeparateHoldingsByGroup') && lib_groups %] + [% FOREACH group IN lib_groups %] + [% IF ( holdings_count.${group.id} > 0 ) %] + [% SET group_tab = "group_holdings_" _ group.id %] + [% WRAPPER tab_panel tabname=group_tab %] + [% PROCESS items_table tab=group_tab %] + [% END # /tab_panel %] + [% END %] + [% END %] + [% END %] [% IF ( MARCNOTES ) %] [% WRAPPER tab_panel tabname="description" %] @@ -1730,7 +1750,15 @@ var bundle_lost_value = [% Koha.Preference('BundleLostValue') | html %]; [% END %] - let items_tab_ids = [ 'holdings', 'otherholdings' ]; + let items_tab_ids = [ + 'holdings', + 'otherholdings' + [% IF Koha.Preference('SeparateHoldingsByGroup') && lib_groups %] + [% FOREACH group IN lib_groups %] + , 'group_holdings_[% group.id | html %]' + [% END %] + [% END %] + ]; items_tab_ids.forEach( function( tab_id, index ) { // Early return if the tab is not shown (ie. no table) -- 2.39.5