From 8efb5d18528b7c316a9a39e9cf9c005da36beffb Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Thu, 23 Sep 2021 15:08:55 +0100 Subject: [PATCH] Bug 28854: Add bundle content display to OPAC TODO: Move expand button to right like staff client --- Koha/Biblio.pm | 13 +++ api/v1/swagger/paths.json | 3 + api/v1/swagger/paths/items.json | 88 ++++++++++++++++++ .../bootstrap/en/modules/opac-detail.tt | 91 ++++++++++++++++++- opac/opac-detail.pl | 10 ++ 5 files changed, 203 insertions(+), 2 deletions(-) diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index e3618dc80f..b5dd264666 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -842,6 +842,19 @@ sub get_marc_notes { return \@marcnotes; } +=head3 public_read_list + +This method returns the list of publicly readable database fields for both API and UI output purposes + +=cut + +sub public_read_list { + return [ + 'biblionumber', 'frameworkcode', 'title', 'unititle', + 'seriestitle', 'copyrightdate', 'datecreated' + ]; +} + =head3 to_api my $json = $biblio->to_api; diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json index 0c2c287d18..67f8ef10bc 100644 --- a/api/v1/swagger/paths.json +++ b/api/v1/swagger/paths.json @@ -176,6 +176,9 @@ "/public/biblios/{biblio_id}/items": { "$ref": "paths/biblios.json#/~1public~1biblios~1{biblio_id}~1items" }, + "/public/items/{item_id}/bundled_items": { + "$ref": "paths/items.json#/~1public~1items~1{item_id}~1bundled_items" + }, "/public/libraries": { "$ref": "paths/libraries.json#/~1public~1libraries" }, diff --git a/api/v1/swagger/paths/items.json b/api/v1/swagger/paths/items.json index a0a2caf9d7..d0e23ef979 100644 --- a/api/v1/swagger/paths/items.json +++ b/api/v1/swagger/paths/items.json @@ -465,5 +465,93 @@ } } } + }, + "/public/items/{item_id}/bundled_items": { + "get": { + "x-mojo-to": "Items#bundled_items", + "operationId": "bundledItemsPublic", + "tags": [ + "items" + ], + "summary": "List bundled items", + "parameters": [ + { + "$ref": "../parameters.json#/item_id_pp" + }, + { + "name": "external_id", + "in": "query", + "description": "Search on the item's barcode", + "required": false, + "type": "string" + }, + { + "$ref": "../parameters.json#/match" + }, + { + "$ref": "../parameters.json#/order_by" + }, + { + "$ref": "../parameters.json#/page" + }, + { + "$ref": "../parameters.json#/per_page" + }, + { + "$ref": "../parameters.json#/q_param" + }, + { + "$ref": "../parameters.json#/q_body" + }, + { + "$ref": "../parameters.json#/q_header" + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A list of item", + "schema": { + "type": "array", + "items": { + "$ref": "../definitions.json#/item" + } + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "503": { + "description": "Under maintenance", + "schema": { + "$ref": "../definitions.json#/error" + } + } + }, + "x-koha-embed": [ + "biblio", + "checkout" + ] + } } } diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt index 0d417a7771..bacb79387b 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt @@ -1068,7 +1068,9 @@ Holdings - + [% IF ( itemdata_bundles ) %] + + [% END %] [% IF Koha.Preference('OPACLocalCoverImages') && ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %] Cover image [% END %] @@ -1118,7 +1120,17 @@ [% FOREACH ITEM_RESULT IN items %] - + + + [% IF ( itemdata_bundles ) %] + [% IF ITEM_RESULT.is_bundle %] + + + + [% ELSE %] + + [% END %] + [% END %] [% IF Koha.Preference('OPACLocalCoverImages') && ( tab == 'holdings' && itemloop_has_images || tab == 'otherholdings' && otheritemloop_has_images ) %] @@ -1421,6 +1433,81 @@ "autoWidth": false }, columns_settings); + function createChild ( row, itemnumber ) { + // This is the table we'll convert into a DataTable + var bundles_table = $(''); + + // Display it the child row + row.child( bundles_table ).show(); + + // Initialise as a DataTable + var bundle_table_url = "/api/v1/public/items/" + itemnumber + "/bundled_items?"; + var bundle_table = bundles_table.api({ + "ajax": { + "url": bundle_table_url + }, + "header_filter": false, + "embed": [ + "biblio" + ], + "order": [[ 0, "asc" ]], + "columns": [ + { + "data": "item_type", + "title": "Item Type", + "searchable": false, + "orderable": true, + }, + { + "data": "biblio.title", + "title": "Title", + "searchable": true, + "orderable": true, + }, + { + "data": "damaged_status", + "title": "Status", + "searchable": false, + "orderable": true, + }, + { + "data": "external_id", + "title": "Barcode", + "searchable": true, + "orderable": true, + }, + { + "data": "callnumber", + "title": "Callnumber", + "searchable": true, + "orderable": true, + }, + ] + }, [], 1); + + return; + } + + // Add event listener for opening and closing details + $('#holdingst tbody').on('click', 'td.details-control', function () { + var tr = $(this).closest('tr'); + var dTable = $(this).closest('table').DataTable({ 'retrieve': true }); + + var itemnumber = tr.data('itemnumber'); + var row = dTable.row( tr ); + + if ( row.child.isShown() ) { + // This row is already open - close it + row.child.hide(); + tr.removeClass('shown'); + } + else { + // Open this row + createChild(row, itemnumber); + tr.addClass('shown'); + } + } ); + var serial_column_settings = [% TablesSettings.GetColumns( 'opac', 'biblio-detail', 'subscriptionst', 'json' ) | $raw %]; KohaTable("#subscriptionst", { diff --git a/opac/opac-detail.pl b/opac/opac-detail.pl index eb9a6866b1..7e6ce44a8e 100755 --- a/opac/opac-detail.pl +++ b/opac/opac-detail.pl @@ -751,6 +751,15 @@ if ( not $viewallitems and @items > $max_items_to_display ) { $itm->{cover_images} = $item->cover_images; } + if ($item->is_bundle) { + $itemfields{bundles} = 1; + $itm->{is_bundle} = 1; + } + + if ($item->in_bundle) { + $itm->{bundle_host} = $item->bundle_host; + } + my $itembranch = $itm->{$separatebranch}; if ($currentbranch and C4::Context->preference('OpacSeparateHoldings')) { if ($itembranch and $itembranch eq $currentbranch) { @@ -802,6 +811,7 @@ my $norequests = ! $biblio->items->filter_by_for_hold->count; MARCNOTES => $marcnotesarray, norequests => $norequests, RequestOnOpac => C4::Context->preference("RequestOnOpac"), + itemdata_bundles => $itemfields{bundles}, itemdata_ccode => $itemfields{ccode}, itemdata_materials => $itemfields{materials}, itemdata_enumchron => $itemfields{enumchron}, -- 2.20.1