From e8d52195475350b286f980364430648499ec16dd Mon Sep 17 00:00:00 2001 From: Martin Renvoize Date: Thu, 16 Sep 2021 09:17:30 +0100 Subject: [PATCH] Bug 29002: Add bookings objects and API classes This patch adds new Koha::Object based classes for bookings logic and adds API controllers to expose the new bookings data via the REST API's. Signed-off-by: Martin Renvoize Signed-off-by: Janet McGowan Signed-off-by: Caroline Cyr La Rose Signed-off-by: Laurence Rault Signed-off-by: Kyle M Hall Signed-off-by: Tomas Cohen Arazi --- Koha/Biblio.pm | 107 +++++++++++ Koha/Booking.pm | 212 +++++++++++++++++++++ Koha/Bookings.pm | 59 ++++++ Koha/Exceptions/Booking.pm | 13 ++ Koha/Item.pm | 105 +++++++++++ Koha/REST/V1/Biblios.pm | 34 ++++ Koha/REST/V1/Bookings.pm | 165 +++++++++++++++++ Koha/REST/V1/Items.pm | 34 ++++ api/v1/swagger/definitions/booking.yaml | 45 +++++ api/v1/swagger/parameters/booking.yaml | 6 + api/v1/swagger/paths/biblios.yaml | 68 +++++++ api/v1/swagger/paths/bookings.yaml | 235 ++++++++++++++++++++++++ api/v1/swagger/paths/items.yaml | 54 ++++++ api/v1/swagger/swagger.yaml | 46 +++-- 14 files changed, 1168 insertions(+), 15 deletions(-) create mode 100644 Koha/Booking.pm create mode 100644 Koha/Bookings.pm create mode 100644 Koha/Exceptions/Booking.pm create mode 100644 Koha/REST/V1/Bookings.pm create mode 100644 api/v1/swagger/definitions/booking.yaml create mode 100644 api/v1/swagger/parameters/booking.yaml create mode 100644 api/v1/swagger/paths/bookings.yaml diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index 406031fb9f..814cba7f92 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -37,6 +37,7 @@ use Koha::Biblio::Metadata::Extractor; use Koha::Biblio::ItemGroups; use Koha::Biblioitems; use Koha::Cache::Memory::Lite; +use Koha::Bookings; use Koha::Checkouts; use Koha::CirculationRules; use Koha::Exceptions; @@ -217,6 +218,98 @@ sub can_article_request { return q{}; } +=head3 check_booking + + my $bookable = + $biblio->check_booking( { start_date => $datetime, end_date => $datetime, [ booking_id => $booking_id ] } ); + +Returns a boolean denoting whether the passed booking can be made without clashing. + +Optionally, you may pass a booking id to exclude from the checks; This is helpful when you are updating an existing booking. + +=cut + +sub check_booking { + my ( $self, $params ) = @_; + + my $start_date = dt_from_string( $params->{start_date} ); + my $end_date = dt_from_string( $params->{end_date} ); + my $booking_id = $params->{booking_id}; + + my $bookable_items = $self->items; + my $total_bookable = $bookable_items->count; + + my $dtf = Koha::Database->new->schema->storage->datetime_parser; + my $existing_bookings = $self->bookings( + [ + start_date => { + '-between' => [ + $dtf->format_datetime($start_date), + $dtf->format_datetime($end_date) + ] + }, + end_date => { + '-between' => [ + $dtf->format_datetime($start_date), + $dtf->format_datetime($end_date) + ] + }, + { + start_date => { '<' => $dtf->format_datetime($start_date) }, + end_date => { '>' => $dtf->format_datetime($end_date) } + } + ] + ); + + my $booked_count = + defined($booking_id) + ? $existing_bookings->search( { booking_id => { '!=' => $booking_id } } ) + ->count + : $existing_bookings->count; + return ( ( $total_bookable - $booked_count ) > 0 ) ? 1 : 0; +} + +=head3 place_booking + + my $booking = $biblio->place_booking( + { + patron => $patron, + start_date => $datetime, + end_date => $datetime + } + ); + +Add a booking for this item for the dates passed. + +Returns the Koha::Booking object or throws an exception if the item cannot be booked for the given dates. + +=cut + +sub place_booking { + my ( $self, $params ) = @_; + + # check for mandatory params + my @mandatory = ( 'start_date', 'end_date', 'patron' ); + for my $param (@mandatory) { + unless ( defined( $params->{$param} ) ) { + Koha::Exceptions::MissingParameter->throw( + error => "The $param parameter is mandatory" ); + } + } + my $patron = $params->{patron}; + + # New booking object + my $booking = Koha::Booking->new( + { + start_date => $params->{start_date}, + end_date => $params->{end_date}, + borrowernumber => $patron->borrowernumber, + biblionumber => $self->biblionumber + } + )->store(); + return $booking; +} + =head3 can_be_transferred $biblio->can_be_transferred({ to => $to_library, from => $from_library }) @@ -604,6 +697,20 @@ sub biblioitem { return Koha::Biblioitems->find( { biblionumber => $self->biblionumber } ); } +=head3 bookings + + my $bookings = $item->bookings(); + +Returns the bookings attached to this biblio. + +=cut + +sub bookings { + my ( $self, $params ) = @_; + my $bookings_rs = $self->_result->bookings->search($params); + return Koha::Bookings->_new_from_dbic( $bookings_rs ); +} + =head3 suggestions my $suggestions = $self->suggestions diff --git a/Koha/Booking.pm b/Koha/Booking.pm new file mode 100644 index 0000000000..bb8ff26b30 --- /dev/null +++ b/Koha/Booking.pm @@ -0,0 +1,212 @@ +package Koha::Booking; + +# Copyright PTFS Europe 2021 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Koha::Exceptions::Booking; +use Koha::DateUtils qw( dt_from_string ); + +use base qw(Koha::Object); + +=head1 NAME + +Koha::Booking - Koha Booking object class + +=head1 API + +=head2 Class methods + +=head3 biblio + +Returns the related Koha::Biblio object for this booking + +=cut + +sub biblio { + my ($self) = @_; + + my $biblio_rs = $self->_result->biblio; + return Koha::Biblio->_new_from_dbic($biblio_rs); +} + +=head3 patron + +Returns the related Koha::Patron object for this booking + +=cut + +sub patron { + my ($self) = @_; + + my $patron_rs = $self->_result->patron; + return Koha::Patron->_new_from_dbic($patron_rs); +} + +=head3 item + +Returns the related Koha::Item object for this Booking + +=cut + +sub item { + my ($self) = @_; + + my $item_rs = $self->_result->item; + return unless $item_rs; + return Koha::Item->_new_from_dbic($item_rs); +} + +=head3 store + +Booking specific store method to catch booking clashes + +=cut + +sub store { + my ($self) = @_; + + $self->_result->result_source->schema->txn_do( + sub { + if ( $self->item_id ) { + Koha::Exceptions::Object::FKConstraint->throw( + broken_fk => 'item_id', + value => $self->item_id, + ) unless ( $self->item ); + + $self->biblio_id( $self->item->biblionumber ) + unless $self->biblio_id; + + Koha::Exceptions::Object::FKConstraint->throw() + unless ( $self->biblio_id == $self->item->biblionumber ); + } + + Koha::Exceptions::Object::FKConstraint->throw( + broken_fk => 'biblio_id', + value => $self->biblio_id, + ) unless ( $self->biblio ); + + # Throw exception for item level booking clash + Koha::Exceptions::Booking::Clash->throw() + if $self->item_id && !$self->item->check_booking( + { + start_date => $self->start_date, + end_date => $self->end_date, + booking_id => $self->in_storage ? $self->booking_id : undef + } + ); + + # Throw exception for biblio level booking clash + Koha::Exceptions::Booking::Clash->throw() + if !$self->biblio->check_booking( + { + start_date => $self->start_date, + end_date => $self->end_date, + booking_id => $self->in_storage ? $self->booking_id : undef + } + ); + + $self = $self->SUPER::store; + } + ); + + return $self; +} + +=head3 intersects + + my $intersects = $booking1->intersects($booking2); + +Returns a boolean denoting whether booking1 interfers/overlaps/clashes with booking2. + +=cut + +sub intersects { + my ( $self, $comp ) = @_; + + # Start date of comparison booking is after end date of this booking. + return 0 + if ( + DateTime->compare( + dt_from_string( $comp->start_date ), + dt_from_string( $self->end_date ) + ) >= 0 + ); + + # End date of comparison booking is before start date of this booking. + return 0 + if ( + DateTime->compare( + dt_from_string( $comp->end_date ), + dt_from_string( $self->start_date ) + ) <= 0 + ); + + # Bookings must overlap + return 1; +} + +=head3 get_items_that_can_fill + + my $items = $bookings->get_items_that_can_fill(); + +Return the list of items that can fulfill this booking. + +Items that are not: + + in transit + lost + withdrawn + not for loan + not already booked + +=cut + +sub get_items_that_can_fill { + my ($self) = @_; + return; +} + +=head3 to_api_mapping + +This method returns the mapping for representing a Koha::Booking object +on the API. + +=cut + +sub to_api_mapping { + return {}; +} + +=head2 Internal methods + +=head3 _type + +=cut + +sub _type { + return 'Booking'; +} + +=head1 AUTHORS + +Martin Renvoize + +=cut + +1; diff --git a/Koha/Bookings.pm b/Koha/Bookings.pm new file mode 100644 index 0000000000..44bc032b02 --- /dev/null +++ b/Koha/Bookings.pm @@ -0,0 +1,59 @@ +package Koha::Bookings; + +# Copyright PTFS Europe 2021 +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Koha::Database; +use Koha::Booking; + +use base qw(Koha::Objects); + +=head1 NAME + +Koha::Bookings - Koha Booking object set class + +=head1 API + +=head2 Class Methods + +=cut + +=head3 type + +=cut + +sub _type { + return 'Booking'; +} + +=head3 object_class + +=cut + +sub object_class { + return 'Koha::Booking'; +} + +=head1 AUTHOR + +Martin Renvoize + +=cut + +1; diff --git a/Koha/Exceptions/Booking.pm b/Koha/Exceptions/Booking.pm new file mode 100644 index 0000000000..79e5b6ad8c --- /dev/null +++ b/Koha/Exceptions/Booking.pm @@ -0,0 +1,13 @@ +package Koha::Exceptions::Booking; + +use Modern::Perl; + +use Exception::Class ( + 'Koha::Exceptions::Booking' => { description => "Something went wrong!" }, + 'Koha::Exceptions::Booking::Clash' => { + isa => 'Koha::Exceptions::Booking', + description => "Adding or updating the booking would result in a clash" + }, +); + +1; diff --git a/Koha/Item.pm b/Koha/Item.pm index 5bcc917afa..fe72b43292 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -512,6 +512,111 @@ sub holds { return Koha::Holds->_new_from_dbic( $holds_rs ); } +=head3 bookings + + my $bookings = $item->bookings(); + +Returns the bookings attached to this item. + +=cut + +sub bookings { + my ( $self, $params ) = @_; + my $bookings_rs = $self->_result->bookings->search($params); + return Koha::Bookings->_new_from_dbic( $bookings_rs ); +} + +=head3 check_booking + + my $bookable = + $item->check_booking( { start_date => $datetime, end_date => $datetime, [ booking_id => $booking_id ] } ); + +Returns a boolean denoting whether the passed booking can be made without clashing. + +Optionally, you may pass a booking id to exclude from the checks; This is helpful when you are updating an existing booking. + +=cut + +sub check_booking { + my ($self, $params) = @_; + + my $start_date = dt_from_string( $params->{start_date} ); + my $end_date = dt_from_string( $params->{end_date} ); + my $booking_id = $params->{booking_id}; + + my $dtf = Koha::Database->new->schema->storage->datetime_parser; + my $existing_bookings = $self->bookings( + [ + start_date => { + '-between' => [ + $dtf->format_datetime($start_date), + $dtf->format_datetime($end_date) + ] + }, + end_date => { + '-between' => [ + $dtf->format_datetime($start_date), + $dtf->format_datetime($end_date) + ] + }, + { + start_date => { '<' => $dtf->format_datetime($start_date) }, + end_date => { '>' => $dtf->format_datetime($end_date) } + } + ] + ); + + my $bookings_count = + defined($booking_id) + ? $existing_bookings->search( { booking_id => { '!=' => $booking_id } } ) + ->count + : $existing_bookings->count; + + return $bookings_count ? 0 : 1; +} + +=head3 place_booking + + my $booking = $item->place_booking( + { + patron => $patron, + start_date => $datetime, + end_date => $datetime + } + ); + +Add a booking for this item for the dates passed. + +Returns the Koha::Booking object or throws an exception if the item cannot be booked for the given dates. + +=cut + +sub place_booking { + my ( $self, $params ) = @_; + + # check for mandatory params + my @mandatory = ( 'start_date', 'end_date', 'patron' ); + for my $param (@mandatory) { + unless ( defined( $params->{$param} ) ) { + Koha::Exceptions::MissingParameter->throw( + error => "The $param parameter is mandatory" ); + } + } + my $patron = $params->{patron}; + + # New booking object + my $booking = Koha::Booking->new( + { + start_date => $params->{start_date}, + end_date => $params->{end_date}, + borrowernumber => $patron->borrowernumber, + biblionumber => $self->biblionumber, + itemnumber => $self->itemnumber, + } + )->store(); + return $booking; +} + =head3 request_transfer my $transfer = $item->request_transfer( diff --git a/Koha/REST/V1/Biblios.pm b/Koha/REST/V1/Biblios.pm index eef084bc2c..057eb74f53 100644 --- a/Koha/REST/V1/Biblios.pm +++ b/Koha/REST/V1/Biblios.pm @@ -246,6 +246,40 @@ sub get_public { }; } +=head3 get_bookings + +Controller function that handles retrieving biblio's bookings + +=cut + +sub get_bookings { + my $c = shift->openapi->valid_input or return; + + my $biblio = Koha::Biblios->find( { biblionumber => $c->validation->param('biblio_id') }, { prefetch => ['bookings'] } ); + + unless ( $biblio ) { + return $c->render( + status => 404, + openapi => { + error => "Object not found." + } + ); + } + + return try { + + my $bookings_rs = $biblio->bookings; + my $bookings = $c->objects->search( $bookings_rs ); + return $c->render( + status => 200, + openapi => $bookings + ); + } + catch { + $c->unhandled_exception($_); + }; +} + =head3 get_items Controller function that handles retrieving biblio's items diff --git a/Koha/REST/V1/Bookings.pm b/Koha/REST/V1/Bookings.pm new file mode 100644 index 0000000000..cc1ad4a97c --- /dev/null +++ b/Koha/REST/V1/Bookings.pm @@ -0,0 +1,165 @@ +package Koha::REST::V1::Bookings; + +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# Koha is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Koha; if not, see . + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use Koha::Bookings; + +use Try::Tiny qw( catch try ); + +=head1 API + +=head2 Methods + +=head3 list + +Controller function that handles retrieving a list of bookings + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + + return try { + my $bookings_set = Koha::Bookings->new; + my $bookings = $c->objects->search($bookings_set); + return $c->render( status => 200, openapi => $bookings ); + } + catch { + $c->unhandled_exception($_); + }; + +} + +=head3 get + +Controller function that handles retrieving a single booking + +=cut + +sub get { + my $c = shift->openapi->valid_input or return; + + return try { + my $booking = + Koha::Bookings->find( $c->validation->param('booking_id') ); + unless ($booking) { + return $c->render( + status => 404, + openapi => { error => "Booking not found" } + ); + } + + return $c->render( status => 200, openapi => $booking->to_api ); + } + catch { + $c->unhandled_exception($_); + } +} + +=head3 add + +Controller function that handles adding a new booking + +=cut + +sub add { + my $c = shift->openapi->valid_input or return; + + return try { + my $booking = + Koha::Booking->new_from_api( $c->validation->param('body') ); + $booking->store; + $c->res->headers->location( + $c->req->url->to_string . '/' . $booking->booking_id ); + return $c->render( + status => 201, + openapi => $booking->to_api + ); + } + catch { + if ( blessed $_ and $_->isa('Koha::Exceptions::Booking::Clash') ) { + return $c->render( + status => 400, + openapi => { error => "Booking would conflict" } + ); + } + + return $c->unhandled_exception($_); + }; +} + +=head3 update + +Controller function that handles updating an existing booking + +=cut + +sub update { + my $c = shift->openapi->valid_input or return; + + my $booking = Koha::Bookings->find( $c->validation->param('booking_id') ); + + if ( not defined $booking ) { + return $c->render( + status => 404, + openapi => { error => "Object not found" } + ); + } + + return try { + $booking->set_from_api( $c->validation->param('body') ); + $booking->store(); + return $c->render( status => 200, openapi => $booking->to_api ); + } + catch { + $c->unhandled_exception($_); + }; +} + +=head3 delete + +Controller function that handles removing an existing booking + +=cut + +sub delete { + my $c = shift->openapi->valid_input or return; + + my $booking = Koha::Bookings->find( $c->validation->param('booking_id') ); + if ( not defined $booking ) { + return $c->render( + status => 404, + openapi => { error => "Object not found" } + ); + } + + return try { + $booking->delete; + return $c->render( + status => 204, + openapi => q{} + ); + } + catch { + $c->unhandled_exception($_); + }; +} + +1; diff --git a/Koha/REST/V1/Items.pm b/Koha/REST/V1/Items.pm index 3079135286..795f11ace5 100644 --- a/Koha/REST/V1/Items.pm +++ b/Koha/REST/V1/Items.pm @@ -174,6 +174,40 @@ sub delete { }; } +=head3 get_bookings + +Controller function that handles retrieving item's bookings + +=cut + +sub get_bookings { + my $c = shift->openapi->valid_input or return; + + my $item = Koha::Items->find( { itemnumber => $c->validation->param('item_id') }, { prefetch => ['bookings'] } ); + + unless ( $item ) { + return $c->render( + status => 404, + openapi => { + error => "Object not found." + } + ); + } + + return try { + + my $bookings_rs = $item->bookings; + my $bookings = $c->objects->search( $bookings_rs ); + return $c->render( + status => 200, + openapi => $bookings + ); + } + catch { + $c->unhandled_exception($_); + }; +} + =head3 pickup_locations Method that returns the possible pickup_locations for a given item diff --git a/api/v1/swagger/definitions/booking.yaml b/api/v1/swagger/definitions/booking.yaml new file mode 100644 index 0000000000..23393a60ff --- /dev/null +++ b/api/v1/swagger/definitions/booking.yaml @@ -0,0 +1,45 @@ +--- +additionalProperties: false +properties: + biblio_id: + description: Internal identifier for the parent bibliographic record + type: integer + biblio: + description: Embedable biblio representation + type: object + booking_id: + description: Internal booking identifier + type: integer + end_date: + description: Start date and time of this booking + format: date-time + type: string + item_id: + description: Internal item identifier + type: + - integer + - "null" + item: + description: Embedable item representation + type: + - object + - "null" + patron_id: + description: Internal patron identifier + type: integer + patron: + description: Embedable patron representation + type: + - object + - "null" + start_date: + description: Start date and time of this booking + format: date-time + type: string +required: + - biblio_id + - item_id + - patron_id + - start_date + - end_date +type: object diff --git a/api/v1/swagger/parameters/booking.yaml b/api/v1/swagger/parameters/booking.yaml new file mode 100644 index 0000000000..a4273fd880 --- /dev/null +++ b/api/v1/swagger/parameters/booking.yaml @@ -0,0 +1,6 @@ +booking_id_pp: + name: booking_id + in: path + description: Booking internal identifier + required: true + type: integer diff --git a/api/v1/swagger/paths/biblios.yaml b/api/v1/swagger/paths/biblios.yaml index d250237b68..c1f9872274 100644 --- a/api/v1/swagger/paths/biblios.yaml +++ b/api/v1/swagger/paths/biblios.yaml @@ -274,6 +274,74 @@ x-koha-authorization: permissions: editcatalogue: edit_catalogue +"/biblios/{biblio_id}/bookings": + get: + x-mojo-to: Biblios#get_bookings + operationId: getBiblioBookings + tags: + - bookings + summary: Get bookings for a biblio + parameters: + - $ref: "../swagger.yaml#/parameters/biblio_id_pp" + - $ref: "../swagger.yaml#/parameters/match" + - $ref: "../swagger.yaml#/parameters/order_by" + - $ref: "../swagger.yaml#/parameters/page" + - $ref: "../swagger.yaml#/parameters/per_page" + - $ref: "../swagger.yaml#/parameters/q_param" + - $ref: "../swagger.yaml#/parameters/q_body" + - $ref: "../swagger.yaml#/parameters/q_header" + - name: x-koha-embed + in: header + required: false + description: Embed list sent as a request header + type: array + items: + type: string + enum: + - item + - patron + collectionFormat: csv + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: A list of the bookings attached to the record + schema: + type: array + items: + $ref: ../swagger.yaml#/definitions/booking + "401": + description: Authentication required + schema: + $ref: ../swagger.yaml#/definitions/error + "403": + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + "404": + description: Biblio not found + schema: + $ref: ../swagger.yaml#/definitions/error + "406": + description: Not acceptable + schema: + type: array + description: Accepted content-types + items: + type: string + "500": + description: Internal server error + schema: + $ref: ../swagger.yaml#/definitions/error + "503": + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + x-koha-authorization: + permissions: + circulation: "1" "/biblios/{biblio_id}/checkouts": get: x-mojo-to: Biblios#get_checkouts diff --git a/api/v1/swagger/paths/bookings.yaml b/api/v1/swagger/paths/bookings.yaml new file mode 100644 index 0000000000..90903d9d9d --- /dev/null +++ b/api/v1/swagger/paths/bookings.yaml @@ -0,0 +1,235 @@ +--- +/bookings: + get: + x-mojo-to: Bookings#list + operationId: listBookings + parameters: + - description: Case insensative search on booking biblio_id + in: query + name: biblio_id + required: false + type: string + - description: Case insensative search on booking item_id + in: query + name: item_id + required: false + type: string + - description: Case insensative search on booking patron_id + in: query + name: patron_id + required: false + type: string + - description: Case Insensative search on booking start_date + in: query + name: start_date + required: false + type: string + - description: Case Insensative search on booking end_date + in: query + name: end_date + required: false + type: string + - $ref: "../swagger.yaml#/parameters/match" + - $ref: "../swagger.yaml#/parameters/order_by" + - $ref: "../swagger.yaml#/parameters/page" + - $ref: "../swagger.yaml#/parameters/per_page" + - $ref: "../swagger.yaml#/parameters/q_param" + - $ref: "../swagger.yaml#/parameters/q_body" + - $ref: "../swagger.yaml#/parameters/q_header" + - name: x-koha-embed + in: header + required: false + description: Embed list sent as a request header + type: array + items: + type: string + enum: + - biblio + - item + - patron + collectionFormat: csv + produces: + - application/json + responses: + 200: + description: A list of bookings + schema: + items: + $ref: ../swagger.yaml#/definitions/booking + type: array + 403: + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + 500: + description: Internal error + schema: + $ref: ../swagger.yaml#/definitions/error + 503: + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + summary: List bookings + tags: + - bookings + x-koha-authorization: + permissions: + catalogue: 1 + post: + operationId: addBooking + parameters: + - description: A JSON object containing informations about the new booking + in: body + name: body + required: true + schema: + $ref: ../swagger.yaml#/definitions/booking + produces: + - application/json + responses: + 201: + description: Booking added + schema: + $ref: ../swagger.yaml#/definitions/booking + 400: + description: Client error + schema: + $ref: ../swagger.yaml#/definitions/error + 401: + description: Authentication required + schema: + $ref: ../swagger.yaml#/definitions/error + 403: + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + 500: + description: Internal error + schema: + $ref: ../swagger.yaml#/definitions/error + 503: + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + summary: Add booking + tags: + - bookings + x-koha-authorization: + permissions: + parameters: manage_bookings + x-mojo-to: Bookings#add +'/bookings/{booking_id}': + delete: + operationId: deleteBooking + parameters: + - $ref: "../swagger.yaml#/parameters/booking_id_pp" + produces: + - application/json + responses: + 204: + description: Booking deleted + 401: + description: Authentication required + schema: + $ref: ../swagger.yaml#/definitions/error + 403: + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + 404: + description: Booking not found + schema: + $ref: ../swagger.yaml#/definitions/error + 500: + description: Internal error + schema: + $ref: ../swagger.yaml#/definitions/error + 503: + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + summary: Delete booking + tags: + - bookings + x-koha-authorization: + permissions: + parameters: manage_bookings + x-mojo-to: Bookings#delete + get: + operationId: getBooking + parameters: + - $ref: "../swagger.yaml#/parameters/booking_id_pp" + produces: + - application/json + responses: + 200: + description: A booking + schema: + $ref: ../swagger.yaml#/definitions/booking + 404: + description: Booking not found + schema: + $ref: ../swagger.yaml#/definitions/error + 500: + description: Internal error + schema: + $ref: ../swagger.yaml#/definitions/error + 503: + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + summary: Get booking + tags: + - bookings + x-koha-authorization: + permissions: + catalogue: 1 + x-mojo-to: Bookings#get + put: + operationId: updateBooking + parameters: + - $ref: "../swagger.yaml#/parameters/booking_id_pp" + - description: A booking object + in: body + name: body + required: true + schema: + $ref: ../swagger.yaml#/definitions/booking + produces: + - application/json + responses: + 200: + description: A booking + schema: + $ref: ../swagger.yaml#/definitions/booking + 400: + description: Client error + schema: + $ref: ../swagger.yaml#/definitions/error + 401: + description: Authentication required + schema: + $ref: ../swagger.yaml#/definitions/error + 403: + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + 404: + description: Booking not found + schema: + $ref: ../swagger.yaml#/definitions/error + 500: + description: Internal error + schema: + $ref: ../swagger.yaml#/definitions/error + 503: + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + summary: Update booking + tags: + - bookings + x-koha-authorization: + permissions: + parameters: manage_bookings + x-mojo-to: Bookings#update diff --git a/api/v1/swagger/paths/items.yaml b/api/v1/swagger/paths/items.yaml index aade91c2ea..2e7ce1e68c 100644 --- a/api/v1/swagger/paths/items.yaml +++ b/api/v1/swagger/paths/items.yaml @@ -336,6 +336,60 @@ x-koha-authorization: permissions: catalogue: 1 +/items/{item_id}/bookings: + get: + x-mojo-to: Items#bookings + operationId: getItemBookings + summary: Get existing bookings for an item + tags: + - items + parameters: + - $ref: "../swagger.yaml#/parameters/item_id_pp" + - $ref: "../swagger.yaml#/parameters/match" + - $ref: "../swagger.yaml#/parameters/order_by" + - $ref: "../swagger.yaml#/parameters/page" + - $ref: "../swagger.yaml#/parameters/per_page" + - $ref: "../swagger.yaml#/parameters/q_param" + - $ref: "../swagger.yaml#/parameters/q_body" + - $ref: "../swagger.yaml#/parameters/q_header" + consumes: + - application/json + produces: + - application/json + responses: + "200": + description: Item bookings + schema: + type: array + items: + $ref: ../swagger.yaml#/definitions/booking + "400": + description: Missing or wrong parameters + schema: + $ref: ../swagger.yaml#/definitions/error + "401": + description: Authentication required + schema: + $ref: ../swagger.yaml#/definitions/error + "403": + description: Access forbidden + schema: + $ref: ../swagger.yaml#/definitions/error + "404": + description: Item not found + schema: + $ref: ../swagger.yaml#/definitions/error + "500": + description: Internal server error + schema: + $ref: ../swagger.yaml#/definitions/error + "503": + description: Under maintenance + schema: + $ref: ../swagger.yaml#/definitions/error + x-koha-authorization: + permissions: + circulation: 1 "/items/{item_id}/pickup_locations": get: x-mojo-to: Items#pickup_locations diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 3d056e2700..204591d6dc 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -13,11 +13,13 @@ definitions: authorised_value_category: $ref: ./definitions/authorised_value_category.yaml identity_provider: - "$ref": ./definitions/identity_provider.yaml + $ref: ./definitions/identity_provider.yaml identity_provider_domain: - "$ref": ./definitions/identity_provider_domain.yaml + $ref: ./definitions/identity_provider_domain.yaml basket: $ref: ./definitions/basket.yaml + booking: + $ref: ./definitions/booking.yaml bundle_link: $ref: ./definitions/bundle_link.yaml cashup: @@ -160,13 +162,13 @@ definitions: $ref: ./definitions/vendor_issue.yaml paths: /acquisitions/baskets/managers: - $ref: paths/acquisitions_baskets.yaml#/~1acquisitions~1baskets~1managers + $ref: ./paths/acquisitions_baskets.yaml#/~1acquisitions~1baskets~1managers /acquisitions/funds: $ref: ./paths/acquisitions_funds.yaml#/~1acquisitions~1funds /acquisitions/funds/owners: - $ref: paths/acquisitions_funds.yaml#/~1acquisitions~1funds~1owners + $ref: ./paths/acquisitions_funds.yaml#/~1acquisitions~1funds~1owners /acquisitions/funds/users: - $ref: paths/acquisitions_funds.yaml#/~1acquisitions~1funds~1users + $ref: ./paths/acquisitions_funds.yaml#/~1acquisitions~1funds~1users /acquisitions/orders: $ref: ./paths/acquisitions_orders.yaml#/~1acquisitions~1orders "/acquisitions/orders/{order_id}": @@ -181,6 +183,10 @@ paths: $ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros /advanced_editor/macros/shared: $ref: ./paths/advancededitormacros.yaml#/~1advanced_editor~1macros~1shared + /bookings: + $ref: ./paths/bookings.yaml#/~1bookings + "/bookings/{booking_id}": + $ref: ./paths/bookings.yaml#/~1bookings~1{booking_id} /search_filters: $ref: ./paths/search_filters.yaml#/~1search_filters "/search_filters/{search_filter_id}": @@ -192,33 +198,35 @@ paths: "/article_requests/{article_request_id}": $ref: "./paths/article_requests.yaml#/~1article_requests~1{article_request_id}" /auth/otp/token_delivery: - $ref: paths/auth.yaml#/~1auth~1otp~1token_delivery + $ref: "./paths/auth.yaml#/~1auth~1otp~1token_delivery" "/auth/password/validation": $ref: "./paths/auth.yaml#/~1auth~1password~1validation" /auth/two-factor/registration: - $ref: paths/auth.yaml#/~1auth~1two-factor~1registration + $ref: ./paths/auth.yaml#/~1auth~1two-factor~1registration /auth/two-factor/registration/verification: - $ref: paths/auth.yaml#/~1auth~1two-factor~1registration~1verification + $ref: ./paths/auth.yaml#/~1auth~1two-factor~1registration~1verification /auth/identity_providers: - $ref: paths/auth.yaml#/~1auth~1identity_providers + $ref: ./paths/auth.yaml#/~1auth~1identity_providers "/auth/identity_providers/{identity_provider_id}": - $ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id} + $ref: ./paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id} "/auth/identity_providers/{identity_provider_id}/domains": - $ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains + $ref: ./paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains "/auth/identity_providers/{identity_provider_id}/domains/{identity_provider_domain_id}": - $ref: paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains~1{identity_provider_domain_id} + $ref: ./paths/auth.yaml#/~1auth~1identity_providers~1{identity_provider_id}~1domains~1{identity_provider_domain_id} /authorised_value_categories: - $ref: paths/authorised_value_categories.yaml#/~1authorised_value_categories + $ref: ./paths/authorised_value_categories.yaml#/~1authorised_value_categories "/authorised_value_categories/{authorised_value_category_name}/authorised_values": $ref: "./paths/authorised_values.yaml#/~1authorised_value_categories~1{authorised_value_category_name}~1authorised_values" "/authorities": $ref: paths/authorities.yaml#/~1authorities "/authorities/{authority_id}": - $ref: paths/authorities.yaml#/~1authorities~1{authority_id} + $ref: "./paths/authorities.yaml#/~1authorities~1{authority_id}" "/biblios": $ref: "./paths/biblios.yaml#/~1biblios" "/biblios/{biblio_id}": $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}" + "/biblios/{biblio_id}/bookings": + $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}~1bookings" "/biblios/{biblio_id}/checkouts": $ref: "./paths/biblios.yaml#/~1biblios~1{biblio_id}~1checkouts" "/biblios/{biblio_id}/items": @@ -375,6 +383,8 @@ paths: $ref: ./paths/items.yaml#/~1items "/items/{item_id}": $ref: "./paths/items.yaml#/~1items~1{item_id}" + "/items/{item_id}/bookings": + $ref: "./paths/items.yaml#/~1items~1{item_id}~1bookings" "/items/{item_id}/bundled_items": $ref: ./paths/items.yaml#/~1items~1{item_id}~1bundled_items "/items/{item_id}/bundled_items/{bundled_item_id}": @@ -484,7 +494,7 @@ paths: "/suggestions/{suggestion_id}": $ref: "./paths/suggestions.yaml#/~1suggestions~1{suggestion_id}" /suggestions/managers: - $ref: paths/suggestions.yaml#/~1suggestions~1managers + $ref: "./paths/suggestions.yaml#/~1suggestions~1managers" "/tickets": $ref: "./paths/tickets.yaml#/~1tickets" "/tickets/{ticket_id}": @@ -534,6 +544,12 @@ parameters: in: header required: false type: string + booking_id_pp: + description: Booking identifier + in: path + name: booking_id + required: true + type: integer framework_id_header: description: Framework id. Use when content type is not application/json name: x-framework-id -- 2.39.5