Bugzilla – Attachment 125458 Details for
Bug 29002
Add ability to book items ahead of time
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 29002: Add Booking objects and API classes
Bug-29002-Add-Booking-objects-and-API-classes.patch (text/plain), 39.26 KB, created by
Martin Renvoize (ashimema)
on 2021-09-29 15:48:10 UTC
(
hide
)
Description:
Bug 29002: Add Booking objects and API classes
Filename:
MIME Type:
Creator:
Martin Renvoize (ashimema)
Created:
2021-09-29 15:48:10 UTC
Size:
39.26 KB
patch
obsolete
>From ca3cc01cefc11dcdd0882f2c79526cb304959056 Mon Sep 17 00:00:00 2001 >From: Martin Renvoize <martin.renvoize@ptfs-europe.com> >Date: Thu, 16 Sep 2021 09:17:30 +0100 >Subject: [PATCH] Bug 29002: Add Booking objects and API classes > >--- > Koha/Biblio.pm | 107 +++++++ > Koha/Booking.pm | 220 +++++++++++++++ > Koha/Bookings.pm | 59 ++++ > Koha/Exceptions/Booking.pm | 15 + > 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.json | 3 + > api/v1/swagger/definitions/booking.json | 33 +++ > api/v1/swagger/parameters.json | 3 + > api/v1/swagger/parameters/booking.json | 9 + > api/v1/swagger/paths.json | 12 + > api/v1/swagger/paths/biblios.json | 98 +++++++ > api/v1/swagger/paths/bookings.json | 352 ++++++++++++++++++++++++ > api/v1/swagger/paths/items.json | 92 +++++++ > 16 files changed, 1341 insertions(+) > 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.json > create mode 100644 api/v1/swagger/parameters/booking.json > create mode 100644 api/v1/swagger/paths/bookings.json > >diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm >index 26ee7abd96..eda94849c4 100644 >--- a/Koha/Biblio.pm >+++ b/Koha/Biblio.pm >@@ -35,6 +35,7 @@ use Koha::ArticleRequest::Status; > use Koha::ArticleRequests; > use Koha::Biblio::Metadatas; > use Koha::Biblioitems; >+use Koha::Bookings; > use Koha::CirculationRules; > use Koha::Item::Transfer::Limits; > use Koha::Items; >@@ -132,6 +133,98 @@ sub can_article_request { > return q{}; > } > >+=head3 can_by_booked >+ >+ my $bookable = >+ $biblio->can_be_booked( { 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 can_be_booked { >+ 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 }) >@@ -480,6 +573,20 @@ sub biblioitem { > return $self->{_biblioitem}; > } > >+=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..308e3899cd >--- /dev/null >+++ b/Koha/Booking.pm >@@ -0,0 +1,220 @@ >+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 <http://www.gnu.org/licenses>. >+ >+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) = @_; >+ >+ $self->{_biblio} ||= Koha::Biblios->find( $self->biblionumber() ); >+ >+ return $self->{_biblio}; >+} >+ >+=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) = @_; >+ >+ $self->{_item} ||= Koha::Items->find( $self->itemnumber() ); >+ >+ return $self->{_item}; >+} >+ >+=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->itemnumber ) { >+ Koha::Exceptions::Object::FKConstraint->throw( >+ broken_fk => 'itemnumber', >+ value => $self->itemnumber, >+ ) unless ( $self->item ); >+ >+ $self->biblionumber( $self->item->biblionumber ) >+ unless $self->biblionumber; >+ >+ Koha::Exceptions::Object::FKConstraint->throw() >+ unless ( $self->biblionumber == $self->item->biblionumber ); >+ } >+ >+ Koha::Exceptions::Object::FKConstraint->throw( >+ broken_fk => 'biblionumber', >+ value => $self->biblionumber, >+ ) unless ( $self->biblio ); >+ >+ # Throw exception for item level booking clash >+ Koha::Exceptions::Booking::Clash->throw() >+ if $self->itemnumber && !$self->item->can_be_booked( >+ { >+ 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->can_be_booked( >+ { >+ 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 { >+ booking_id => 'booking_id', >+ borrowernumber => 'patron_id', >+ biblionumber => 'biblio_id', >+ itemnumber => 'item_id', >+ start_date => 'start_date', >+ end_date => 'end_date' >+ }; >+} >+ >+=head2 Internal methods >+ >+=head3 _type >+ >+=cut >+ >+sub _type { >+ return 'Booking'; >+} >+ >+=head1 AUTHORS >+ >+Martin Renvoize <martin.renvoize@ptfs-europe.com> >+ >+=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 <http://www.gnu.org/licenses>. >+ >+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 <martin.renvoize@ptfs-europe.com> >+ >+=cut >+ >+1; >diff --git a/Koha/Exceptions/Booking.pm b/Koha/Exceptions/Booking.pm >new file mode 100644 >index 0000000000..9ebae153cb >--- /dev/null >+++ b/Koha/Exceptions/Booking.pm >@@ -0,0 +1,15 @@ >+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 updateing the booking would result in a clash" >+ }, >+); >+ >+1; >diff --git a/Koha/Item.pm b/Koha/Item.pm >index 60d80a5c3e..d8d4c4a05a 100644 >--- a/Koha/Item.pm >+++ b/Koha/Item.pm >@@ -410,6 +410,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 can_be_booked >+ >+ my $bookable = >+ $item->can_be_booked( { 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 can_be_booked { >+ 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 3ddb896e73..dd95d93a37 100644 >--- a/Koha/REST/V1/Biblios.pm >+++ b/Koha/REST/V1/Biblios.pm >@@ -235,6 +235,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 <http://www.gnu.org/licenses>. >+ >+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 1887bce514..fcb06dc04c 100644 >--- a/Koha/REST/V1/Items.pm >+++ b/Koha/REST/V1/Items.pm >@@ -81,6 +81,40 @@ sub get { > }; > } > >+=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.json b/api/v1/swagger/definitions.json >index 402eed6b25..09d380fa61 100644 >--- a/api/v1/swagger/definitions.json >+++ b/api/v1/swagger/definitions.json >@@ -5,6 +5,9 @@ > "basket": { > "$ref": "definitions/basket.json" > }, >+ "booking": { >+ "$ref": "definitions/booking.json" >+ }, > "cashup": { > "$ref": "definitions/cashup.json" > }, >diff --git a/api/v1/swagger/definitions/booking.json b/api/v1/swagger/definitions/booking.json >new file mode 100644 >index 0000000000..f2cc461e1a >--- /dev/null >+++ b/api/v1/swagger/definitions/booking.json >@@ -0,0 +1,33 @@ >+{ >+ "type": "object", >+ "properties": { >+ "booking_id": { >+ "type": "integer", >+ "description": "Internal booking identifier" >+ }, >+ "biblio_id": { >+ "type": "integer", >+ "description": "Internal identifier for the parent bibliographic record" >+ }, >+ "item_id": { >+ "type": [ "integer", "null" ], >+ "description": "Internal item identifier" >+ }, >+ "patron_id": { >+ "type": "integer", >+ "description": "Internal patron identifier" >+ }, >+ "start_date": { >+ "type": "string", >+ "format": "date-time", >+ "description": "Start date and time of this booking" >+ }, >+ "end_date": { >+ "type": "string", >+ "format": "date-time", >+ "description": "Start date and time of this booking" >+ } >+ }, >+ "additionalProperties": false, >+ "required": ["biblio_id", "item_id", "patron_id", "start_date", "end_date"] >+} >diff --git a/api/v1/swagger/parameters.json b/api/v1/swagger/parameters.json >index 95464e1461..3d5cb73328 100644 >--- a/api/v1/swagger/parameters.json >+++ b/api/v1/swagger/parameters.json >@@ -2,6 +2,9 @@ > "biblio_id_pp": { > "$ref": "parameters/biblio.json#/biblio_id_pp" > }, >+ "booking_id_pp": { >+ "$ref": "parameters/booking.json#/booking_id_pp" >+ }, > "advancededitormacro_id_pp": { > "$ref": "parameters/advancededitormacro.json#/advancededitormacro_id_pp" > }, >diff --git a/api/v1/swagger/parameters/booking.json b/api/v1/swagger/parameters/booking.json >new file mode 100644 >index 0000000000..d1433066fc >--- /dev/null >+++ b/api/v1/swagger/parameters/booking.json >@@ -0,0 +1,9 @@ >+{ >+ "booking_id_pp": { >+ "name": "booking_id", >+ "in": "path", >+ "description": "Booking internal identifier", >+ "required": true, >+ "type": "integer" >+ } >+} >diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json >index 23f420cc05..25698b461e 100644 >--- a/api/v1/swagger/paths.json >+++ b/api/v1/swagger/paths.json >@@ -20,12 +20,21 @@ > "/biblios/{biblio_id}": { > "$ref": "paths/biblios.json#/~1biblios~1{biblio_id}" > }, >+ "/biblios/{biblio_id}/bookings": { >+ "$ref": "paths/biblios.json#/~1biblios~1{biblio_id}~1bookings" >+ }, > "/biblios/{biblio_id}/items": { > "$ref": "paths/biblios.json#/~1biblios~1{biblio_id}~1items" > }, > "/biblios/{biblio_id}/pickup_locations": { > "$ref": "paths/biblios.json#/~1biblios~1{biblio_id}~1pickup_locations" > }, >+ "/bookings": { >+ "$ref": "paths/bookings.json#/~1bookings" >+ }, >+ "/bookings/{booking_id}": { >+ "$ref": "paths/bookings.json#/~1bookings~1{booking_id}" >+ }, > "/cash_registers/{cash_register_id}/cashups": { > "$ref": "paths/cash_registers.json#/~1cash_registers~1{cash_register_id}~1cashups" > }, >@@ -83,6 +92,9 @@ > "/items/{item_id}": { > "$ref": "paths/items.json#/~1items~1{item_id}" > }, >+ "/items/{item_id}/bookings": { >+ "$ref": "paths/items.json#/~1items~1{item_id}~1bookings" >+ }, > "/items/{item_id}/pickup_locations": { > "$ref": "paths/items.json#/~1items~1{item_id}~1pickup_locations" > }, >diff --git a/api/v1/swagger/paths/biblios.json b/api/v1/swagger/paths/biblios.json >index f1b494ddb1..beeed7c035 100644 >--- a/api/v1/swagger/paths/biblios.json >+++ b/api/v1/swagger/paths/biblios.json >@@ -132,6 +132,104 @@ > } > } > }, >+ "/biblios/{biblio_id}/bookings": { >+ "get": { >+ "x-mojo-to": "Biblios#get_bookings", >+ "operationId": "getBiblioBookings", >+ "tags": [ >+ "bookings" >+ ], >+ "summary": "Get bookings for a biblio", >+ "parameters": [ >+ { >+ "$ref": "../parameters.json#/biblio_id_pp" >+ }, >+ { >+ "$ref": "../parameters.json#/match" >+ }, >+ { >+ "$ref": "../parameters.json#/order_by" >+ }, >+ { >+ "$ref": "../parameters.json#/page" >+ }, >+ { >+ "$ref": "../parameters.json#/per_page" >+ }, >+ { >+ "$ref": "../parameters.json#/q_param" >+ }, >+ { >+ "$ref": "../parameters.json#/q_body" >+ }, >+ { >+ "$ref": "../parameters.json#/q_header" >+ } >+ ], >+ "consumes": [ >+ "application/json" >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A list of the bookings attached to the record", >+ "schema": { >+ "type": "array", >+ "items": { >+ "$ref": "../definitions.json#/booking" >+ } >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "Biblio not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "406": { >+ "description": "Not acceptable", >+ "schema": { >+ "type": "array", >+ "description": "Accepted content-types", >+ "items": { >+ "type": "string" >+ } >+ } >+ }, >+ "500": { >+ "description": "Internal server error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "circulation": "1" >+ } >+ } >+ } >+ }, > "/biblios/{biblio_id}/items": { > "get": { > "x-mojo-to": "Biblios#get_items", >diff --git a/api/v1/swagger/paths/bookings.json b/api/v1/swagger/paths/bookings.json >new file mode 100644 >index 0000000000..1d92c67e8f >--- /dev/null >+++ b/api/v1/swagger/paths/bookings.json >@@ -0,0 +1,352 @@ >+{ >+ "/bookings": { >+ "get": { >+ "x-mojo-to": "Bookings#list", >+ "operationId": "listBookings", >+ "tags": [ >+ "bookings" >+ ], >+ "summary": "List bookings", >+ "produces": [ >+ "application/json" >+ ], >+ "parameters": [ >+ { >+ "name": "biblio_id", >+ "in": "query", >+ "description": "Case insensative search on booking biblio_id", >+ "required": false, >+ "type": "string" >+ }, >+ { >+ "name": "item_id", >+ "in": "query", >+ "description": "Case insensative search on booking item_id", >+ "required": false, >+ "type": "string" >+ }, >+ { >+ "name": "patron_id", >+ "in": "query", >+ "description": "Case insensative search on booking patron_id", >+ "required": false, >+ "type": "string" >+ }, >+ { >+ "name": "start_date", >+ "in": "query", >+ "description": "Case Insensative search on booking start_date", >+ "required": false, >+ "type": "string" >+ }, >+ { >+ "name": "end_date", >+ "in": "query", >+ "description": "Case Insensative search on booking end_date", >+ "required": false, >+ "type": "string" >+ }, >+ >+ { >+ "$ref": "../parameters.json#/match" >+ }, >+ { >+ "$ref": "../parameters.json#/order_by" >+ }, >+ { >+ "$ref": "../parameters.json#/page" >+ }, >+ { >+ "$ref": "../parameters.json#/per_page" >+ }, >+ { >+ "$ref": "../parameters.json#/q_param" >+ }, >+ { >+ "$ref": "../parameters.json#/q_body" >+ }, >+ { >+ "$ref": "../parameters.json#/q_header" >+ } >+ ], >+ "responses": { >+ "200": { >+ "description": "A list of bookings", >+ "schema": { >+ "type": "array", >+ "items": { >+ "$ref": "../definitions.json#/booking" >+ } >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "catalogue": "1" >+ } >+ } >+ }, >+ "post": { >+ "x-mojo-to": "Bookings#add", >+ "operationId": "addBooking", >+ "tags": [ >+ "bookings" >+ ], >+ "summary": "Add booking", >+ "parameters": [ >+ { >+ "name": "body", >+ "in": "body", >+ "description": "A JSON object containing informations about the new booking", >+ "required": true, >+ "schema": { >+ "$ref": "../definitions.json#/booking" >+ } >+ } >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "201": { >+ "description": "Booking added", >+ "schema": { >+ "$ref": "../definitions.json#/booking" >+ } >+ }, >+ "400": { >+ "description": "Client error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "parameters": "manage_bookings" >+ } >+ } >+ } >+ }, >+ "/bookings/{booking_id}": { >+ "get": { >+ "x-mojo-to": "Bookings#get", >+ "operationId": "getBooking", >+ "tags": [ >+ "bookings" >+ ], >+ "summary": "Get booking", >+ "parameters": [ >+ { >+ "$ref": "../parameters.json#/booking_id_pp" >+ } >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A booking", >+ "schema": { >+ "$ref": "../definitions.json#/booking" >+ } >+ }, >+ "404": { >+ "description": "Booking not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "catalogue": "1" >+ } >+ } >+ }, >+ "put": { >+ "x-mojo-to": "Bookings#update", >+ "operationId": "updateBooking", >+ "tags": [ >+ "bookings" >+ ], >+ "summary": "Update booking", >+ "parameters": [ >+ { >+ "$ref": "../parameters.json#/booking_id_pp" >+ }, >+ { >+ "name": "body", >+ "in": "body", >+ "description": "A booking object", >+ "required": true, >+ "schema": { >+ "$ref": "../definitions.json#/booking" >+ } >+ } >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A booking", >+ "schema": { >+ "$ref": "../definitions.json#/booking" >+ } >+ }, >+ "400": { >+ "description": "Client error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "Booking not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "parameters": "manage_bookings" >+ } >+ } >+ }, >+ "delete": { >+ "x-mojo-to": "Bookings#delete", >+ "operationId": "deleteBooking", >+ "tags": [ >+ "bookings" >+ ], >+ "summary": "Delete booking", >+ "parameters": [ >+ { >+ "$ref": "../parameters.json#/booking_id_pp" >+ } >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "204": { >+ "description": "Booking deleted" >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "Booking not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "parameters": "manage_bookings" >+ } >+ } >+ } >+ } >+} >diff --git a/api/v1/swagger/paths/items.json b/api/v1/swagger/paths/items.json >index 7c18f625ee..7cef274139 100644 >--- a/api/v1/swagger/paths/items.json >+++ b/api/v1/swagger/paths/items.json >@@ -127,6 +127,98 @@ > } > } > }, >+ "/items/{item_id}/bookings": { >+ "get": { >+ "x-mojo-to": "Items#bookings", >+ "operationId": "getItemBookings", >+ "summary": "Get existing bookings for an item", >+ "tags": ["items"], >+ "parameters": [ >+ { >+ "$ref": "../parameters.json#/item_id_pp" >+ }, >+ { >+ "$ref": "../parameters.json#/match" >+ }, >+ { >+ "$ref": "../parameters.json#/order_by" >+ }, >+ { >+ "$ref": "../parameters.json#/page" >+ }, >+ { >+ "$ref": "../parameters.json#/per_page" >+ }, >+ { >+ "$ref": "../parameters.json#/q_param" >+ }, >+ { >+ "$ref": "../parameters.json#/q_body" >+ }, >+ { >+ "$ref": "../parameters.json#/q_header" >+ } >+ ], >+ "consumes": [ >+ "application/json" >+ ], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "Item bookings", >+ "schema": { >+ "type": "array", >+ "items": { >+ "$ref": "../definitions.json#/booking" >+ } >+ } >+ }, >+ "400": { >+ "description": "Missing or wrong parameters", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "Item not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal server error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "circulation": 1 >+ } >+ } >+ } >+ }, > "/items/{item_id}/pickup_locations": { > "get": { > "x-mojo-to": "Items#pickup_locations", >-- >2.20.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 29002
:
125456
|
125457
|
125458
|
125459
|
151209
|
151211
|
151213
|
151216
|
151217
|
151218
|
158357
|
158358
|
160831