API v1 orders endpoints
This commit is contained in:
parent
7d5155bef6
commit
127ae83f04
9 changed files with 165 additions and 10 deletions
19
app/controllers/api/v1/orders_controller.rb
Normal file
19
app/controllers/api/v1/orders_controller.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
class Api::V1::OrdersController < Api::V1::BaseController
|
||||||
|
include Concerns::CollectionScope
|
||||||
|
|
||||||
|
before_action ->{ doorkeeper_authorize! 'orders:read', 'orders:write' }
|
||||||
|
|
||||||
|
def index
|
||||||
|
render_collection search_scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render json: scope.find(params.require(:id))
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def scope
|
||||||
|
Order.includes(:supplier)
|
||||||
|
end
|
||||||
|
end
|
|
@ -53,14 +53,19 @@ module Concerns::AuthApi
|
||||||
end
|
end
|
||||||
|
|
||||||
case scope_parts.first
|
case scope_parts.first
|
||||||
when 'user' then true # access to the current user's own profile
|
when 'user' then return true # access to the current user's own profile
|
||||||
when 'config' then current_user.role_admin?
|
when 'config' then return current_user.role_admin?
|
||||||
when 'users' then current_user.role_admin?
|
when 'users' then return current_user.role_admin?
|
||||||
when 'workgroups' then current_user.role_admin?
|
when 'workgroups' then return current_user.role_admin?
|
||||||
when 'suppliers' then current_user.role_suppliers?
|
when 'suppliers' then return current_user.role_suppliers?
|
||||||
when 'group_orders' then current_user.role_orders?
|
when 'group_orders' then return current_user.role_orders?
|
||||||
when 'finance' then current_user.role_finance?
|
when 'finance' then return current_user.role_finance?
|
||||||
# please note that offline_access does not belong here, since it is not used for permission checking
|
# please note that offline_access does not belong here, since it is not used for permission checking
|
||||||
end
|
end
|
||||||
|
|
||||||
|
case scope
|
||||||
|
when 'orders:read' then return true
|
||||||
|
when 'orders:write' then return current_user.role_orders?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,6 +51,14 @@ class Order < ApplicationRecord
|
||||||
include DateTimeAttributeValidate
|
include DateTimeAttributeValidate
|
||||||
date_time_attribute :starts, :boxfill, :ends
|
date_time_attribute :starts, :boxfill, :ends
|
||||||
|
|
||||||
|
def self.ransackable_attributes(auth_object = nil)
|
||||||
|
%w(id state supplier_id starts boxfill ends pickup)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.ransackable_associations(auth_object = nil)
|
||||||
|
%w(supplier articles order_articles)
|
||||||
|
end
|
||||||
|
|
||||||
def stockit?
|
def stockit?
|
||||||
supplier_id.nil?
|
supplier_id.nil?
|
||||||
end
|
end
|
||||||
|
@ -111,11 +119,11 @@ class Order < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def boxfill?
|
def boxfill?
|
||||||
FoodsoftConfig[:use_boxfill] && open? && boxfill.present? && boxfill < Time.now
|
!!FoodsoftConfig[:use_boxfill] && open? && boxfill.present? && boxfill < Time.now
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_boxfill_useful?
|
def is_boxfill_useful?
|
||||||
FoodsoftConfig[:use_boxfill] && supplier.try(:has_tolerance?)
|
!!FoodsoftConfig[:use_boxfill] && !!supplier.try(:has_tolerance?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def expired?
|
def expired?
|
||||||
|
|
|
@ -23,6 +23,14 @@ class Supplier < ApplicationRecord
|
||||||
scope :undeleted, -> { where(deleted_at: nil) }
|
scope :undeleted, -> { where(deleted_at: nil) }
|
||||||
scope :having_articles, -> { where(id: Article.undeleted.select(:supplier_id).distinct) }
|
scope :having_articles, -> { where(id: Article.undeleted.select(:supplier_id).distinct) }
|
||||||
|
|
||||||
|
def self.ransackable_attributes(auth_object = nil)
|
||||||
|
%w(id name)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.ransackable_associations(auth_object = nil)
|
||||||
|
%w(articles stock_articles orders)
|
||||||
|
end
|
||||||
|
|
||||||
# sync all articles with the external database
|
# sync all articles with the external database
|
||||||
# returns an array with articles(and prices), which should be updated (to use in a form)
|
# returns an array with articles(and prices), which should be updated (to use in a form)
|
||||||
# also returns an array with outlisted_articles, which should be deleted
|
# also returns an array with outlisted_articles, which should be deleted
|
||||||
|
|
11
app/serializers/order_serializer.rb
Normal file
11
app/serializers/order_serializer.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class OrderSerializer < ActiveModel::Serializer
|
||||||
|
attributes :id, :name, :starts, :ends, :boxfill, :pickup, :is_open, :is_boxfill
|
||||||
|
|
||||||
|
def is_open
|
||||||
|
object.open?
|
||||||
|
end
|
||||||
|
|
||||||
|
def is_boxfill
|
||||||
|
object.boxfill?
|
||||||
|
end
|
||||||
|
end
|
|
@ -49,10 +49,11 @@ Doorkeeper.configure do
|
||||||
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
|
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
|
||||||
|
|
||||||
# default is a collection of read-only scopes
|
# default is a collection of read-only scopes
|
||||||
default_scopes 'config:user', 'finance:user', 'user:read'
|
default_scopes 'config:user', 'finance:user', 'user:read', 'orders:read'
|
||||||
|
|
||||||
optional_scopes 'config:read', 'config:write',
|
optional_scopes 'config:read', 'config:write',
|
||||||
'finance:read', 'finance:write',
|
'finance:read', 'finance:write',
|
||||||
|
'orders:write',
|
||||||
'user:write',
|
'user:write',
|
||||||
'offline_access'
|
'offline_access'
|
||||||
|
|
||||||
|
|
|
@ -271,6 +271,7 @@ Rails.application.routes.draw do
|
||||||
resources :financial_transaction_classes, only: [:index, :show]
|
resources :financial_transaction_classes, only: [:index, :show]
|
||||||
resources :financial_transaction_types, only: [:index, :show]
|
resources :financial_transaction_types, only: [:index, :show]
|
||||||
resources :financial_transactions, only: [:index, :show]
|
resources :financial_transactions, only: [:index, :show]
|
||||||
|
resources :orders, only: [:index, :show]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -179,6 +179,65 @@ paths:
|
||||||
$ref: '#/definitions/Error404'
|
$ref: '#/definitions/Error404'
|
||||||
security:
|
security:
|
||||||
- foodsoft_auth: ['finance:read', 'finance:write']
|
- foodsoft_auth: ['finance:read', 'finance:write']
|
||||||
|
/orders:
|
||||||
|
get:
|
||||||
|
summary: orders
|
||||||
|
tags:
|
||||||
|
- 2. Orders
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/parameters/page'
|
||||||
|
- $ref: '#/parameters/per_page'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
orders:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/Order'
|
||||||
|
meta:
|
||||||
|
$ref: '#/definitions/Meta'
|
||||||
|
401:
|
||||||
|
description: not logged-in
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error401'
|
||||||
|
403:
|
||||||
|
description: missing scope or no permission
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error403'
|
||||||
|
security:
|
||||||
|
- foodsoft_auth: ['orders:read', 'orders:write']
|
||||||
|
/orders/{id}:
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/parameters/idInUrl'
|
||||||
|
get:
|
||||||
|
summary: find order by id
|
||||||
|
tags:
|
||||||
|
- 2. Order
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
order:
|
||||||
|
$ref: '#/definitions/Order'
|
||||||
|
401:
|
||||||
|
description: not logged-in
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error401'
|
||||||
|
403:
|
||||||
|
description: missing scope or no permission
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error403'
|
||||||
|
404:
|
||||||
|
description: not found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/Error404'
|
||||||
|
security:
|
||||||
|
- foodsoft_auth: ['orders:read', 'orders:write']
|
||||||
|
|
||||||
/financial_transaction_classes:
|
/financial_transaction_classes:
|
||||||
get:
|
get:
|
||||||
|
@ -436,6 +495,37 @@ definitions:
|
||||||
description: name of the class of the transaction
|
description: name of the class of the transaction
|
||||||
required: ['id', 'name', 'financial_transaction_class_id', 'financial_transaction_class_name']
|
required: ['id', 'name', 'financial_transaction_class_id', 'financial_transaction_class_name']
|
||||||
|
|
||||||
|
Order:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: name of the order's supplier (or stock)
|
||||||
|
starts:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
description: when the order was opened
|
||||||
|
ends:
|
||||||
|
type: ['string', 'null']
|
||||||
|
format: date-time
|
||||||
|
description: when the order will close or was closed
|
||||||
|
boxfill:
|
||||||
|
type: ['string', 'null']
|
||||||
|
format: date-time
|
||||||
|
description: when the order will enter or entered the boxfill phase
|
||||||
|
pickup:
|
||||||
|
type: ['string', 'null']
|
||||||
|
format: date
|
||||||
|
description: pickup date
|
||||||
|
is_open:
|
||||||
|
type: boolean
|
||||||
|
description: if the order is currently open or not
|
||||||
|
is_boxfill:
|
||||||
|
type: boolean
|
||||||
|
description: if the order is currently in the boxfill phase or not
|
||||||
|
|
||||||
Navigation:
|
Navigation:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
|
|
|
@ -113,6 +113,18 @@ describe 'API v1', type: :apivore, order: :defined do
|
||||||
it_handles_invalid_token(:get, '/financial_transaction_types')
|
it_handles_invalid_token(:get, '/financial_transaction_types')
|
||||||
it_handles_invalid_token(:get, '/financial_transaction_types/{id}', ->{ api_auth({'id' => tpy_1.id }) })
|
it_handles_invalid_token(:get, '/financial_transaction_types/{id}', ->{ api_auth({'id' => tpy_1.id }) })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'orders' do
|
||||||
|
let(:api_scopes) { ['orders:read'] }
|
||||||
|
let!(:order) { create :order }
|
||||||
|
|
||||||
|
it { is_expected.to validate(:get, '/orders', 200, api_auth) }
|
||||||
|
it { is_expected.to validate(:get, '/orders/{id}', 200, api_auth({'id' => order.id})) }
|
||||||
|
it { is_expected.to validate(:get, '/orders/{id}', 404, api_auth({'id' => Order.last.id + 1})) }
|
||||||
|
|
||||||
|
it_handles_invalid_token_and_scope(:get, '/orders')
|
||||||
|
it_handles_invalid_token_and_scope(:get, '/orders/{id}', ->{ api_auth({'id' => order.id}) })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# needs to be last context so it is always run at the end
|
# needs to be last context so it is always run at the end
|
||||||
|
|
Loading…
Reference in a new issue