From 2531331106798ad62e9262a35e953f3f2105a2e9 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Fri, 4 Jul 2025 12:07:35 +0200 Subject: [PATCH] Bug 38122: Add the ability to group holdings by status This is a quite ugly solution, but that may answer end-user needs. It add the option the group items by status on the bibliographic record detail page. However it will have VERY bad impact on performances for record with a lot of items, as we are going to determine the status of each items of the record. --- Koha/REST/V1/Biblios.pm | 19 ++++++++++++ api/v1/swagger/paths/biblios.yaml | 7 ++++- .../tables/items/catalogue_detail.inc | 31 +++++++++++++++++-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm index 0c6f950585f..f99b61af223 100644 --- a/Koha/REST/V1/Biblios.pm +++ b/Koha/REST/V1/Biblios.pm @@ -250,6 +250,9 @@ sub get_items { # Deletion of parameter to avoid filtering on the items table in the case of bookings on 'itemtype' $c->req->params->remove('bookable'); + my $group_by_status = $c->param('group_by_status'); + $c->req->params->remove('group_by_status'); + return $c->render_resource_not_found("Bibliographic record") unless $biblio; @@ -261,6 +264,22 @@ sub get_items { my $items_rs = $biblio->items( { host_items => 1 } )->search_ordered( {}, { join => 'biblioitem' } ); $items_rs = $items_rs->filter_by_bookable if $bookable_only; + if ($group_by_status) { + my @item_ids; + for my $status ( + qw( available checked_out local_use in_transit lost withdrawn damaged not_for_loan on_hold recalled in_bundle restricted ) + ) + { + push @item_ids, $items_rs->search( { _status => $status } )->get_column('itemnumber'); + } + $items_rs = $items_rs->search( + {}, + { + order_by => [ \[ sprintf( "field(me.itemnumber, %s)", join( ', ', map { qq{'$_'} } @item_ids ) ) ] ] + } + ); + } + # FIXME We need to order_by serial.publisheddate if we have _order_by=+me.serial_issue_number my $items = $c->objects->search($items_rs); diff --git a/api/v1/swagger/paths/biblios.yaml b/api/v1/swagger/paths/biblios.yaml index ab9f8ebd454..74e79fac647 100644 --- a/api/v1/swagger/paths/biblios.yaml +++ b/api/v1/swagger/paths/biblios.yaml @@ -499,6 +499,11 @@ description: Limit to items that are bookable required: false type: boolean + - name: group_by_status + in: query + description: Return the items grouped by status + required: false + type: boolean consumes: - application/json produces: @@ -919,4 +924,4 @@ "503": description: Under maintenance schema: - $ref: "../swagger.yaml#/definitions/error" \ No newline at end of file + $ref: "../swagger.yaml#/definitions/error" 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 67440510e69..50e9b4a9df0 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 @@ -61,6 +61,7 @@ + | Actions: [% IF CAN_user_tools_items_batchdel %] @@ -249,7 +250,6 @@ [%# FIXME The X-Base-Total-Count will be the number of items of the biblios %] [%# In case or SeparateHoldings we may need to display the number of biblios in each tab %] [%# Do we need separate/new endpoints or do we hack the somewhere client-side? %] - let item_table_url = "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?"; let embed = ["+strings,_status,home_library,holding_library,checkout,checkout.patron,transfer,transfer+strings,first_hold,first_hold+strings,first_hold.patron,first_hold.desk"]; [% IF Koha.Preference('LocalCoverImages') %] embed.push('cover_image_ids'); @@ -290,6 +290,26 @@ holdings: "[% PROCESS 'build_table' tab="holdings" | collapse | $tojson %]", otherholdings: "[% PROCESS 'build_table' tab="otherholdings" | collapse | $tojson %]", }; + + let group_by_status_values = { + holdings: false, + otherholdings: false, + }; + $(".GroupByStatus").on("click",function(e){ + e.preventDefault(); + let tab_id = $(this).data("tab"); + let was_grouped = group_by_status_values[tab_id]; + group_by_status_values[tab_id] = !was_grouped; + + build_items_table(tab_id, true, { destroy: true }, build_items_table_drawncallback ); + + if ( was_grouped ) { + $(this).html(' Group by status'); + } else { + $(this).html(' Ungroup by status'); + } + }); + function build_items_table (tab_id, add_filters, dt_options, drawcallback) { let table_dt; @@ -335,8 +355,15 @@ [offset+7] : () => all_statuses, }; + let group_by_status = function(){ + if ( group_by_status_values[tab_id] ) { + return 'group_by_status=1'; + } + return ''; + } + var items_table = $("#" + tab_id + '_table').kohaTable({ - ajax: { url: item_table_url }, + ajax: { url: "/api/v1/biblios/[% biblio.biblionumber | uri %]/items?" + group_by_status() }, order: [], embed, autoWidth: false, -- 2.34.1