Bug 29408: Add JSDoc documentation for kohaTable function
[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 ) ) {
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     if (my $itemcallnumber_from = scalar $cgi->param('itemcallnumber_from')) {
189         push @{ $filter->{filters} }, {
190             field => 'itemcallnumber',
191             query => $itemcallnumber_from,
192             operator => '>=',
193         };
194     }
195     if (my $itemcallnumber_to = scalar $cgi->param('itemcallnumber_to')) {
196         push @{ $filter->{filters} }, {
197             field => 'itemcallnumber',
198             query => $itemcallnumber_to,
199             operator => '<=',
200         };
201     }
202
203     my $sortby = $cgi->param('sortby') || 'itemnumber';
204     if (C4::Context->preference("marcflavour") ne "UNIMARC" && $sortby eq 'publicationyear') {
205         $sortby = 'copyrightdate';
206     }
207     my $search_params = {
208         rows => scalar $cgi->param('rows') // 20,
209         page => scalar $cgi->param('page') || 1,
210         sortby => $sortby,
211         sortorder => scalar $cgi->param('sortorder') || 'asc',
212     };
213
214     my ($results, $total_rows) = SearchItems($filter, $search_params);
215
216     if ($format eq 'barcodes') {
217         print $cgi->header({
218             type => 'text/plain',
219             attachment => 'barcodes.txt',
220         });
221
222         foreach my $item (@$results) {
223             print $item->{barcode} . "\n";
224         }
225         exit;
226     }
227
228     if ($results) {
229         foreach my $item (@$results) {
230             my $biblio = Koha::Biblios->find( $item->{biblionumber} );
231             $item->{biblio} = $biblio;
232             $item->{biblioitem} = $biblio->biblioitem->unblessed;
233         }
234     }
235
236     $template->param(
237         filter => $filter,
238         search_params => $search_params,
239         results => $results,
240         total_rows => $total_rows,
241     );
242
243     if ($format eq 'csv') {
244         print $cgi->header({
245             type => 'text/csv',
246             attachment => 'items.csv',
247         });
248
249         for my $line ( split '\n', $template->output ) {
250             print "$line\n" unless $line =~ m|^\s*$|;
251         }
252     } elsif ($format eq 'json') {
253         $template->param(sEcho => scalar $cgi->param('sEcho'));
254         output_with_http_headers $cgi, $cookie, $template->output, 'json';
255     }
256
257     exit;
258 }
259
260 # Display the search form
261
262 my @branches = map { value => $_->branchcode, label => $_->branchname }, Koha::Libraries->search( {}, { order_by => 'branchname' } );
263 my @itemtypes;
264 foreach my $itemtype ( Koha::ItemTypes->search_with_localization ) {
265     push @itemtypes, {
266         value => $itemtype->itemtype,
267         label => $itemtype->translated_description,
268     };
269 }
270
271 my @ccodes = Koha::AuthorisedValues->get_descriptions_by_koha_field({ kohafield => 'items.ccode' });
272 foreach my $ccode (@ccodes) {
273     $ccode->{value} = $ccode->{authorised_value},
274     $ccode->{label} = $ccode->{lib},
275 }
276
277 my @itemlosts;
278 foreach my $value (@$itemlost_values) {
279     push @itemlosts, {
280         value => $value->{authorised_value},
281         label => $value->{lib},
282     };
283 }
284
285 my @withdrawns;
286 foreach my $value (@$withdrawn_values) {
287     push @withdrawns, {
288         value => $value->{authorised_value},
289         label => $value->{lib},
290     };
291 }
292
293 my @items_search_fields = GetItemSearchFields();
294
295 my $authorised_values = {};
296 foreach my $field (@items_search_fields) {
297     if (my $category = ($field->{authorised_values_category})) {
298         $authorised_values->{$category} = GetAuthorisedValues($category);
299     }
300 }
301
302 $template->param(
303     branches => \@branches,
304     itemtypes => \@itemtypes,
305     ccodes => \@ccodes,
306     itemlosts => \@itemlosts,
307     withdrawns => \@withdrawns,
308     items_search_fields => \@items_search_fields,
309     authorised_values_json => to_json($authorised_values),
310 );
311
312 output_html_with_http_headers $cgi, $cookie, $template->output;