From d85ed87b63469523b63f9f4c9cf5961b90b247fc Mon Sep 17 00:00:00 2001 From: Ayoub Glizi-Vicioso Date: Thu, 12 Mar 2026 17:02:29 -0400 Subject: [PATCH] Bug 38122: Improve items sorting logic in bibliographic details --- Koha/REST/V1/Biblios.pm | 100 ++++++++++++++---- .../tables/items/catalogue_detail.inc | 61 ++++++----- 2 files changed, 116 insertions(+), 45 deletions(-) diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm index 4ffca7dbfb..eee08055ba 100644 --- a/Koha/REST/V1/Biblios.pm +++ b/Koha/REST/V1/Biblios.pm @@ -271,27 +271,87 @@ sub get_items { if ($group_by_status) { $c->req->params->remove('_order_by'); - $items_rs = $items_rs->search( - {}, - { - order_by => [ - \[ "CASE - WHEN (withdrawn != 0) THEN '10_Withdrawn' - WHEN (itemlost != 0) THEN '09_Lost' - WHEN (damaged != 0) THEN '08_Damaged' - WHEN (notforloan = 3) THEN '07_In bundle' - WHEN (notforloan != 0) THEN '06_Not for loan' - WHEN EXISTS (SELECT 1 FROM issues WHERE itemnumber = me.itemnumber AND onsite_checkout = 1) THEN '05_Local use' - WHEN (onloan IS NOT NULL) THEN '04_Checked out' - WHEN (SELECT COUNT(*) FROM branchtransfers WHERE itemnumber = me.itemnumber AND datearrived IS NULL) > 0 THEN '03_In transit' - WHEN (SELECT COUNT(*) FROM reserves WHERE itemnumber = me.itemnumber AND (found IS NULL OR found = 'W')) > 0 THEN '02_On hold' - ELSE '01_Available' - END ASC" ], - { -asc => 'me.itemlost' }, - { -asc => 'me.notforloan' }, - ] + + my $q_param = $c->param('q'); + if ($q_param) { + if ( $q_param =~ /"_status"\s*:\s*"(\w+)"/ ) { + my $requested_status = $1; + + if ( $requested_status eq 'recalled' ) { + $items_rs = $items_rs->search( + \[ + "EXISTS (SELECT 1 FROM recalls WHERE item_id = me.itemnumber AND status IN ('requested','overdue','waiting','in_transit'))" + ] + ); + $c->req->params->remove('q'); + } elsif ( $requested_status eq 'available' ) { + $items_rs = $items_rs->search( + { + 'me.itemlost' => 0, + 'me.withdrawn' => 0, + 'me.onloan' => undef, + 'me.notforloan' => 0, + 'me.damaged' => 0, + 'me.restricted' => [ undef, 0 ], + } + ); + $items_rs = $items_rs->search( + \[ + "NOT EXISTS (SELECT 1 FROM branchtransfers WHERE itemnumber = me.itemnumber AND datearrived IS NULL)" + ] + ); + $items_rs = $items_rs->search( + \[ + "NOT EXISTS (SELECT 1 FROM reserves WHERE itemnumber = me.itemnumber AND (found IS NULL OR found = 'W'))" + ] + ); + $c->req->params->remove('q'); + } else { + $items_rs = $items_rs->search( + {}, + { + order_by => [ + { -asc => 'me.onloan' }, + { -asc => 'me.itemlost' }, + { -asc => 'me.withdrawn' }, + { -asc => 'me.notforloan' }, + { -asc => 'me.restricted' }, + ] + } + ); + } } - ); + } else { + + $items_rs = $items_rs->search( + {}, + { + order_by => [ + \[ + "CASE + WHEN (withdrawn != 0) THEN '11_Withdrawn' + WHEN (itemlost != 0) THEN '10_Lost' + WHEN (restricted IS NOT NULL AND restricted != 0) THEN '09_Restricted' + WHEN (damaged != 0) THEN '08_Damaged' + WHEN (notforloan = 3) THEN '07_In bundle' + WHEN (notforloan != 0) THEN '06_Not for loan' + WHEN EXISTS (SELECT 1 FROM issues WHERE itemnumber = me.itemnumber AND onsite_checkout = 1) THEN '05_Local use' + WHEN EXISTS (SELECT 1 FROM recalls WHERE item_id = me.itemnumber AND status IN ('requested','overdue','waiting','in_transit','cancelled','expired','fulfilled')) THEN '04_Recalled' + WHEN (onloan IS NOT NULL) THEN '03_Checked out' + WHEN (SELECT COUNT(*) FROM branchtransfers WHERE itemnumber = me.itemnumber AND datearrived IS NULL) > 0 THEN '02_In transit' + WHEN (SELECT COUNT(*) FROM reserves WHERE itemnumber = me.itemnumber AND (found IS NULL OR found = 'W')) > 0 THEN '01_On hold' + ELSE '00_Available' + END ASC" + ], + { -asc => 'me.onloan' }, + { -asc => 'me.itemlost' }, + { -asc => 'me.withdrawn' }, + { -asc => 'me.notforloan' }, + { -asc => 'me.restricted' }, + ] + } + ); + } } # FIXME We need to order_by serial.publisheddate if we have _order_by=+me.serial_issue_number 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 5d798eccb3..b6d4ae11e3 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 @@ -306,52 +306,64 @@ let status = ""; let priority = ""; - if (!row._status) row._status = []; + if (!row._status) return; if (row.withdrawn != 0) { - status = _("Withdrawn"); - priority = "10"; - } else if (row.lost_status != 0) { + status = av_withdrawn.get(row.withdrawn.toString()) || _("Withdrawn"); + priority = "11"; + } + else if (row.lost_status != 0) { let lost_text = av_lost.get(row.lost_status.toString()) || _("Lost"); status = lost_text; if (forSort) { - if (lost_text.toLowerCase().includes("paid")) priority = "09c"; - else if (lost_text.toLowerCase().includes("overdue")) priority = "09b"; - else priority = "09a"; + if (lost_text.toLowerCase().includes("paid")) priority = "10c"; + else if (lost_text.toLowerCase().includes("overdue")) priority = "10b"; + else priority = "10a"; } else { - priority = "09"; + priority = "10"; } } - else if (row.damaged_status != 0) { - status = _("Damaged"); + else if (row.restricted_status != null && row.restricted_status != 0) { + status = av_restricted.get(row.restricted_status.toString()) || _("Restricted access"); + priority = "09"; + } + else if (row.damaged_status != 0) { + status = av_damaged.get(row.damaged_status.toString()) || _("Damaged"); priority = "08"; } else if (row.not_for_loan_status == 3) { status = _("In bundle"); priority = "07"; - } else if (row.not_for_loan_status != 0) { - status = _("Not for loan"); + } + else if (row.not_for_loan_status != 0) { + status = av_not_for_loan.get(row.not_for_loan_status.toString()) || _("Not for loan"); priority = "06"; } else if (row._status.includes('local_use')) { status = _("Local use"); priority = "05"; } + else if (row._status.includes('recalled')) { + status = _("Recalled"); + priority = "04"; + } else if (row._status.includes('checked_out')) { status = _("Checked out"); - priority = "04"; + priority = "03"; } else if (row._status.includes('in_transit')) { status = _("In transit"); - priority = "03"; + priority = "02"; } - else if (row._status.includes('on_hold') || row._status.includes('waiting')) { + else if (row._status.includes('on_hold') || row._status.includes('waiting')) { status = _("On hold"); - priority = "02"; + priority = "01"; } - else if (row._status.includes('available') || (row.lost_status == 0 && row.withdrawn == 0)) { + else if (row._status.includes('available') + || (row.lost_status == 0 && row.withdrawn == 0) + && (row.restricted_status == null || row.restricted_status == 0)) { status = _("Available"); - priority = "01"; + priority = "00"; } else { status = _("Undefined"); @@ -361,8 +373,8 @@ status = status.trim(); if (forSort) { - if (priority.startsWith("09")) { - return "09_" + _("Lost"); + if (priority.startsWith("10")) { + return "10_" + _("Lost"); } return priority + "_" + status; } @@ -391,9 +403,11 @@ let groupColor = "#007bff"; - if (group.startsWith("01")) { + if (group.startsWith("00")) { groupColor = "#28a745"; - } else if (group.startsWith("08") || group.startsWith("09") || group.startsWith("10")) { + }else if (group.startsWith("08") || group.startsWith("09")){ + groupColor = "#FFEB3B"; + }else if (group.startsWith("10") || group.startsWith("11")) { groupColor = "#dc3545"; } @@ -634,9 +648,6 @@ searchable: false, orderable: false, render: function (data, type, row, meta) { - if (type === 'sort' || type === 'filter' || type === 'type') { - return get_display_status(row, true); - } let nodes = ""; row._status.forEach( status => { if ( status == 'checked_out' || status == 'local_use') { -- 2.53.0