Bug 31272: Use TT plugins for pickup library and due date in opac-reserve.pl
[koha.git] / catalogue / itemsearch.pl
1 #!/usr/bin/perl
2 # Copyright 2013 BibLibre
3 #
4 # This file is part of Koha
5 #
6 # Koha is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # Koha is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Koha; if not, see <http://www.gnu.org/licenses>.
18
19 use Modern::Perl;
20 use CGI;
21
22 use JSON qw( to_json );
23
24 use C4::Auth qw( get_template_and_user );
25 use C4::Output qw( output_with_http_headers output_html_with_http_headers );
26 use C4::Items qw( SearchItems );
27 use C4::Koha qw( GetAuthorisedValues );
28
29 use Koha::AuthorisedValues;
30 use Koha::Biblios;
31 use Koha::Item::Search::Field qw(GetItemSearchFields);
32 use Koha::ItemTypes;
33 use Koha::Libraries;
34
35 my $cgi = CGI->new;
36 my %params = $cgi->Vars;
37
38 my $format = $cgi->param('format');
39 my $template_name = 'catalogue/itemsearch.tt';
40
41 if (defined $format and $format eq 'json') {
42     $template_name = 'catalogue/itemsearch_json.tt';
43
44     # Map DataTables parameters with 'regular' parameters
45     $cgi->param('rows', scalar $cgi->param('iDisplayLength'));
46     $cgi->param('page', (scalar $cgi->param('iDisplayStart') / scalar $cgi->param('iDisplayLength')) + 1);
47     my @columns = split /,/, scalar $cgi->param('sColumns');
48     $cgi->param('sortby', $columns[ scalar $cgi->param('iSortCol_0') ]);
49     $cgi->param('sortorder', scalar $cgi->param('sSortDir_0'));
50
51     my @f = $cgi->multi_param('f');
52     my @q = $cgi->multi_param('q');
53     push @q, '' if @q == 0;
54     my @op = $cgi->multi_param('op');
55     my @c = $cgi->multi_param('c');
56     my $iColumns = $cgi->param('iColumns');
57     foreach my $i (0 .. ($iColumns - 1)) {
58         my $sSearch = $cgi->param("sSearch_$i");
59         if (defined $sSearch and $sSearch ne '') {
60             my @words = split /\s+/, $sSearch;
61             foreach my $word (@words) {
62                 push @f, $columns[$i];
63                 push @c, 'and';
64
65                 if ( grep { $_ eq $columns[$i] } qw( ccode homebranch holdingbranch location itype notforloan itemlost onloan ) ) {
66                     push @q, "$word";
67                     push @op, '=';
68                 } else {
69                     push @q, "%$word%";
70                     push @op, 'like';
71                 }
72             }
73         }
74     }
75     $cgi->param('f', @f);
76     $cgi->param('q', @q);
77     $cgi->param('op', @op);
78     $cgi->param('c', @c);
79 } elsif (defined $format and $format eq 'csv') {
80     $template_name = 'catalogue/itemsearch_csv.tt';
81
82     # Retrieve all results
83     $cgi->param('rows', 0);
84 } elsif (defined $format and $format eq 'barcodes') {
85     # Retrieve all results
86     $cgi->param('rows', 0);
87 } elsif (defined $format) {
88     die "Unsupported format $format";
89 }
90
91 my ($template, $borrowernumber, $cookie) = get_template_and_user({
92     template_name => $template_name,
93     query => $cgi,
94     type => 'intranet',
95     flagsrequired   => { catalogue => 1 },
96 });
97
98 my $mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.itemlost', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
99 my $itemlost_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : [];
100
101 $mss = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.withdrawn', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
102 my $withdrawn_values = $mss->count ? GetAuthorisedValues($mss->next->authorised_value) : [];
103
104 if ( Koha::MarcSubfieldStructures->search( { frameworkcode => '', kohafield => 'items.new_status' } )->count ) {
105     $template->param( has_new_status => 1 );
106 }
107
108 if ( defined $format ) {
109     # Parameters given, it's a search
110
111     my $filter = {
112         conjunction => 'AND',
113         filters => [],
114     };
115
116     foreach my $p (qw(homebranch holdingbranch location itype ccode issues datelastborrowed notforloan itemlost withdrawn)) {
117         if (my @q = $cgi->multi_param($p)) {
118             if ($q[0] ne '') {
119                 my $f = {
120                     field => $p,
121                     query => \@q,
122                 };
123                 if (my $op = scalar $cgi->param($p . '_op')) {
124                     $f->{operator} = $op;
125                 }
126                 push @{ $filter->{filters} }, $f;
127             }
128         }
129     }
130
131     my @c = $cgi->multi_param('c');
132     my @fields = $cgi->multi_param('f');
133     my @q = $cgi->multi_param('q');
134     my @op = $cgi->multi_param('op');
135
136     my $f;
137     for (my $i = 0; $i < @fields; $i++) {
138         my $field = $fields[$i];
139         my $q = shift @q;
140         my $op = shift @op;
141         if (defined $q and $q ne '') {
142             if (C4::Context->preference("marcflavour") ne "UNIMARC" && $field eq 'publicationyear') {
143                 $field = 'copyrightdate';
144             }
145
146             if ($i == 0) {
147                 $f = {
148                     field => $field,
149                     query => $q,
150                     operator => $op,
151                 };
152             } else {
153                 my $c = shift @c;
154                 $f = {
155                     conjunction => $c,
156                     filters => [
157                         $f, {
158                             field => $field,
159                             query => $q,
160                             operator => $op,
161                         }
162                     ],
163                 };
164             }
165         }
166     }
167     push @{ $filter->{filters} }, $f;
168
169     # Yes/No parameters
170     foreach my $p (qw( damaged new_status )) {
171         my $v = $cgi->param($p) // '';
172         my $f = {
173             field => $p,
174             query => 0,
175         };
176         if ( $p eq 'new_status' ) {
177             $f->{ifnull} = 0;
178         }
179         if ($v eq 'yes') {
180             $f->{operator} = '!=';
181             push @{ $filter->{filters} }, $f;
182         } elsif ($v eq 'no') {
183             $f->{operator} = '=';
184             push @{ $filter->{filters} }, $f;
185         }
186     }
187
188     # null/is not null parameters
189     foreach my $p (qw( onloan )) {
190         my $v = $cgi->param($p) // '';
191         my $f = {
192             field => $p,
193             operator => "is",
194         };
195         if ( $v eq 'IS NOT NULL' ) {
196             $f->{query} = "not null";
197         } elsif ( $v eq 'IS NULL' ) {
198             $f->{query} = "null";
199         }
200         push @{ $filter->{filters} }, $f unless ( $v eq "" );
201     }
202
203     if (my $itemcallnumber_from = scalar $cgi->param('itemcallnumber_from')) {
204         push @{ $filter->{filters} }, {
205             field => 'itemcallnumber',
206             query => $itemcallnumber_from,
207             operator => '>=',
208         };
209     }
210     if (my $itemcallnumber_to = scalar $cgi->param('itemcallnumber_to')) {
211         push @{ $filter->{filters} }, {
212             field => 'itemcallnumber',
213             query => $itemcallnumber_to,
214             operator => '<=',
215         };
216     }
217
218     my $sortby = $cgi->param('sortby') || 'itemnumber';
219     if (C4::Context->preference("marcflavour") ne "UNIMARC" && $sortby eq 'publicationyear') {
220         $sortby = 'copyrightdate';
221     }
222     my $search_params = {
223         rows => scalar $cgi->param('rows') // 20,
224         page => scalar $cgi->param('page') || 1,
225         sortby => $sortby,
226         sortorder => scalar $cgi->param('sortorder') || 'asc',
227     };
228
229     my ($results, $total_rows) = SearchItems($filter, $search_params);
230
231     if ($format eq 'barcodes') {
232         print $cgi->header({
233             type => 'text/plain',
234             attachment => 'barcodes.txt',
235         });
236
237         foreach my $item (@$results) {
238             print $item->{barcode} . "\n";
239         }
240         exit;
241     }
242
243     if ($results) {
244         foreach my $item (@$results) {
245             my $biblio = Koha::Biblios->find( $item->{biblionumber} );
246             $item->{biblio} = $biblio;
247             $item->{biblioitem} = $biblio->biblioitem->unblessed;
248             my $checkout = Koha::Checkouts->find({ itemnumber => $item->{itemnumber} });
249             $item->{checkout} = $checkout;
250         }
251     }
252
253     $template->param(
254         filter => $filter,
255         search_params => $search_params,
256         results => $results,
257         total_rows => $total_rows,
258     );
259
260     if ($format eq 'csv') {
261         print $cgi->header({
262             type => 'text/csv',
263             attachment => 'items.csv',
264         });
265
266         for my $line ( split '\n', $template->output ) {
267             print "$line\n" unless $line =~ m|^\s*$|;
268         }
269     } elsif ($format eq 'json') {
270         $template->param(sEcho => scalar $cgi->param('sEcho'));
271         output_with_http_headers $cgi, $cookie, $template->output, 'json';
272     }
273
274     exit;
275 }
276
277 # Display the search form
278
279 my @branches = map { value => $_->branchcode, label => $_->branchname }, Koha::Libraries->search( {}, { order_by => 'branchname' } )->as_list;
280 my @itemtypes = map { value => $_->itemtype, label => $_->translated_description }, Koha::ItemTypes->search_with_localization->as_list;
281
282 my @ccodes = Koha::AuthorisedValues->get_descriptions_by_koha_field({ kohafield => 'items.ccode' });
283 foreach my $ccode (@ccodes) {
284     $ccode->{value} = $ccode->{authorised_value},
285     $ccode->{label} = $ccode->{lib},
286 }
287
288 my @itemlosts;
289 foreach my $value (@$itemlost_values) {
290     push @itemlosts, {
291         value => $value->{authorised_value},
292         label => $value->{lib},
293     };
294 }
295
296 my @withdrawns;
297 foreach my $value (@$withdrawn_values) {
298     push @withdrawns, {
299         value => $value->{authorised_value},
300         label => $value->{lib},
301     };
302 }
303
304 my @items_search_fields = GetItemSearchFields();
305
306 my $authorised_values = {};
307 foreach my $field (@items_search_fields) {
308     if (my $category = ($field->{authorised_values_category})) {
309         $authorised_values->{$category} = GetAuthorisedValues($category);
310     }
311 }
312
313 $template->param(
314     branches => \@branches,
315     itemtypes => \@itemtypes,
316     ccodes => \@ccodes,
317     itemlosts => \@itemlosts,
318     withdrawns => \@withdrawns,
319     items_search_fields => \@items_search_fields,
320     authorised_values_json => to_json($authorised_values),
321 );
322
323 output_html_with_http_headers $cgi, $cookie, $template->output;