API v1 orders endpoints

This commit is contained in:
wvengen 2018-10-13 16:16:44 +02:00 committed by wvengen
parent 7d5155bef6
commit 127ae83f04
9 changed files with 165 additions and 10 deletions

View 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

View File

@ -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

View File

@ -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?

View File

@ -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

View 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

View File

@ -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'

View File

@ -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

View File

@ -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:

View File

@ -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