Bug 29464: Make GET /acquisitions/orders honour sorting
[koha-ffzg.git] / Koha / REST / V1 / Acquisitions / Orders.pm
1 package Koha::REST::V1::Acquisitions::Orders;
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18 use Modern::Perl;
19
20 use Mojo::Base 'Mojolicious::Controller';
21
22 use Koha::Acquisition::Orders;
23
24 use Clone qw( clone );
25 use Scalar::Util qw( blessed );
26 use Try::Tiny qw( catch try );
27
28 =head1 NAME
29
30 Koha::REST::V1::Acquisitions::Orders
31
32 =head1 API
33
34 =head2 Methods
35
36 =head3 list
37
38 Controller function that handles listing Koha::Acquisition::Order objects
39
40 =cut
41
42 sub list {
43
44     my $c = shift->openapi->valid_input or return;
45
46     return try {
47
48         my $only_active = delete $c->validation->output->{only_active};
49         my $order_id    = delete $c->validation->output->{order_id};
50
51         my $orders_rs;
52
53         if ( $only_active ) {
54             $orders_rs = Koha::Acquisition::Orders->filter_by_active;
55         }
56         else {
57             $orders_rs = Koha::Acquisition::Orders->new;
58         }
59
60         $orders_rs = $orders_rs->filter_by_id_including_transfers({ ordernumber => $order_id })
61             if $order_id;
62
63         my $args = $c->validation->output;
64         my $attributes = {};
65
66         # Extract reserved params
67         my ( $filtered_params, $reserved_params, $path_params ) = $c->extract_reserved_params($args);
68         # Look for embeds
69         my $embed = $c->stash('koha.embed');
70         my $fixed_embed = clone($embed);
71         if ( exists $fixed_embed->{biblio} ) {
72             # Add biblioitems to prefetch
73             # FIXME remove if we merge biblio + biblioitems
74             $fixed_embed->{biblio}->{children}->{biblioitem} = {};
75             $c->stash('koha.embed', $fixed_embed);
76         }
77
78         # Merge sorting into query attributes
79         $c->dbic_merge_sorting(
80             {
81                 attributes => $attributes,
82                 params     => $reserved_params,
83                 result_set => $orders_rs,
84             }
85         );
86
87         # If no pagination parameters are passed, default
88         $reserved_params->{_per_page} //= C4::Context->preference('RESTdefaultPageSize');
89         $reserved_params->{_page}     //= 1;
90
91         unless ( $reserved_params->{_per_page} == -1 ) {
92             # Merge pagination into query attributes
93             $c->dbic_merge_pagination(
94                 {
95                     filter => $attributes,
96                     params => $reserved_params
97                 }
98             );
99         }
100
101         # Generate prefetches for embedded stuff
102         $c->dbic_merge_prefetch(
103             {
104                 attributes => $attributes,
105                 result_set => $orders_rs
106             }
107         );
108
109         # Call the to_model function by reference, if defined
110         if ( defined $filtered_params ) {
111
112             # Apply the mapping function to the passed params
113             $filtered_params = $orders_rs->attributes_from_api($filtered_params);
114             $filtered_params = $c->build_query_params( $filtered_params, $reserved_params );
115         }
116
117         if ( defined $path_params ) {
118
119             # Apply the mapping function to the passed params
120             $filtered_params //= {};
121             $path_params = $orders_rs->attributes_from_api($path_params);
122             foreach my $param (keys %{$path_params}) {
123                 $filtered_params->{$param} = $path_params->{$param};
124             }
125         }
126
127         if ( defined $reserved_params->{q} || defined $reserved_params->{query} || defined $reserved_params->{'x-koha-query'}) {
128             $filtered_params //={};
129             my @query_params_array;
130             my $query_params;
131
132             # FIXME The following lines are an ugly fix to deal with isbn and ean searches
133             # This must NOT be reused or extended
134             # Instead we need a better and global solution in a Koha::*Biblio method
135             for my $q ( qw( q query x-koha-query ) ) {
136                 next unless $reserved_params->{$q};
137                 for my $f ( qw( isbn ean publisher ) ) {
138                     $reserved_params->{$q} =~ s|"biblio.$f":|"biblio.biblioitem.$f":|g;
139                 }
140                 push @query_params_array, $reserved_params->{$q};
141             }
142
143             if(scalar(@query_params_array) > 1) {
144                 $query_params = {'-and' => \@query_params_array};
145             }
146             else {
147                 $query_params = $query_params_array[0];
148             }
149
150             $filtered_params = $c->merge_q_params( $filtered_params, $query_params, $orders_rs );
151         }
152
153         # Perform search
154         my $orders = $orders_rs->search( $filtered_params, $attributes );
155         my $total  = $orders_rs->search->count;
156
157         $c->add_pagination_headers(
158             {
159                 total      => ($orders->is_paged ? $orders->pager->total_entries : $orders->count),
160                 base_total => $total,
161                 params     => $args,
162             }
163         );
164
165         return $c->render(
166             status  => 200,
167             openapi => $orders->to_api({ embed => $embed })
168         );
169     }
170     catch {
171         $c->unhandled_exception($_);
172     };
173 }
174
175 =head3 get
176
177 Controller function that handles retrieving a single Koha::Acquisition::Order object
178
179 =cut
180
181 sub get {
182     my $c = shift->openapi->valid_input or return;
183
184     my $order = Koha::Acquisition::Orders->find( $c->validation->param('order_id') );
185
186     unless ($order) {
187         return $c->render(
188             status  => 404,
189             openapi => { error => "Order not found" }
190         );
191     }
192
193     return try {
194         my $embed = $c->stash('koha.embed');
195
196         return $c->render(
197             status  => 200,
198             openapi => $order->to_api({ embed => $embed })
199         );
200     }
201     catch {
202         $c->unhandled_exception($_);
203     };
204 }
205
206 =head3 add
207
208 Controller function that handles adding a new Koha::Acquisition::Order object
209
210 =cut
211
212 sub add {
213     my $c = shift->openapi->valid_input or return;
214
215     return try {
216         my $order = Koha::Acquisition::Order->new_from_api( $c->validation->param('body') );
217         $order->store->discard_changes;
218
219         $c->res->headers->location(
220             $c->req->url->to_string . '/' . $order->ordernumber
221         );
222
223         return $c->render(
224             status  => 201,
225             openapi => $order->to_api
226         );
227     }
228     catch {
229         if ( blessed $_ and $_->isa('Koha::Exceptions::Object::DuplicateID') ) {
230             return $c->render(
231                 status  => 409,
232                 openapi => { error => $_->error, conflict => $_->duplicate_id }
233             );
234         }
235
236         $c->unhandled_exception($_);
237     };
238 }
239
240 =head3 update
241
242 Controller function that handles updating a Koha::Acquisition::Order object
243
244 =cut
245
246 sub update {
247     my $c = shift->openapi->valid_input or return;
248
249     my $order = Koha::Acquisition::Orders->find( $c->validation->param('order_id') );
250
251     unless ($order) {
252         return $c->render(
253             status  => 404,
254             openapi => { error => "Order not found" }
255         );
256     }
257
258     return try {
259         $order->set_from_api( $c->validation->param('body') );
260         $order->store()->discard_changes;
261
262         return $c->render(
263             status  => 200,
264             openapi => $order->to_api
265         );
266     }
267     catch {
268         $c->unhandled_exception($_);
269     };
270 }
271
272 =head3 delete
273
274 Controller function that handles deleting a Koha::Patron object
275
276 =cut
277
278 sub delete {
279     my $c = shift->openapi->valid_input or return;
280
281     my $order = Koha::Acquisition::Orders->find( $c->validation->param('order_id') );
282
283     unless ($order) {
284         return $c->render(
285             status  => 404,
286             openapi => { error => 'Order not found' }
287         );
288     }
289
290     return try {
291
292         $order->delete;
293
294         return $c->render(
295             status  => 204,
296             openapi => q{}
297         );
298     }
299     catch {
300         $c->unhandled_exception($_);
301     };
302 }
303
304 1;