1 package Koha::REST::V1::Items;
3 # This file is part of Koha.
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.
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.
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>.
20 use Mojo::Base 'Mojolicious::Controller';
22 use C4::Circulation qw( barcodedecode );
26 use List::MoreUtils qw( any );
27 use Try::Tiny qw( catch try );
31 Koha::REST::V1::Items - Koha REST API for handling items (V1)
41 Controller function that handles listing Koha::Item objects
46 my $c = shift->openapi->valid_input or return;
49 my $items_set = Koha::Items->new;
50 my $items = $c->objects->search( $items_set );
57 $c->unhandled_exception($_);
63 Controller function that handles listing Koha::Item objects available to the opac
68 my $c = shift->openapi->valid_input or return;
71 my $patron = $c->stash('koha.user');
74 Koha::Items->filter_by_visible_in_opac( { patron => $patron } );
75 my $items = $c->objects->search($items_set);
83 $c->unhandled_exception($_);
89 Controller function that handles retrieving a single Koha::Item
94 my $c = shift->openapi->valid_input or return;
97 my $items_rs = Koha::Items->new;
98 my $item = $c->objects->find($items_rs, $c->param('item_id'));
102 openapi => { error => 'Item not found'}
105 return $c->render( status => 200, openapi => $item );
108 $c->unhandled_exception($_);
114 Controller function that handles deleting a single Koha::Item
119 my $c = shift->openapi->valid_input or return;
122 my $item = Koha::Items->find($c->param('item_id'));
126 openapi => { error => 'Item not found'}
130 my $safe_to_delete = $item->safe_to_delete;
132 if ( !$safe_to_delete ) {
134 # Pick the first error, if any
135 my ( $error ) = grep { $_->type eq 'error' } @{ $safe_to_delete->messages };
138 Koha::Exception->throw('Koha::Item->safe_to_delete returned false but carried no error message');
142 book_on_loan => { code => 'checked_out', description => 'The item is checked out' },
143 book_reserved => { code => 'found_hold', description => 'Waiting or in-transit hold for the item' },
144 last_item_for_hold => { code => 'last_item_for_hold', description => 'The item is the last one on a record on which a biblio-level hold is placed' },
145 linked_analytics => { code => 'linked_analytics', description => 'The item has linked analytic records' },
146 not_same_branch => { code => 'not_same_branch', description => 'The item is blocked by independent branches' },
149 if ( any { $error->message eq $_ } keys %{$errors} ) {
151 my $code = $error->message;
156 error => $errors->{ $code }->{description},
157 error_code => $errors->{ $code }->{code},
161 Koha::Exception->throw( 'Koha::Patron->safe_to_delete carried an unexpected message: ' . $error->message );
173 $c->unhandled_exception($_);
179 Controller function that handles retrieving item's bookings
184 my $c = shift->openapi->valid_input or return;
186 my $item = Koha::Items->find( { itemnumber => $c->param('item_id') }, { prefetch => ['bookings'] } );
191 openapi => { error => "Object not found." }
197 my $bookings_rs = $item->bookings;
198 my $bookings = $c->objects->search($bookings_rs);
204 $c->unhandled_exception($_);
208 =head3 pickup_locations
210 Method that returns the possible pickup_locations for a given item
211 used for building the dropdown selector
215 sub pickup_locations {
216 my $c = shift->openapi->valid_input or return;
218 my $item_id = $c->param('item_id');
219 my $item = Koha::Items->find( $item_id );
224 openapi => { error => "Item not found" }
228 my $patron_id = $c->param('patron_id');
229 my $patron = Koha::Patrons->find( $patron_id );
231 $c->req->params->remove('patron_id');
236 openapi => { error => "Patron not found" }
242 my $pl_set = $item->pickup_locations( { patron => $patron } );
245 if ( C4::Context->preference('AllowHoldPolicyOverride') ) {
247 my $libraries_rs = Koha::Libraries->search( { pickup_location => 1 } );
248 my $libraries = $c->objects->search($libraries_rs);
252 $library->{needs_override} = (
253 any { $_->branchcode eq $library->{library_id} }
254 @{ $pl_set->as_list }
263 my $pickup_locations = $c->objects->search($pl_set);
264 @response = map { $_->{needs_override} = Mojo::JSON->false; $_; } @{$pickup_locations};
269 openapi => \@response
273 $c->unhandled_exception($_);
279 Controller function that handles bundled_items Koha::Item objects
284 my $c = shift->openapi->valid_input or return;
286 my $item_id = $c->param('item_id');
287 my $item = Koha::Items->find( $item_id );
292 openapi => { error => "Item not found" }
297 my $items_set = $item->bundle_items;
298 my $items = $c->objects->search( $items_set );
305 $c->unhandled_exception($_);
311 Controller function that handles adding items to this bundle
316 my $c = shift->openapi->valid_input or return;
318 my $item_id = $c->param('item_id');
319 my $item = Koha::Items->find( $item_id );
324 openapi => { error => "Item not found" }
328 my $body = $c->req->json;
330 my $bundle_item_id = $body->{'external_id'};
331 $bundle_item_id = barcodedecode($bundle_item_id);
332 my $bundle_item = Koha::Items->find( { barcode => $bundle_item_id } );
334 unless ($bundle_item) {
337 openapi => { error => "Bundle item not found" }
343 force_checkin => $body->{force_checkin},
344 ignore_holds => $body->{ignore_holds},
347 my $link = $item->add_to_bundle($bundle_item, $options);
350 openapi => $bundle_item
354 if ( ref($_) eq 'Koha::Exceptions::Object::DuplicateID' ) {
358 error => 'Item is already bundled',
359 error_code => 'already_bundled',
360 key => $_->duplicate_id
364 elsif ( ref($_) eq 'Koha::Exceptions::Item::Bundle::BundleIsCheckedOut' ) {
368 error => 'Bundle is checked out',
369 error_code => 'bundle_checked_out'
372 } elsif ( ref($_) eq 'Koha::Exceptions::Item::Bundle::ItemIsCheckedOut' ) {
376 error => 'Item is checked out',
377 error_code => 'checked_out'
381 elsif ( ref($_) eq 'Koha::Exceptions::Checkin::FailedCheckin' ) {
385 error => 'Item cannot be checked in',
386 error_code => 'failed_checkin'
390 elsif ( ref($_) eq 'Koha::Exceptions::Item::Bundle::ItemHasHolds' ) {
394 error => 'Item is reserved',
395 error_code => 'reserved'
399 elsif ( ref($_) eq 'Koha::Exceptions::Item::Bundle::IsBundle' ) {
403 error => 'Bundles cannot be nested',
404 error_code => 'failed_nesting'
409 $c->unhandled_exception($_);
414 =head3 remove_from_bundle
416 Controller function that handles removing items from this bundle
420 sub remove_from_bundle {
421 my $c = shift->openapi->valid_input or return;
423 my $item_id = $c->param('item_id');
424 my $item = Koha::Items->find( $item_id );
429 openapi => { error => "Item not found" }
433 my $bundle_item_id = $c->param('bundled_item_id');
434 $bundle_item_id = barcodedecode($bundle_item_id);
435 my $bundle_item = Koha::Items->find( { itemnumber => $bundle_item_id } );
437 unless ($bundle_item) {
440 openapi => { error => "Bundle item not found" }
445 $bundle_item->remove_from_bundle;
451 if ( ref($_) eq 'Koha::Exceptions::Item::Bundle::BundleIsCheckedOut' ) {
455 error => 'Bundle is checked out',
456 error_code => 'bundle_checked_out'
460 $c->unhandled_exception($_);