@@ -, +, @@ and for clearing an item group for items. --- admin/columns_settings.yml | 4 + catalogue/detail.pl | 37 ++ .../prog/en/includes/html_helpers.inc | 24 +- .../prog/en/modules/catalogue/detail.tt | 408 +++++++++++++++++- 4 files changed, 460 insertions(+), 13 deletions(-) --- a/admin/columns_settings.yml +++ a/admin/columns_settings.yml @@ -358,6 +358,8 @@ modules: columnname: holdings_homebranch - columnname: holdings_ccode + - + columnname: holdings_volume - columnname: holdings_itemcallnumber - @@ -415,6 +417,8 @@ modules: columnname: otherholdings_homebranch - columnname: otherholdings_ccode + - + columnname: otherholdings_volume - columnname: otherholdings_itemcallnumber - --- a/catalogue/detail.pl +++ a/catalogue/detail.pl @@ -47,7 +47,10 @@ use C4::HTML5Media; use C4::CourseReserves qw( GetItemCourseReservesInfo ); use Koha::AuthorisedValues; use Koha::Biblios; +use Koha::Biblio::ItemGroup::Items; +use Koha::Biblio::ItemGroups; use Koha::CoverImages; +use Koha::DateUtils; use Koha::Illrequests; use Koha::Items; use Koha::ItemTypes; @@ -99,6 +102,39 @@ if ( not defined $record ) { my $marc_record = eval { $biblio->metadata->record }; $template->param( decoding_error => $@ ); +my $op = $query->param('op') || q{}; +if ( $op eq 'set_item_group' ) { + my $item_group_id = $query->param('item_group_id'); + my @itemnumbers = $query->multi_param('itemnumber'); + + foreach my $item_id (@itemnumbers) { + my $item_group_item = Koha::Biblio::ItemGroup::Items->find( { item_id => $item_id } ); + + if ($item_group_item) { + $item_group_item->item_group_id($item_group_id); + } + else { + $item_group_item = Koha::Biblio::ItemGroup::Item->new( + { + item_id => $item_id, + item_group_id => $item_group_id, + } + ); + } + + $item_group_item->store(); + } +} +elsif ( $op eq 'unset_item_group' ) { + my $item_group_id = $query->param('item_group_id'); + my @itemnumbers = $query->multi_param('itemnumber'); + + foreach my $item_id (@itemnumbers) { + my $item_group_item = Koha::Biblio::ItemGroup::Items->find( { item_id => $item_id } ); + $item_group_item->delete() if $item_group_item; + } +} + if($query->cookie("holdfor")){ my $holdfor_patron = Koha::Patrons->find( $query->cookie("holdfor") ); if ( $holdfor_patron ) { @@ -341,6 +377,7 @@ foreach my $item (@items) { # checking for holds my $item_object = Koha::Items->find( $item->{itemnumber} ); + $item->{object} = $item_object; my $holds = $item_object->current_holds; if ( my $first_hold = $holds->next ) { $item->{first_hold} = $first_hold; --- a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers.inc +++ a/koha-tmpl/intranet-tmpl/prog/en/includes/html_helpers.inc @@ -101,12 +101,12 @@ [% SET mv = subfield.marc_value %] [% IF ( mv.type == 'hidden' ) %] - + [% ELSIF ( mv.type == 'select' ) %] [% IF ( mv.readonly || subfield.IS_RETURN_CLAIM ) %] - + [% ELSE %] - + [% END %] [% FOREACH aval IN mv.values %] @@ -123,19 +123,19 @@ [% ELSIF ( mv.type == 'text_auth' ) %] [% IF mv.readonly %] - + [% ELSE %] - + [% SET dopop = "Dopop('/cgi-bin/koha/authorities/auth_finder.pl?authtypecode=\"${mv.authtypecode}\"&index=${mv.id}','${mv.id}')" %] ... [% END %] [% ELSIF ( mv.type == 'text_plugin' ) %] [% IF mv.readonly %] - + [% ELSE %] - + [% IF ( mv.nopopup ) %] - ... + ... [% ELSE %] ... [% END %] @@ -145,15 +145,15 @@ [% END %] [% ELSIF ( mv.type == 'text' ) %] [% IF mv.readonly %] - + [% ELSE %] - + [% END %] [% ELSIF ( mv.type == 'textarea' ) %] [% IF mv.readonly %] - [% mv.value | html %] + [% mv.value | html %] [% ELSE %] - [% mv.value | html %] + [% mv.value | html %] [% END %] [% END %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt @@ -283,7 +283,8 @@ Holdings ([% itemloop.size() || 0 | html %]) [% END %] -[% IF ( MARCNOTES ) %]Descriptions ([% ( MARCNOTES.size || 1 ) | html %])[% END %] +[% IF Koha.Preference('EnableItemGroups') %]Item Groups[% END %] +[% IF ( MARCNOTES || notes ) %]Descriptions ([% ( MARCNOTES.size || 1 ) | html %])[% END %] [% IF ComponentParts && ComponentParts.size %]Components ([% ComponentParts.size | html %])[% END %] [% IF ( subscriptionsnumber ) %]Subscriptions[% END %] [% IF Koha.Preference('AcquisitionDetails') %]Acquisition details[% END %] @@ -321,6 +322,10 @@ [% IF CAN_user_tools_items_batchmod %] Modify selected items [% END %] + [% IF CAN_user_editcatalogue_manage_item_groups && biblio.item_groups.count %] + Add/move to item group + Remove from item group + [% END %] [% END %] @@ -335,6 +340,9 @@ Current library Home library [% IF ( itemdata_ccode ) %]Collection[% END %] + [% IF Koha.Preference('EnableItemGroups') %] + Item group + [% END %] Call number [% IF volinfo %] Serial enumeration / chronology @@ -409,6 +417,7 @@ Note that permanent location is a code, and location may be an authval. [% IF ( itemdata_ccode ) %][% item.ccode | html %][% END %] + [% IF Koha.Preference('EnableItemGroups') %][% item.object.item_group.description | html %][% END %] [% IF ( item.itemcallnumber ) %] [% item.itemcallnumber | html %][% END %] [% IF ( volinfo ) %] [% IF itemdata_publisheddate #If there is at least one published date, use it for sorting %] @@ -622,7 +631,30 @@ Note that permanent location is a code, and location may be an authval. [% END %][%# end of block items_table %] +<<<<<<< HEAD +======= +[% IF Koha.Preference('EnableItemGroups') %] + + [% IF CAN_user_editcatalogue_manage_item_groups %] + + New item group + + [% END %] + + + + Display Order + Description + + + + + +[% END %] + + +>>>>>>> Bug 24857: Add item group management to detail.pl [% IF ( Koha.Preference('NovelistSelectStaffEnabled') && Koha.Preference('NovelistSelectStaffProfile') && Koha.Preference('NovelistSelectStaffView') == 'above' ) %] @@ -1054,6 +1086,136 @@ Note that permanent location is a code, and location may be an authval. [% END %] + + + + + × + Create a new item group + + + + + + Name: + + Required + + + Display order: + + Required + + Numbers only, item groups will be displayed in counting order + + + + + + + + + + + + + + × + Edit item group + + + + + + Name: + + Required + + + Sort order: + + Numbers only, item groups will be displayed in counting order + + + + + + + + + + + + + + × + Delete item group + + + Are you sure you want to delete this item group? + + + + + + + + + + + × + Set item group for items + + + + + + Item group: + + [% FOREACH ig IN biblio.item_groups %] + [% ig.description | html %] + [% END %] + + Required + + + + + + + + + + + + + + × + Remove item from item group + + + Are you sure you want to remove these item(s) from their item group(s)? + + + + + + [% MACRO jsinclude BLOCK %] [% INCLUDE 'catalog-strings.inc' %] [% Asset.js("js/catalog.js") | $raw %] @@ -1411,6 +1573,250 @@ Note that permanent location is a code, and location may be an authval. if ( search_index ){ $('#cat-search-block select.advsearch').val(search_index)}; if ( search_value ){ $('#cat-search-block #search-form').val(search_value)}; }); + + [% IF Koha.Preference('EnableItemGroups') %] + // Load item groups table + var itemGroupsTable = KohaTable("items-group-table", { + "bAutoWidth": false, + 'sDom': '<"top pager"ilp>t<"bottom pager"ip>r', + "aoColumns": [ + { + "mDataProp": function( oObj ) { + return oObj.display_order; + }, + }, + { + "mDataProp": function( oObj ) { + return oObj.description; + }, + }, + { + "mDataProp": function( oObj ) { + [% IF CAN_user_editcatalogue_manage_item_groups %] + return ` + ${_("Edit")} + ` + + ' ' + + ` + ${('Delete')} + `; + [% ELSE %] + return ""; + [% END %] + }, + }, + ], + "bPaginate": false, + "bProcessing": true, + "bServerSide": false, + "sAjaxSource": `/api/v1/biblios/${biblionumber}/item_groups?_per_page=-1`, + "sAjaxDataProp": "", + "fnServerData": function ( sSource, aoData, fnCallback ) { + $.getJSON( sSource, aoData, function (json) { + fnCallback(json) + } ); + }, + }); + + // Create new item groups + $('.item-group-create').on('click', function(){ + $('#modal-item-group-create-form-description').val(""); + $('#modal-item-group-create-submit').removeAttr('disabled'); + $('#modal-item-group-create').modal('show'); + }); + + $("#modal-item-group-create-form").validate({ + submitHandler: function(form) { + $.ajax({ + url: `/api/v1/biblios/${biblionumber}/item_groups`, + headers: { "x-koha-embed": "items" }, + success: function(item_groups){ + $('#modal-item-group-create-submit').attr('disabled', 'disabled'); + + var settings = { + "url": `/api/v1/biblios/${biblionumber}/item_groups`, + "method": "POST", + "headers": { + "Content-Type": "application/json" + }, + "data": JSON.stringify( + { + "description": $("#modal-item-group-create-form-description").val(), + "display_order": $("#modal-item-group-create-form-display_order").val(), + } + ), + }; + + $.ajax(settings) + .done(function (response) { + $('#item-group-add-form-select').append($('', { + value: response.item_group_id, + text: response.description + })); + + $('#modal-item-group-create').modal('hide'); + if ( item_groups.length == 0 ) { + // This bib has no previous item groups, reload the page + window.location.replace(`/cgi-bin/koha/catalogue/detail.pl?biblionumber=${biblionumber}`); + } else { + // Has other item groups, just reload the table + itemGroupsTable.api().ajax.reload(); + } + }) + .fail(function(err) { + var message = err.responseJSON.error; + alert(message); + }); + } + }); + } + }); + + $('#modal-item-group-create').on('shown.bs.modal', function () { + $('#modal-item-group-create-form-description').focus(); + }) + + // Edit existing item groups + $('body').on( 'click', '.item-group-edit', function(){ + const item_group_id = $(this).data('item-group-id'); + const url = `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`; + $.get( url, function( data ) { + $('#modal-item-group-edit-form-description').val( data.description ); + $('#modal-item-group-edit-form-display_order').val( data.display_order ); + $('#modal-item-group-edit-submit').data('item-group-id', item_group_id ); + $('#modal-item-group-edit-submit').removeAttr('disabled'); + $('#modal-item-group-edit').modal('show'); + }); + }); + + $("#modal-item-group-edit-form").validate({ + submitHandler: function(form) { + $('#modal-item-group-edit-submit').attr('disabled', 'disabled'); + + const item_group_id = $('#modal-item-group-edit-submit').data('item-group-id'); + const url = `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`; + + var settings = { + "url": url, + "method": "PUT", + "headers": { + "Content-Type": "application/json" + }, + "data": JSON.stringify( + { + "description": $("#modal-item-group-edit-form-description").val(), + "display_order": $("#modal-item-group-edit-form-display_order").val(), + } + ), + }; + + $.ajax(settings) + .done(function (response) { + $('#modal-item-group-edit').modal('hide'); + itemGroupsTable.api().ajax.reload(); + }) + .fail(function(err) { + var message = err.responseJSON.error; + alert(message); + }); + } + }); + + $('#modal-item-group-edit').on('shown.bs.modal', function () { + $('#modal-item-group-edit-form-description').focus(); + }) + + // Delete existing item groups + $('body').on( 'click', '.item-group-delete', function(){ + const item_group_id = $(this).data('item-group-id'); + $('#modal-item-group-delete-submit').data('item-group-id', item_group_id ); + $('#modal-item-group-delete-submit').removeAttr('disabled'); + $('#modal-item-group-delete').modal('show'); + }); + $("#modal-item-group-delete-submit").on('click', function(){ + $('#modal-item-group-delete-submit').attr('disabled', 'disabled'); + const item_group_id = $("#modal-item-group-delete-submit").data('item-group-id'); + + $.ajax({ + url: `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`, + headers: { "x-koha-embed": "items" }, + success: function(item_group_data){ + $.ajax({ + "url": `/api/v1/biblios/${biblionumber}/item_groups/${item_group_id}`, + "method": "DELETE", + }) + .done(function (response) { + $('#modal-item-group-delete').modal('hide'); + $(`#item-group-add-form-select option[value='${item_group_id}']`).remove(); + if ( item_group_data.items === null ) { + // No items for this item group, we can just refresh the table + itemGroupsTable.api().ajax.reload(); + } else { + // This item group had items attached to it, we need to reload the page + window.location.replace(`/cgi-bin/koha/catalogue/detail.pl?biblionumber=${biblionumber}`); + } + }) + .fail(function(err) { + var message = err.responseJSON.error; + alert(message); + }); + } + }); + }); + + // Add item(s) to a item group + $('.itemselection_action_item_group_set').on('click', function(){ + $('#modal-item-group-set').modal('show'); + }); + + $("#modal-item-group-set-form").validate({ + submitHandler: function(form) { + $('#modal-item-group-set-submit').attr('disabled', 'disabled'); + + const item_group_id = $('#item-group-add-form-select').val(); + + let itemnumbers = new Array(); + $("input[name='itemnumber'][type='checkbox']:checked").each(function() { + const itemnumber = $(this).val(); + itemnumbers.push( itemnumber ); + }); + if (itemnumbers.length > 0) { + let url = '/cgi-bin/koha/catalogue/detail.pl?op=set_item_group'; + url += '&itemnumber=' + itemnumbers.join('&itemnumber='); + url += '&biblionumber=[% biblionumber | uri %]'; + url += `&item_group_id=${item_group_id}`; + + window.location.replace(url); + } + + $('#modal-item-group-set').modal('hide'); + } + }); + + // Remove item(s) from an item group + $('.itemselection_action_item_group_unset').on('click', function(){ + $('#modal-item-group-unset').modal('show'); + }); + + $("#modal-item-group-unset-submit").on('click', function(){ + $('#modal-item-group-unset-submit').attr('disabled', 'disabled'); + + let itemnumbers = new Array(); + $("input[name='itemnumber'][type='checkbox']:checked").each(function() { + const itemnumber = $(this).val(); + itemnumbers.push( itemnumber ); + }); + if (itemnumbers.length > 0) { + let url = '/cgi-bin/koha/catalogue/detail.pl?op=unset_item_group'; + url += '&itemnumber=' + itemnumbers.join('&itemnumber='); + url += '&biblionumber=[% biblionumber | uri %]'; + + window.location.replace(url); + } + + $('#modal-item-group-unset').modal('hide'); + }); + [% END %] [% END %] [% INCLUDE 'intranet-bottom.inc' %] --
+ Name: + + Required +
+ Display order: + + Required + + Numbers only, item groups will be displayed in counting order +
+ Sort order: + + Numbers only, item groups will be displayed in counting order +
+ Item group: + + [% FOREACH ig IN biblio.item_groups %] + [% ig.description | html %] + [% END %] + + Required +