View | Details | Raw Unified | Return to bug 18433
Collapse All | Expand All

(-)a/catalogue/item-export.pl (+64 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2017 BibLibre
4
#
5
# This file is part of Koha
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use CGI;
23
24
use C4::Auth;
25
use C4::Output;
26
27
my $cgi = new CGI;
28
29
my ($template, $borrowernumber, $cookie) = get_template_and_user({
30
    template_name => 'catalogue/itemsearch_csv.tt',
31
    query => $cgi,
32
    type => 'intranet',
33
    authnotrequired => 0,
34
    flagsrequired   => { catalogue => 1 },
35
});
36
37
my @itemnumbers = $cgi->multi_param('itemnumber');
38
my $format = $cgi->param('format') // 'csv';
39
40
my @items = Koha::Items->search({ itemnumber => { -in => \@itemnumbers } });
41
42
if ($format eq 'barcodes') {
43
    print $cgi->header({
44
        type => 'text/plain',
45
        attachment => 'barcodes.txt',
46
    });
47
48
    foreach my $item (@items) {
49
        print $item->barcode . "\n";
50
    }
51
    exit;
52
}
53
54
$template->param(
55
    results => \@items,
56
);
57
58
print $cgi->header({
59
    type => 'text/csv',
60
    attachment => 'items.csv',
61
});
62
for my $line ( split '\n', $template->output ) {
63
    print "$line\n" unless $line =~ m|^\s*$|;
64
}
(-)a/catalogue/itemsearch.pl (-61 / +5 lines)
Lines 97-109 my ($template, $borrowernumber, $cookie) = get_template_and_user({ Link Here
97
    flagsrequired   => { catalogue => 1 },
97
    flagsrequired   => { catalogue => 1 },
98
});
98
});
99
99
100
my $mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.notforloan', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
100
my $mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.itemlost', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
101
my $notforloan_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : [];
102
103
$mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.location', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
104
my $location_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : [];
105
106
$mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.itemlost', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
107
my $itemlost_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : [];
101
my $itemlost_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : [];
108
102
109
$mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.withdrawn', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
103
$mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.withdrawn', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
Lines 226-263 if (scalar keys %params > 0) { Link Here
226
    }
220
    }
227
221
228
    if ($results) {
222
    if ($results) {
229
        # Get notforloan labels
230
        my $notforloan_map = {};
231
        foreach my $nfl_value (@$notforloan_values) {
232
            $notforloan_map->{$nfl_value->{authorised_value}} = $nfl_value->{lib};
233
        }
234
235
        # Get location labels
236
        my $location_map = {};
237
        foreach my $loc_value (@$location_values) {
238
            $location_map->{$loc_value->{authorised_value}} = $loc_value->{lib};
239
        }
240
241
        # Get itemlost labels
242
        my $itemlost_map = {};
243
        foreach my $il_value (@$itemlost_values) {
244
            $itemlost_map->{$il_value->{authorised_value}} = $il_value->{lib};
245
        }
246
247
        # Get withdrawn labels
248
        my $withdrawn_map = {};
249
        foreach my $wd_value (@$withdrawn_values) {
250
            $withdrawn_map->{$wd_value->{authorised_value}} = $wd_value->{lib};
251
        }
252
253
        foreach my $item (@$results) {
223
        foreach my $item (@$results) {
254
            my $biblio = Koha::Biblios->find( $item->{biblionumber} );
224
            my $biblio = Koha::Biblios->find( $item->{biblionumber} );
255
            $item->{biblio} = $biblio;
225
            $item->{biblio} = $biblio;
256
            $item->{biblioitem} = $biblio->biblioitem->unblessed;
226
            $item->{biblioitem} = $biblio->biblioitem->unblessed;
257
            $item->{status} = $notforloan_map->{$item->{notforloan}};
258
            if (defined $item->{location}) {
259
                $item->{location} = $location_map->{$item->{location}};
260
            }
261
        }
227
        }
262
    }
228
    }
263
229
Lines 288-300 if (scalar keys %params > 0) { Link Here
288
# Display the search form
254
# Display the search form
289
255
290
my @branches = map { value => $_->branchcode, label => $_->branchname }, Koha::Libraries->search( {}, { order_by => 'branchname' } );
256
my @branches = map { value => $_->branchcode, label => $_->branchname }, Koha::Libraries->search( {}, { order_by => 'branchname' } );
291
my @locations;
292
foreach my $location (@$location_values) {
293
    push @locations, {
294
        value => $location->{authorised_value},
295
        label => $location->{lib} // $location->{authorised_value},
296
    };
297
}
298
my @itemtypes;
257
my @itemtypes;
299
foreach my $itemtype ( Koha::ItemTypes->search ) {
258
foreach my $itemtype ( Koha::ItemTypes->search ) {
300
    push @itemtypes, {
259
    push @itemtypes, {
Lines 303-325 foreach my $itemtype ( Koha::ItemTypes->search ) { Link Here
303
    };
262
    };
304
}
263
}
305
264
306
$mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.ccode', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
265
my @ccodes = Koha::AuthorisedValues->get_descriptions_by_koha_field({ kohafield => 'items.ccode' });
307
my $ccode_avcode = $mss->count ? $mss->next->authorised_value : 'CCODE';
266
foreach my $ccode (@ccodes) {
308
my $ccodes = GetAuthorisedValues($ccode_avcode);
267
    $ccode->{value} = $ccode->{authorised_value},
309
my @ccodes;
268
    $ccode->{label} = $ccode->{lib},
310
foreach my $ccode (@$ccodes) {
311
    push @ccodes, {
312
        value => $ccode->{authorised_value},
313
        label => $ccode->{lib},
314
    };
315
}
316
317
my @notforloans;
318
foreach my $value (@$notforloan_values) {
319
    push @notforloans, {
320
        value => $value->{authorised_value},
321
        label => $value->{lib},
322
    };
323
}
269
}
324
270
325
my @itemlosts;
271
my @itemlosts;
Lines 349-358 foreach my $field (@items_search_fields) { Link Here
349
295
350
$template->param(
296
$template->param(
351
    branches => \@branches,
297
    branches => \@branches,
352
    locations => \@locations,
353
    itemtypes => \@itemtypes,
298
    itemtypes => \@itemtypes,
354
    ccodes => \@ccodes,
299
    ccodes => \@ccodes,
355
    notforloans => \@notforloans,
356
    itemlosts => \@itemlosts,
300
    itemlosts => \@itemlosts,
357
    withdrawns => \@withdrawns,
301
    withdrawns => \@withdrawns,
358
    items_search_fields => \@items_search_fields,
302
    items_search_fields => \@items_search_fields,
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.csv.inc (-2 / +2 lines)
Lines 1-7 Link Here
1
[%- USE Branches -%]
1
[%- USE Branches -%]
2
[%- USE Koha -%]
2
[%- USE Koha -%]
3
[%- USE ItemTypes -%]
3
[%- USE ItemTypes -%]
4
[% USE AuthorisedValues %]
4
[%- USE AuthorisedValues -%]
5
[%- SET biblio = item.biblio -%]
5
[%- SET biblio = item.biblio -%]
6
[%- SET biblioitem = item.biblioitem -%]
6
[%- SET biblioitem = item.biblioitem -%]
7
"[% biblio.title | html %] [% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %]by [% END %][% biblio.author | html %]", "[% (biblioitem.publicationyear || biblio.copyrightdate) | html %]", "[% biblioitem.publishercode | html %]", "[% AuthorisedValues.GetByCode( 'CCODE', item.ccode ) | html %]", "[% item.barcode | html %]", "[% item.itemcallnumber | html %]", "[% Branches.GetName(item.homebranch) | html %]", "[% Branches.GetName(item.holdingbranch) | html %]", "[% item.location | html %]", "[% ItemTypes.GetDescription(item.itype) | html %]", "[% item.stocknumber | html %]", "[% item.status | html %]","[% AuthorisedValues.GetByCode( 'LOST', item.itemlost ) || "" | html %]","[% AuthorisedValues.GetByCode( 'WITHDRAWN', item.withdrawn ) || "" | html %]", "[% (item.issues || 0) | html %]"
7
"[% biblio.title | html %] [% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %]by [% END %][% biblio.author | html %]", "[% (biblioitem.publicationyear || biblio.copyrightdate) | html %]", "[% biblioitem.publishercode | html %]", "[% AuthorisedValues.GetByCode( 'CCODE', item.ccode ) | html %]", "[% item.barcode | html %]", "[% item.itemcallnumber | html %]", "[% Branches.GetName(item.homebranch) | html %]", "[% Branches.GetName(item.holdingbranch) | html %]", "[% AuthorisedValues.GetDescriptionByKohaField(frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => item.location) | html %]", "[% ItemTypes.GetDescription(item.itype) | html %]", "[% item.stocknumber | html %]", "[% AuthorisedValues.GetDescriptionByKohaField(frameworkcode => biblio.frameworkcode, kohafield => 'items.notforloan', authorised_value => item.notforloan) | html %]","[% AuthorisedValues.GetByCode( 'LOST', item.itemlost ) || "" | html %]","[% AuthorisedValues.GetByCode( 'WITHDRAWN', item.withdrawn ) || "" | html %]", "[% (item.issues || 0) | html %]"
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/catalogue/itemsearch_item.json.inc (-3 / +6 lines)
Lines 2-12 Link Here
2
[%- USE Koha -%]
2
[%- USE Koha -%]
3
[%- USE To -%]
3
[%- USE To -%]
4
[%- USE ItemTypes -%]
4
[%- USE ItemTypes -%]
5
[% USE AuthorisedValues %]
5
[%- USE AuthorisedValues -%]
6
[%- biblio = item.biblio -%]
6
[%- biblio = item.biblio -%]
7
[%- biblioitem = item.biblioitem -%]
7
[%- biblioitem = item.biblioitem -%]
8
[
8
[
9
  "[% FILTER escape_quotes = replace('"', '\"') ~%]
9
  "[% FILTER escape_quotes = replace('"', '\"') ~%]
10
    <input type="checkbox" name="itemnumber" value="[% item.itemnumber %]"/>
11
  [%~ END %]",
12
  "[% FILTER escape_quotes ~%]
10
    <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber | uri %]" title="Go to record detail page">[% biblio.title | html %]</a>[% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %] by[% END %] [% biblio.author | html %]
13
    <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblio.biblionumber | uri %]" title="Go to record detail page">[% biblio.title | html %]</a>[% IF ( Koha.Preference( 'marcflavour' ) == 'UNIMARC' && biblio.author ) %] by[% END %] [% biblio.author | html %]
11
  [%~ END %]",
14
  [%~ END %]",
12
  "[% (biblioitem.publicationyear || biblio.copyrightdate) | html %]",
15
  "[% (biblioitem.publicationyear || biblio.copyrightdate) | html %]",
Lines 18-27 Link Here
18
  "[% item.itemcallnumber | html %]",
21
  "[% item.itemcallnumber | html %]",
19
  "[% Branches.GetName(item.homebranch) | html %]",
22
  "[% Branches.GetName(item.homebranch) | html %]",
20
  "[% Branches.GetName(item.holdingbranch) | html %]",
23
  "[% Branches.GetName(item.holdingbranch) | html %]",
21
  "[% item.location | html %]",
24
  "[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.location', authorised_value => item.location) | html %]",
22
  "[% ItemTypes.GetDescription(item.itype) | html %]",
25
  "[% ItemTypes.GetDescription(item.itype) | html %]",
23
  "[% item.stocknumber | html %]",
26
  "[% item.stocknumber | html %]",
24
  "[% item.status | html %]",
27
  "[% AuthorisedValues.GetDescriptionByKohaField( frameworkcode => biblio.frameworkcode, kohafield => 'items.notforloan', authorised_value => item.notforloan) | html %]",
25
  "[% AuthorisedValues.GetByCode( 'LOST', item.itemlost ) || "" | html %]",
28
  "[% AuthorisedValues.GetByCode( 'LOST', item.itemlost ) || "" | html %]",
26
  "[% AuthorisedValues.GetByCode( 'WITHDRAWN', item.withdrawn ) || "" | html %]",
29
  "[% AuthorisedValues.GetByCode( 'WITHDRAWN', item.withdrawn ) || "" | html %]",
27
  "[% (item.issues || 0) | html %]",
30
  "[% (item.issues || 0) | html %]",
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/itemsearch.tt (-19 / +86 lines)
Lines 1-6 Link Here
1
[% USE raw %]
1
[% USE raw %]
2
[% USE To %]
2
[% USE To %]
3
[% USE Asset %]
3
[% USE Asset %]
4
[% USE AuthorisedValues %]
4
5
5
[% BLOCK form_label %]
6
[% BLOCK form_label %]
6
  [% SWITCH label %]
7
  [% SWITCH label %]
Lines 110-115 Link Here
110
    [%- To.json(escaped) | $raw -%]
111
    [%- To.json(escaped) | $raw -%]
111
[%- END -%]
112
[%- END -%]
112
113
114
[% notforloans = AuthorisedValues.GetDescriptionsByKohaField({ kohafield = 'items.notforloan' }) %]
115
[% FOREACH nfl IN notforloans %]
116
    [% nfl.value = nfl.authorised_value %]
117
    [% nfl.label = nfl.lib %]
118
[% END %]
119
120
[% locations = AuthorisedValues.GetDescriptionsByKohaField({ kohafield = 'items.location' }) %]
121
[% FOREACH loc IN locations %]
122
    [% loc.value = loc.authorised_value %]
123
    [% loc.label = loc.lib %]
124
[% END %]
125
113
[%# Page starts here %]
126
[%# Page starts here %]
114
127
115
[% SET footerjs = 1 %]
128
[% SET footerjs = 1 %]
Lines 266-271 Link Here
266
        function submitForm($form) {
279
        function submitForm($form) {
267
            var tr = ''
280
            var tr = ''
268
                + '    <tr>'
281
                + '    <tr>'
282
                + '      <th id="items_checkbox"></th>'
269
                + '      <th id="items_title">' + _("Title") + '</th>'
283
                + '      <th id="items_title">' + _("Title") + '</th>'
270
                + '      <th id="items_pubdate">' + _("Publication date") + '</th>'
284
                + '      <th id="items_pubdate">' + _("Publication date") + '</th>'
271
                + '      <th id="items_publisher">' + _("Publisher") + '</th>'
285
                + '      <th id="items_publisher">' + _("Publisher") + '</th>'
Lines 301-338 Link Here
301
                    $('#item-search-block').show();
315
                    $('#item-search-block').show();
302
                });
316
                });
303
317
318
            function exportItems(format) {
319
              var itemnumbers = [];
320
              $('#results').find('input[name="itemnumber"]:checked').each(function() {
321
                itemnumbers.push($(this).val());
322
              });
323
              if (itemnumbers.length) {
324
                var href = '/cgi-bin/koha/catalogue/item-export.pl?format=' + format;
325
                href += '&itemnumber=' + itemnumbers.join('&itemnumber=');
326
                location = href;
327
              } else {
328
                $('#format-' + format).prop('checked', true);
329
                $('#itemsearchform').submit();
330
                $('#format-html').prop('checked', true);
331
              }
332
            }
333
304
            var csvExportLink = $('<a>')
334
            var csvExportLink = $('<a>')
305
                .attr('href', '#')
335
                .attr('href', '#')
306
                .html(_("Export results to CSV"))
336
                .html("CSV")
307
                .addClass('btn btn-default btn-xs')
308
                .on('click', function(e) {
337
                .on('click', function(e) {
309
                    e.preventDefault();
338
                    e.preventDefault();
310
                    $('#format-csv').prop('checked', true);
339
                    exportItems('csv');
311
                    $('#itemsearchform').submit();
312
                    $('#format-html').prop('checked', true);
313
                });
340
                });
314
            var barcodesExportLink = $('<a>')
341
            var barcodesExportLink = $('<a>')
315
                .attr('href', '#')
342
                .attr('href', '#')
316
                .html(_("Export results to barcodes file"))
343
                .html(_("Barcodes file"))
317
                .addClass('btn btn-default btn-xs')
318
                .on('click', function(e) {
344
                .on('click', function(e) {
319
                    e.preventDefault();
345
                    e.preventDefault();
320
                    $('#format-barcodes').prop('checked', true);
346
                    exportItems('barcodes');
321
                    $('#itemsearchform').submit();
322
                    $('#format-html').prop('checked', true);
323
              });
347
              });
324
348
325
            var editSearchAndExportLinks = $('<p>')
349
            var exportButton = $('<div>')
326
                .append(editSearchLink)
350
              .addClass('btn-group')
327
                .append(' | ')
351
              .append($('<button>')
328
                .append(csvExportLink)
352
                  .addClass('btn btn-default btn-xs dropdown-toggle')
329
                .append(' ')
353
                  .attr('id', 'export-button')
330
                .append(barcodesExportLink);
354
                  .attr('data-toggle', 'dropdown')
355
                  .attr('aria-haspopup', 'true')
356
                  .attr('aria-expanded', 'false')
357
                  .html(_("Export all results to") + ' <span class="caret"></span>'))
358
              .append($('<ul>')
359
                  .addClass('dropdown-menu')
360
                  .append($('<li>').append(csvExportLink))
361
                  .append($('<li>').append(barcodesExportLink)));
362
363
            var selectVisibleRows = $('<a>')
364
              .attr('href', '#')
365
              .append('<i class="fa fa-check"></i> ')
366
              .append(_("Select visible rows"))
367
              .on('click', function(e) {
368
                  e.preventDefault();
369
                  $('#results input[type="checkbox"]').prop('checked', true).change();
370
              });
371
            var clearSelection = $('<a>')
372
              .attr('href', '#')
373
              .append('<i class="fa fa-remove"></i> ')
374
              .append(_("Clear selection"))
375
              .on('click', function(e) {
376
                  e.preventDefault();
377
                  $('#results input[type="checkbox"]').prop('checked', false).change();
378
              });
379
            var exportLinks = $('<p>')
380
              .append(selectVisibleRows)
381
              .append(' ')
382
              .append(clearSelection)
383
              .append(' | ')
384
              .append(exportButton);
331
385
332
            var results_heading = $('<div>').addClass('results-heading')
386
            var results_heading = $('<div>').addClass('results-heading')
333
                .append("<h1>" + _("Item search results") + "</h1>")
387
                .append("<h1>" + _("Item search results") + "</h1>")
334
                .append($('<p>').append(advSearchLink))
388
                .append($('<p>').append(advSearchLink))
335
                .append(editSearchAndExportLinks);
389
                .append($('<p>').append(editSearchLink))
390
                .append(exportLinks);
336
            $('#results-wrapper').empty()
391
            $('#results-wrapper').empty()
337
                .append(results_heading)
392
                .append(results_heading)
338
                .append(table);
393
                .append(table);
Lines 369-375 Link Here
369
                    });
424
                    });
370
                },
425
                },
371
                'sDom': '<"top pager"ilp>t<"bottom pager"ip>r',
426
                'sDom': '<"top pager"ilp>t<"bottom pager"ip>r',
427
                'aaSorting': [[1, 'asc']],
372
                'aoColumns': [
428
                'aoColumns': [
429
                    { 'sName': 'checkbox', 'bSortable': false },
373
                    { 'sName': 'title' },
430
                    { 'sName': 'title' },
374
                    { 'sName': 'publicationyear' },
431
                    { 'sName': 'publicationyear' },
375
                    { 'sName': 'publishercode' },
432
                    { 'sName': 'publishercode' },
Lines 385-396 Link Here
385
                    { 'sName': 'itemlost' },
442
                    { 'sName': 'itemlost' },
386
                    { 'sName': 'withdrawn' },
443
                    { 'sName': 'withdrawn' },
387
                    { 'sName': 'issues' },
444
                    { 'sName': 'issues' },
388
                    { 'sName': 'checkbox', 'bSortable': false }
445
                    { 'sName': 'actions', 'bSortable': false }
389
                ],
446
                ],
390
                "sPaginationType": "full_numbers"
447
                "sPaginationType": "full_numbers"
391
            })).columnFilter({
448
            })).columnFilter({
392
                'sPlaceHolder': 'head:after',
449
                'sPlaceHolder': 'head:after',
393
                'aoColumns': [
450
                'aoColumns': [
451
                    null,
394
                    { 'type': 'text' },
452
                    { 'type': 'text' },
395
                    { 'type': 'text' },
453
                    { 'type': 'text' },
396
                    { 'type': 'text' },
454
                    { 'type': 'text' },
Lines 433-438 Link Here
433
                    null
491
                    null
434
                ]
492
                ]
435
            });
493
            });
494
495
            $('#results').on('change', 'input[type="checkbox"]', function() {
496
              var countSelected = $(this).parents('table').find('input:checked').length;
497
              var caret = ' <span class="caret">';
498
              if (countSelected > 0) {
499
                $('#export-button').html(_("Export selected results to") + caret);
500
              } else {
501
                $('#export-button').html(_("Export all results to") + caret);
502
              }
503
            });
436
        }
504
        }
437
        var Sticky;
505
        var Sticky;
438
        $(document).ready(function () {
506
        $(document).ready(function () {
439
- 

Return to bug 18433