From fe879bd966d2d77d536985e48260801c2113e6ec Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Tue, 28 Feb 2017 09:00:07 -0300 Subject: [PATCH] Bug 18120: REST api | Add a 'vendors' endpoint This patch introduces an /acquisitions/vendors endpoint. To test: - Apply the patch - Run: $ sudo koha-shell kohadev k$ prove t/db_dependent/api/v1/acquisitions_vendors.t => SUCCESS: Tests pass - Sign off :-D Sponsored-by: ByWater Solutions Signed-off-by: Matthias Meusburger --- Koha/REST/V1/Acquisitions/Vendors.pm | 197 ++++++++++++++++ Koha/Schema/Result/Aqbookseller.pm | 7 + api/v1/swagger/definitions.json | 6 + api/v1/swagger/definitions/vendor.json | 149 ++++++++++++ api/v1/swagger/parameters.json | 3 + api/v1/swagger/parameters/vendor.json | 9 + api/v1/swagger/paths.json | 6 + api/v1/swagger/paths/acquisitions_vendors.json | 303 +++++++++++++++++++++++++ api/v1/swagger/x-primitives.json | 5 + 9 files changed, 685 insertions(+) create mode 100644 Koha/REST/V1/Acquisitions/Vendors.pm create mode 100644 api/v1/swagger/definitions/vendor.json create mode 100644 api/v1/swagger/parameters/vendor.json create mode 100644 api/v1/swagger/paths/acquisitions_vendors.json diff --git a/Koha/REST/V1/Acquisitions/Vendors.pm b/Koha/REST/V1/Acquisitions/Vendors.pm new file mode 100644 index 0000000000..a8302c8bab --- /dev/null +++ b/Koha/REST/V1/Acquisitions/Vendors.pm @@ -0,0 +1,197 @@ +package Koha::REST::V1::Acquisitions::Vendors; + +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use Koha::Acquisition::Booksellers; + +use Try::Tiny; + +sub list_vendors { + my $c = shift->openapi->valid_input or return; + + my $args = _to_model($c->req->params->to_hash); + my $filter; + + for my $filter_param ( keys %$args ) { + $filter->{$filter_param} = { LIKE => $args->{$filter_param} . "%" } + if $args->{$filter_param}; + } + + my @vendors; + + return try { + @vendors = Koha::Acquisition::Booksellers->search($filter); + @vendors = map { _to_api($_->TO_JSON) } @vendors; + return $c->render( status => 200, + openapi => \@vendors ); + } + catch { + if ( $_->isa('DBIx::Class::Exception') ) { + return $c->render( status => 500, + openapi => { error => $_->{msg} } ); + } + else { + return $c->render( status => 500, + openapi => { error => "Something went wrong, check the logs." } ); + } + }; +} + +sub get_vendor { + my $c = shift->openapi->valid_input or return; + + my $vendor = Koha::Acquisition::Booksellers->find( $c->validation->param('vendor_id') ); + unless ($vendor) { + return $c->render( status => 404, + openapi => { error => "Vendor not found" } ); + } + + return $c->render( status => 200, + openapi => _to_api($vendor->TO_JSON) ); +} + +sub add_vendor { + my $c = shift->openapi->valid_input or return; + + my $vendor = Koha::Acquisition::Bookseller->new( _to_model( $c->validation->param('body') ) ); + + return try { + $vendor->store; + return $c->render( status => 200, + openapi => _to_api($vendor->TO_JSON) ); + } + catch { + if ( $_->isa('DBIx::Class::Exception') ) { + return $c->render( status => 500, + openapi => { error => $_->msg } ); + } + else { + return $c->render( status => 500, + openapi => { error => "Something went wrong, check the logs." } ); + } + }; +} + +sub update_vendor { + my $c = shift->openapi->valid_input or return; + + my $vendor; + + return try { + $vendor = Koha::Acquisition::Booksellers->find( $c->validation->param('vendor_id') ); + $vendor->set( _to_model( $c->validation->param('body') ) ); + $vendor->store(); + return $c->render( status => 200, + openapi => _to_api($vendor->TO_JSON) ); + } + catch { + if ( not defined $vendor ) { + return $c->render( status => 404, + openapi => { error => "Object not found" } ); + } + elsif ( $_->isa('Koha::Exceptions::Object') ) { + return $c->render( status => 500, + openapi => { error => $_->message } ); + } + else { + return $c->render( status => 500, + openapi => { error => "Something went wrong, check the logs." } ); + } + }; + +} + +sub delete_vendor { + my $c = shift->openapi->valid_input or return; + + my $vendor; + + return try { + $vendor = Koha::Acquisition::Booksellers->find( $c->validation->param('vendor_id') ); + $vendor->delete; + return $c->render( status => 200, + openapi => q{} ); + } + catch { + if ( not defined $vendor ) { + return $c->render( status => 404, + openapi => { error => "Object not found" } ); + } + elsif ( $_->isa('DBIx::Class::Exception') ) { + return $c->render( status => 500, + openapi => { error => $_->msg } ); + } + else { + return $c->render( status => 500, + openapi => { error => "Something went wrong, check the logs." } ); + } + }; + +} + +sub _to_api { + + my $vendor = shift; + + #my $vendor = $vendor_param->TO_JSON; + + # Delete unused fields + delete $vendor->{booksellerfax}; + delete $vendor->{bookselleremail}; + delete $vendor->{booksellerurl}; + delete $vendor->{currency}; + delete $vendor->{othersupplier}; + + # Rename changed fields + $vendor->{list_currency} = $vendor->{listprice}; + delete $vendor->{listprice}; + $vendor->{invoice_currency} = $vendor->{invoiceprice}; + delete $vendor->{invoiceprice}; + $vendor->{gst} = $vendor->{gstreg}; + delete $vendor->{gstreg}; + $vendor->{list_includes_gst} = $vendor->{listincgst}; + delete $vendor->{listincgst}; + $vendor->{invoice_includes_gst} = $vendor->{invoiceincgst}; + delete $vendor->{invoiceincgst}; + + return $vendor; +} + +sub _to_model { + my $vendor_param = shift; + + my $vendor = $vendor_param; + + # Rename back + $vendor->{listprice} = $vendor->{list_currency}; + delete $vendor->{list_currency}; + $vendor->{invoiceprice} = $vendor->{invoice_currency}; + delete $vendor->{invoice_currency}; + $vendor->{gstreg} = $vendor->{gst}; + delete $vendor->{gst}; + $vendor->{listincgst} = $vendor->{list_includes_gst}; + delete $vendor->{list_includes_gst}; + $vendor->{invoiceincgst} = $vendor->{invoice_includes_gst}; + delete $vendor->{invoice_includes_gst}; + + return $vendor; +} + +1; diff --git a/Koha/Schema/Result/Aqbookseller.pm b/Koha/Schema/Result/Aqbookseller.pm index e9c2656940..e59b7057e8 100644 --- a/Koha/Schema/Result/Aqbookseller.pm +++ b/Koha/Schema/Result/Aqbookseller.pm @@ -385,6 +385,13 @@ __PACKAGE__->has_many( # Created by DBIx::Class::Schema::Loader v0.07042 @ 2016-09-09 13:43:30 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:b3aUNZsdvNzEuKScGD7ZPQ +__PACKAGE__->add_columns( + '+active' => { is_boolean => 1 }, + '+gstreg' => { is_boolean => 1 }, + '+listincgst' => { is_boolean => 1 }, + '+invoiceincgst' => { is_boolean => 1 }, +); + # You can replace this text with custom code or comments, and it will be preserved on regeneration 1; diff --git a/api/v1/swagger/definitions.json b/api/v1/swagger/definitions.json index 939baa8615..340b9a978b 100644 --- a/api/v1/swagger/definitions.json +++ b/api/v1/swagger/definitions.json @@ -13,5 +13,11 @@ }, "patron": { "$ref": "definitions/patron.json" + }, + "error": { + "$ref": "definitions/error.json" + }, + "vendor": { + "$ref": "definitions/vendor.json" } } diff --git a/api/v1/swagger/definitions/vendor.json b/api/v1/swagger/definitions/vendor.json new file mode 100644 index 0000000000..f24bdde414 --- /dev/null +++ b/api/v1/swagger/definitions/vendor.json @@ -0,0 +1,149 @@ +{ + "type": "object", + "properties": { + "id": { + "$ref": "../x-primitives.json#/vendor_id" + }, + "name": { + "type": [ + "string" + ], + "description": "Vendor name" + }, + "address1": { + "type": [ + "string", + "null" + ], + "description": "Vendor physical address (line 1)" + }, + "address2": { + "type": [ + "string", + "null" + ], + "description": "Vendor physical address (line 2)" + }, + "address3": { + "type": [ + "string", + "null" + ], + "description": "Vendor physical address (line 3)" + }, + "address4": { + "type": [ + "string", + "null" + ], + "description": "Vendor physical address (line 4)" + }, + "phone": { + "type": [ + "string", + "null" + ], + "description": "Vendor phone number" + }, + "fax": { + "type": [ + "string", + "null" + ], + "description": "Vendor fax number" + }, + "accountnumber": { + "type": [ + "string", + "null" + ], + "description": "Vendor account number" + }, + "notes": { + "type": [ + "string", + "null" + ], + "description": "Vendor notes" + }, + "postal": { + "type": [ + "string", + "null" + ], + "description": "Vendor postal address" + }, + "url": { + "type": [ + "string", + "null" + ], + "description": "Vendor web address" + }, + "active": { + "type": [ + "boolean", + "null" + ], + "description": "Is this vendor active" + }, + "list_currency": { + "type": [ + "string", + "null" + ], + "description": "List prices currency" + }, + "invoice_currency": { + "type": [ + "string", + "null" + ], + "description": "Invoice prices currency" + }, + "gst": { + "type": [ + "boolean", + "null" + ], + "description": "Is the library taxed when buying to this vendor" + }, + "list_includes_gst": { + "type": [ + "boolean", + "null" + ], + "description": "List prices include taxes" + }, + "invoice_includes_gst": { + "type": [ + "boolean", + "null" + ], + "description": "Invoice prices include taxes" + }, + "tax_rate": { + "type": [ + "number", + "null" + ], + "description": "Tax rate" + }, + "discount": { + "type": [ + "number", + "null" + ], + "description": "Discount offered on all items ordered from this vendor" + }, + "deliverytime": { + "type": [ + "integer", + "null" + ], + "description": "Vendor expected delivery time (in days)" + } + }, + "additionalProperties": false, + "required": ["name"] +} diff --git a/api/v1/swagger/parameters.json b/api/v1/swagger/parameters.json index eeb156a7b8..b8835d22d1 100644 --- a/api/v1/swagger/parameters.json +++ b/api/v1/swagger/parameters.json @@ -10,5 +10,8 @@ }, "holdIdPathParam": { "$ref": "parameters/hold.json#/holdIdPathParam" + }, + "vendoridPathParam": { + "$ref": "parameters/vendor.json#/vendoridPathParam" } } diff --git a/api/v1/swagger/parameters/vendor.json b/api/v1/swagger/parameters/vendor.json new file mode 100644 index 0000000000..64dbea0f53 --- /dev/null +++ b/api/v1/swagger/parameters/vendor.json @@ -0,0 +1,9 @@ +{ + "vendoridPathParam": { + "name": "vendor_id", + "in": "path", + "description": "Vendor id", + "required": true, + "type": "integer" + } +} diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json index b1fcf40f5e..147e985386 100644 --- a/api/v1/swagger/paths.json +++ b/api/v1/swagger/paths.json @@ -1,4 +1,10 @@ { + "/acquisitions/vendors": { + "$ref": "paths/acquisitions_vendors.json#/~1acquisitions~1vendors" + }, + "/acquisitions/vendors/{vendor_id}": { + "$ref": "paths/acquisitions_vendors.json#/~1acquisitions~1vendors~1{vendor_id}" + }, "/cities": { "$ref": "paths/cities.json#/~1cities" }, diff --git a/api/v1/swagger/paths/acquisitions_vendors.json b/api/v1/swagger/paths/acquisitions_vendors.json new file mode 100644 index 0000000000..a34c72a18d --- /dev/null +++ b/api/v1/swagger/paths/acquisitions_vendors.json @@ -0,0 +1,303 @@ +{ + "/acquisitions/vendors": { + "get": { + "x-mojo-to": "Acquisitions::Vendors#list_vendors", + "operationId": "listVendors", + "tags": ["acquisitions","vendors"], + "produces": [ + "application/json" + ], + "parameters": [{ + "name": "name", + "in": "query", + "description": "Case insensitive search on vendor name", + "required": false, + "type": "string" + }, { + "name": "accountnumber", + "in": "query", + "description": "Case insensitive search on vendor's account number", + "required": false, + "type": "string" + }], + "responses": { + "200": { + "description": "A list of vendors", + "schema": { + "type": "array", + "items": { + "$ref": "../definitions.json#/vendor" + } + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Vendor 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": { + "acquisition": "1" + } + } + }, + "post": { + "x-mojo-to": "Acquisitions::Vendors#add_vendor", + "operationId": "addVendor", + "tags": ["acquisitions","vendors"], + "parameters": [{ + "name": "body", + "in": "body", + "description": "A JSON object representing a vendor", + "required": true, + "schema": { + "$ref": "../definitions.json#/vendor" + } + }], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Vendor added", + "schema": { + "$ref": "../definitions.json#/vendor" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Vendor 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": { + "acquisition": "vendors_manage" + } + } + } + }, + "/acquisitions/vendors/{vendor_id}": { + "get": { + "x-mojo-to": "Acquisitions::Vendors#get_vendor", + "operationId": "getVendor", + "tags": ["acquisitions","vendors"], + "parameters": [{ + "$ref": "../parameters.json#/vendoridPathParam" + }], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A vendor", + "schema": { + "$ref": "../definitions.json#/vendor" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Vendor 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": { + "acquisition": "1" + } + } + }, + "put": { + "x-mojo-to": "Acquisitions::Vendors#update_vendor", + "operationId": "updateVendor", + "tags": ["acquisitions","vendors"], + "parameters": [{ + "$ref": "../parameters.json#/vendoridPathParam" + }, { + "name": "body", + "in": "body", + "description": "A JSON object representing a vendor", + "required": true, + "schema": { + "$ref": "../definitions.json#/vendor" + } + }], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A vendor", + "schema": { + "$ref": "../definitions.json#/vendor" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Vendor 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": { + "acquisition": "1" + } + } + }, + "delete": { + "x-mojo-to": "Acquisitions::Vendors#delete_vendor", + "operationId": "deleteVendor", + "tags": ["acquisitions","vendors"], + "parameters": [{ + "$ref": "../parameters.json#/vendoridPathParam" + }], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Vendor deleted", + "schema": { + "type": "string" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Vendor 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": { + "acquisition": "1" + } + } + } + } +} diff --git a/api/v1/swagger/x-primitives.json b/api/v1/swagger/x-primitives.json index ae4e7395f6..12e5e9de39 100644 --- a/api/v1/swagger/x-primitives.json +++ b/api/v1/swagger/x-primitives.json @@ -39,5 +39,10 @@ "surname": { "type": "string", "description": "patron's last name" + }, + "vendor_id": { + "type": "integer", + "description": "internally assigned vendor identifier", + "readOnly": true } } -- 2.14.1