From 5922d8a03a97f02f64c61b8532756a7c5037b6ba Mon Sep 17 00:00:00 2001 From: Julian Maurice Date: Wed, 8 Dec 2021 19:21:41 +0100 Subject: [PATCH] Bug 29668: Add API route to add a basket Example usage: POST /api/v1/acquisitions/baskets { "vendor_id": 1, "name": "Basket #1", } Test plan: 1. Try requesting this endpoint with your favorite API tool (I recommend https://github.com/frigus02/RESTer) 2. Run `prove t/db_dependent/api/v1/acquisitions_baskets/post.t` --- Koha/Acquisition/Basket.pm | 1 + Koha/REST/V1/Acquisitions/Baskets.pm | 62 +++++++++++++++++ api/v1/swagger/definitions/basket.yaml | 24 +++++-- api/v1/swagger/paths.yaml | 2 + .../swagger/paths/acquisitions_baskets.yaml | 45 ++++++++++++ .../api/v1/acquisitions_baskets/post.t | 68 +++++++++++++++++++ 6 files changed, 196 insertions(+), 6 deletions(-) create mode 100644 Koha/REST/V1/Acquisitions/Baskets.pm create mode 100644 api/v1/swagger/paths/acquisitions_baskets.yaml create mode 100755 t/db_dependent/api/v1/acquisitions_baskets/post.t diff --git a/Koha/Acquisition/Basket.pm b/Koha/Acquisition/Basket.pm index 556fa326b0..732a549b8c 100644 --- a/Koha/Acquisition/Basket.pm +++ b/Koha/Acquisition/Basket.pm @@ -270,6 +270,7 @@ sub to_api_mapping { return { basketno => 'basket_id', basketname => 'name', + note => undef, booksellernote => 'vendor_note', contractnumber => 'contract_id', creationdate => 'creation_date', diff --git a/Koha/REST/V1/Acquisitions/Baskets.pm b/Koha/REST/V1/Acquisitions/Baskets.pm new file mode 100644 index 0000000000..2f793c36e5 --- /dev/null +++ b/Koha/REST/V1/Acquisitions/Baskets.pm @@ -0,0 +1,62 @@ +package Koha::REST::V1::Acquisitions::Baskets; + +# 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::Acquisition::Baskets; + +use Clone qw( clone ); +use Scalar::Util qw( blessed ); +use Try::Tiny qw( catch try ); + +=head1 NAME + +Koha::REST::V1::Acquisitions::Baskets + +=head1 API + +=head2 Methods + +=head3 add + +Controller function that handles adding a new Koha::Acquisition::Basket object + +=cut + +sub add { + my $c = shift->openapi->valid_input or return; + + return try { + my $basket = Koha::Acquisition::Basket->new_from_api( $c->validation->param('body') ); + $basket->store->discard_changes; + + $c->res->headers->location( + $c->req->url->to_string . '/' . $basket->basketno + ); + + return $c->render( + status => 201, + openapi => $basket->to_api + ); + } catch { + $c->unhandled_exception($_); + }; +} + +1; diff --git a/api/v1/swagger/definitions/basket.yaml b/api/v1/swagger/definitions/basket.yaml index 8ab8ff1d69..0bf6c8b87a 100644 --- a/api/v1/swagger/definitions/basket.yaml +++ b/api/v1/swagger/definitions/basket.yaml @@ -5,7 +5,9 @@ properties: type: integer description: Internal identifier for the basket name: - type: string + type: + - string + - "null" description: Basket name internal_note: type: @@ -18,7 +20,9 @@ properties: - "null" description: Vendor note contract_id: - type: integer + type: + - integer + - "null" description: Internal identifier of the linked contract creation_date: type: @@ -32,10 +36,13 @@ properties: - "null" format: date description: The date the basket was closed + closed: + type: boolean + description: Is the basket closed ? vendor_id: type: integer description: Internal identifier for the vendor - authorised_by: + creator_id: type: - integer - "null" @@ -45,12 +52,12 @@ properties: - integer - "null" description: links this basket to its group (aqbasketgroups.id) - delivery_library: + delivery_library_id: type: - string - "null" description: basket delivery place - billing_library: + billing_library_id: type: - string - "null" @@ -64,11 +71,16 @@ properties: type: boolean description: If the orders in this basket are standing create_items: - type: string + type: + - string + - "null" enum: - ordering - receiving - cataloguing + - null description: "When items should be created for orders in this basket (Options: 'ordering', 'receiving', 'cataloguing'. Null means system wide config)" additionalProperties: false +required: + - vendor_id diff --git a/api/v1/swagger/paths.yaml b/api/v1/swagger/paths.yaml index 6908fa8bb1..08d4f87d33 100644 --- a/api/v1/swagger/paths.yaml +++ b/api/v1/swagger/paths.yaml @@ -1,6 +1,8 @@ --- /oauth/token: $ref: paths/oauth.yaml#/~1oauth~1token +"/acquisitions/baskets": + $ref: paths/acquisitions_baskets.yaml#/~1acquisitions~1baskets /acquisitions/orders: $ref: paths/acquisitions_orders.yaml#/~1acquisitions~1orders "/acquisitions/orders/{order_id}": diff --git a/api/v1/swagger/paths/acquisitions_baskets.yaml b/api/v1/swagger/paths/acquisitions_baskets.yaml new file mode 100644 index 0000000000..5c8d0480d2 --- /dev/null +++ b/api/v1/swagger/paths/acquisitions_baskets.yaml @@ -0,0 +1,45 @@ +--- +"/acquisitions/baskets": + post: + x-mojo-to: Acquisitions::Baskets#add + operationId: addBasket + tags: + - baskets + summary: Add basket + consumes: + - application/json + produces: + - application/json + parameters: + - + name: body + in: body + description: A basket + required: true + schema: + $ref: ../definitions.yaml#/basket + responses: + "201": + description: Basket created + schema: + $ref: ../definitions.yaml#/basket + "401": + description: Authentication required + schema: + $ref: ../definitions.yaml#/error + "403": + description: Access forbidden + schema: + $ref: ../definitions.yaml#/error + "500": + description: Internal server error + schema: + $ref: ../definitions.yaml#/error + "503": + description: Under maintenance + schema: + $ref: ../definitions.yaml#/error + x-koha-authorization: + permissions: + acquisition: + - order_manage diff --git a/t/db_dependent/api/v1/acquisitions_baskets/post.t b/t/db_dependent/api/v1/acquisitions_baskets/post.t new file mode 100755 index 0000000000..8a7536d882 --- /dev/null +++ b/t/db_dependent/api/v1/acquisitions_baskets/post.t @@ -0,0 +1,68 @@ +#!/usr/bin/env perl + +use Modern::Perl; + +use Test::More tests => 14; +use Test::Mojo; + +use t::lib::Mocks; +use t::lib::TestBuilder; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); + +my $t = Test::Mojo->new('Koha::REST::V1'); + +$schema->storage->txn_begin; + +my $bookseller = $builder->build_object( + { + class => 'Koha::Acquisition::Booksellers', + } +); +my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } +); +my $password = 'thePassword123'; +$patron->set_password( { password => $password, skip_validation => 1 } ); +my $userid = $patron->userid; + +my $url = "//$userid:$password@/api/v1/acquisitions/baskets"; + +$t->post_ok($url, json => {}) + ->status_is(403); + +$schema->resultset('UserPermission')->create( + { + borrowernumber => $patron->borrowernumber, + module_bit => 11, + code => 'order_manage', + } +); + +$t->post_ok($url, json => {}) + ->status_is(400); + +$t->post_ok($url, json => { vendor_id => $bookseller->id }) + ->status_is(201) + ->json_has('/basket_id') + ->json_is('/vendor_id', $bookseller->id); + +my $basket = { + vendor_id => $bookseller->id, + name => 'Basket #1', + vendor_note => 'Vendor note', +}; +$t->post_ok($url, json => $basket) + ->status_is(201) + ->json_has('/basket_id') + ->json_is('/vendor_id', $basket->{vendor_id}) + ->json_is('/name', $basket->{name}) + ->json_is('/vendor_note', $basket->{vendor_note}); + +$schema->storage->txn_rollback; -- 2.30.2