From 393c72ad16ea7915a38f37b76705d5d5eca144fd Mon Sep 17 00:00:00 2001 From: Julian Maurice Date: Fri, 14 Apr 2017 15:45:04 +0200 Subject: [PATCH] Bug 18433: Allow to select results to export in item search This adds a column of checkboxes in the results table to be able to select the items to be exported Test plan: 1. Go to item search and click 'Search' 2. Without checking any checkbox, verify that the export still works (it should export all results) 3. Tick some checkboxes and re-export, verify that only selected items are exported --- Koha/AuthorisedValueCategories.pm | 23 +++++ Koha/Template/Plugin/AuthorisedValues.pm | 9 ++ catalogue/item-export.pl | 70 +++++++++++++ catalogue/itemsearch.pl | 45 +-------- .../en/includes/catalogue/itemsearch_item.csv.inc | 5 +- .../en/includes/catalogue/itemsearch_item.json.inc | 10 +- .../prog/en/modules/catalogue/itemsearch.tt | 108 +++++++++++++++++---- 7 files changed, 208 insertions(+), 62 deletions(-) create mode 100755 catalogue/item-export.pl diff --git a/Koha/AuthorisedValueCategories.pm b/Koha/AuthorisedValueCategories.pm index b756f6ab1e..5702893aea 100644 --- a/Koha/AuthorisedValueCategories.pm +++ b/Koha/AuthorisedValueCategories.pm @@ -22,6 +22,7 @@ use Carp; use Koha::Database; use Koha::AuthorisedValueCategory; +use Koha::MarcSubfieldStructures; use base qw(Koha::Objects); @@ -35,6 +36,28 @@ Koha::AuthorisedValueCategories - Koha AuthorisedValueCategory Object set class =cut +=head3 findByKohaField + + my $category = Koha::AuthorisedValueCategories->findByKohaField($kohafield, [$frameworkcode]); + +Returns the authorised value category linked to the given koha field + +=cut + +sub findByKohaField { + my ($class, $kohafield, $frameworkcode) = @_; + + $frameworkcode //= ''; + + my ($subfield) = Koha::MarcSubfieldStructures->search({ + frameworkcode => $frameworkcode, + kohafield => $kohafield, + authorised_value => { not => undef }, + }); + + return $subfield ? $class->find($subfield->authorised_value) : undef; +} + =head3 type =cut diff --git a/Koha/Template/Plugin/AuthorisedValues.pm b/Koha/Template/Plugin/AuthorisedValues.pm index 05c27b843d..280b4eb21e 100644 --- a/Koha/Template/Plugin/AuthorisedValues.pm +++ b/Koha/Template/Plugin/AuthorisedValues.pm @@ -23,6 +23,7 @@ use base qw( Template::Plugin ); use C4::Koha; use Koha::AuthorisedValues; +use Koha::AuthorisedValueCategories; sub GetByCode { my ( $self, $category, $code, $opac ) = @_; @@ -68,6 +69,14 @@ sub GetCategories { ]; } +sub GetCategoryByKohaField { + my ($self, $kohafield, $frameworkcode) = @_; + + my $category = Koha::AuthorisedValueCategories->findByKohaField($kohafield, $frameworkcode); + + return $category ? $category->category_name : undef; +} + 1; =head1 NAME diff --git a/catalogue/item-export.pl b/catalogue/item-export.pl new file mode 100755 index 0000000000..564cd0be93 --- /dev/null +++ b/catalogue/item-export.pl @@ -0,0 +1,70 @@ +#!/usr/bin/perl + +# Copyright 2017 BibLibre +# +# This file is part of Koha +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with Koha; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use CGI; + +use C4::Auth; +use C4::Output; + +my $cgi = new CGI; + +my ($template, $borrowernumber, $cookie) = get_template_and_user({ + template_name => 'catalogue/itemsearch_csv.tt', + query => $cgi, + type => 'intranet', + authnotrequired => 0, + flagsrequired => { catalogue => 1 }, +}); + +my @itemnumbers = $cgi->multi_param('itemnumber'); +my $format = $cgi->param('format') // 'csv'; + +my @items; +foreach my $itemnumber (@itemnumbers) { + my $item = Koha::Items->find($itemnumber); + if ($item) { + push @items, $item; + } +} + +if ($format eq 'barcodes') { + print $cgi->header({ + type => 'text/plain', + attachment => 'barcodes.txt', + }); + + foreach my $item (@items) { + print $item->barcode . "\n"; + } + exit; +} + +$template->param( + results => \@items, +); + +print $cgi->header({ + type => 'text/csv', + attachment => 'items.csv', +}); +for my $line ( split '\n', $template->output ) { + print "$line\n" unless $line =~ m|^\s*$|; +} diff --git a/catalogue/itemsearch.pl b/catalogue/itemsearch.pl index 5f20dd3813..7ca7013a60 100755 --- a/catalogue/itemsearch.pl +++ b/catalogue/itemsearch.pl @@ -27,7 +27,7 @@ use C4::Items; use C4::Biblio; use C4::Koha; -use Koha::AuthorisedValues; +use Koha::AuthorisedValueCategories; use Koha::Item::Search::Field qw(GetItemSearchFields); use Koha::ItemTypes; use Koha::Libraries; @@ -90,12 +90,6 @@ my ($template, $borrowernumber, $cookie) = get_template_and_user({ flagsrequired => { catalogue => 1 }, }); -my $mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.notforloan', authorised_value => { not => undef } }); -my $notforloan_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : []; - -$mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.location', authorised_value => { not => undef } }); -my $location_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : []; - if (scalar keys %params > 0) { # Parameters given, it's a search @@ -213,25 +207,9 @@ if (scalar keys %params > 0) { } if ($results) { - # Get notforloan labels - my $notforloan_map = {}; - foreach my $nfl_value (@$notforloan_values) { - $notforloan_map->{$nfl_value->{authorised_value}} = $nfl_value->{lib}; - } - - # Get location labels - my $location_map = {}; - foreach my $loc_value (@$location_values) { - $location_map->{$loc_value->{authorised_value}} = $loc_value->{lib}; - } - foreach my $item (@$results) { $item->{biblio} = GetBiblio($item->{biblionumber}); ($item->{biblioitem}) = GetBiblioItemByBiblioNumber($item->{biblionumber}); - $item->{status} = $notforloan_map->{$item->{notforloan}}; - if (defined $item->{location}) { - $item->{location} = $location_map->{$item->{location}}; - } } } @@ -261,13 +239,6 @@ if (scalar keys %params > 0) { # Display the search form my @branches = map { value => $_->branchcode, label => $_->branchname }, Koha::Libraries->search( {}, { order_by => 'branchname' } ); -my @locations; -foreach my $location (@$location_values) { - push @locations, { - value => $location->{authorised_value}, - label => $location->{lib} // $location->{authorised_value}, - }; -} my @itemtypes; foreach my $itemtype ( Koha::ItemTypes->search ) { push @itemtypes, { @@ -276,8 +247,8 @@ foreach my $itemtype ( Koha::ItemTypes->search ) { }; } -$mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.ccode', authorised_value => { not => undef } }); -my $ccode_avcode = $mss->count ? $mss->next->authorised_value : 'CCODE'; +my $ccode_avcategory = Koha::AuthorisedValueCategories->findByKohaField('items.ccode'); +my $ccode_avcode = $ccode_avcategory ? $ccode_avcategory->category_name : 'CCODE'; my $ccodes = GetAuthorisedValues($ccode_avcode); my @ccodes; foreach my $ccode (@$ccodes) { @@ -287,14 +258,6 @@ foreach my $ccode (@$ccodes) { }; } -my @notforloans; -foreach my $value (@$notforloan_values) { - push @notforloans, { - value => $value->{authorised_value}, - label => $value->{lib}, - }; -} - my @items_search_fields = GetItemSearchFields(); my $authorised_values = {}; @@ -306,10 +269,8 @@ foreach my $field (@items_search_fields) { $template->param( branches => \@branches, - locations => \@locations, itemtypes => \@itemtypes, ccodes => \@ccodes, - notforloans => \@notforloans, items_search_fields => \@items_search_fields, authorised_values_json => to_json($authorised_values), ); diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc index 5e38a58db5..aeef03ed14 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc @@ -1,5 +1,8 @@ [%- USE Branches -%] [%- USE Koha -%] +[%- USE AuthorisedValues -%] [%- biblio = item.biblio -%] [%- biblioitem = item.biblioitem -%] -"[% biblio.title |html %] [% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %]by [% END %][% biblio.author |html %]", "[% (biblioitem.publicationyear || biblio.copyrightdate) |html %]", "[% biblioitem.publishercode |html %]", "[% biblioitem.collectiontitle |html %]", "[% item.barcode |html %]", "[% item.itemcallnumber |html %]", "[% Branches.GetName(item.homebranch) |html %]", "[% Branches.GetName(item.holdingbranch) |html %]", "[% item.location |html %]", "[% item.stocknumber |html %]", "[% item.status |html %]", "[% (item.issues || 0) |html %]" +[%- notforloan_avcategory = AuthorisedValues.GetCategoryByKohaField('items.notforloan') -%] +[%- location_avcategory = AuthorisedValues.GetCategoryByKohaField('items.location') -%] +"[% biblio.title |html %] [% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %]by [% END %][% biblio.author |html %]", "[% (biblioitem.publicationyear || biblio.copyrightdate) |html %]", "[% biblioitem.publishercode |html %]", "[% biblioitem.collectiontitle |html %]", "[% item.barcode |html %]", "[% item.itemcallnumber |html %]", "[% Branches.GetName(item.homebranch) |html %]", "[% Branches.GetName(item.holdingbranch) |html %]", "[% IF location_avcategory %][% AuthorisedValues.GetByCode(location_avcategory, item.location) |html %][% ELSE %][% item.location |html %][% END %]", "[% item.stocknumber |html %]", "[% IF notforloan_avcategory %][% AuthorisedValues.GetByCode(notforloan_avcategory, item.notforloan) |html %][% ELSE %][% item.notforloan |html %][% END %]", "[% (item.issues || 0) |html %]" diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc index 4085b94999..20f6d42064 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc @@ -1,9 +1,15 @@ [%- USE Branches -%] [%- USE Koha -%] +[%- USE AuthorisedValues -%] [%- biblio = item.biblio -%] [%- biblioitem = item.biblioitem -%] +[%- notforloan_avcategory = AuthorisedValues.GetCategoryByKohaField('items.notforloan') -%] +[%- location_avcategory = AuthorisedValues.GetCategoryByKohaField('items.location') -%] [ "[% FILTER escape_quotes = replace('"', '\"') ~%] + + [%~ END %]", + "[% FILTER escape_quotes ~%] [% biblio.title |html %][% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %] by[% END %] [% biblio.author |html %] [%~ END %]", "[% (biblioitem.publicationyear || biblio.copyrightdate) |html %]", @@ -15,9 +21,9 @@ "[% item.itemcallnumber |html %]", "[% Branches.GetName(item.homebranch) |html %]", "[% Branches.GetName(item.holdingbranch) |html %]", - "[% item.location |html %]", + "[% IF location_avcategory %][% AuthorisedValues.GetByCode(location_avcategory, item.location) | html %][% ELSE %][% item.location |html %][% END %]", "[% item.stocknumber |html %]", - "[% item.status |html %]", + "[% IF notforloan_avcategory %][% AuthorisedValues.GetByCode(notforloan_avcategory, item.notforloan) | html %][% ELSE %][% item.notforloan |html %][% END %]", "[% (item.issues || 0) |html %]", "[% FILTER escape_quotes ~%] Edit diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/itemsearch.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/itemsearch.tt index 5905e3e281..e721da65d3 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/itemsearch.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/itemsearch.tt @@ -1,5 +1,6 @@ [% USE CGI %] [% USE JSON.Escape %] +[% USE AuthorisedValues %] [% BLOCK form_label %] [% SWITCH label %] @@ -155,6 +156,24 @@ [% END %] +[% notforloan_avcategory = AuthorisedValues.GetCategoryByKohaField('items.notforloan') %] +[% IF notforloan_avcategory %] + [% notforloans = AuthorisedValues.Get(notforloan_avcategory) %] + [% FOREACH nfl IN notforloans %] + [% nfl.value = nfl.authorised_value %] + [% nfl.label = nfl.lib %] + [% END %] +[% END %] + +[% location_avcategory = AuthorisedValues.GetCategoryByKohaField('items.location') %] +[% IF location_avcategory %] + [% locations = AuthorisedValues.Get(location_avcategory) %] + [% FOREACH loc IN locations %] + [% loc.value = loc.authorised_value %] + [% loc.label = loc.lib %] + [% END %] +[% END %] + [%# Page starts here %] [% INCLUDE 'doc-head-open.inc' %] @@ -207,6 +226,7 @@ function submitForm($form) { var tr = '' + ' ' + + ' ' + ' ' + _("Title") + '' + ' ' + _("Publication date") + '' + ' ' + _("Publisher") + '' @@ -239,38 +259,79 @@ $('#item-search-block').show(); }); + function exportItems(format) { + var itemnumbers = []; + $('#results').find('input[name="itemnumber"]:checked').each(function() { + itemnumbers.push($(this).val()); + }); + if (itemnumbers.length) { + var href = '/cgi-bin/koha/catalogue/item-export.pl?format=' + format; + href += '&itemnumber=' + itemnumbers.join('&itemnumber='); + location = href; + } else { + $('#format-' + format).prop('checked', true); + $('#itemsearchform').submit(); + $('#format-html').prop('checked', true); + } + } + var csvExportLink = $('') .attr('href', '#') - .html(_("Export results to CSV")) - .addClass('btn btn-default btn-xs') + .html(_("CSV")) .on('click', function(e) { e.preventDefault(); - $('#format-csv').prop('checked', true); - $('#itemsearchform').submit(); - $('#format-html').prop('checked', true); + exportItems('csv') }); var barcodesExportLink = $('') .attr('href', '#') - .html(_("Export results to barcodes file")) - .addClass('btn btn-default btn-xs') + .html(_("Barcodes file")) .on('click', function(e) { e.preventDefault(); - $('#format-barcodes').prop('checked', true); - $('#itemsearchform').submit(); - $('#format-html').prop('checked', true); + exportItems('barcodes'); }); - var editSearchAndExportLinks = $('

') - .append(editSearchLink) - .append(' | ') - .append(csvExportLink) + var exportButton = $('

') + .addClass('btn-group') + .append($('