mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
Merge branch 'dev' into us78
This commit is contained in:
commit
dafeb668e0
@ -16,3 +16,5 @@ Style/EmptyElse:
|
|||||||
EnforcedStyle: empty
|
EnforcedStyle: empty
|
||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
EnforcedStyle: compact
|
EnforcedStyle: compact
|
||||||
|
Style/AndOr:
|
||||||
|
EnforcedStyle: conditionals
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# API Controller for resources of Invoice and Avoir
|
||||||
class API::InvoicesController < API::ApiController
|
class API::InvoicesController < API::ApiController
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :set_invoice, only: [:show, :download]
|
before_action :set_invoice, only: %i[show download]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize Invoice
|
authorize Invoice
|
||||||
@invoices = Invoice.includes(:avoir, :invoiced, invoice_items: [:subscription, :invoice_item], user: [:profile, :trainings]).all.order('reference DESC')
|
@invoices = Invoice.includes(
|
||||||
|
:avoir, :invoiced, invoice_items: %i[subscription invoice_item], user: %i[profile trainings]
|
||||||
|
).all.order('reference DESC')
|
||||||
end
|
end
|
||||||
|
|
||||||
def download
|
def download
|
||||||
authorize @invoice
|
authorize @invoice
|
||||||
send_file File.join(Rails.root, @invoice.file), :type => 'application/pdf', :disposition => 'attachment'
|
send_file File.join(Rails.root, @invoice.file), type: 'application/pdf', disposition: 'attachment'
|
||||||
end
|
end
|
||||||
|
|
||||||
def list
|
def list
|
||||||
@ -17,44 +22,18 @@ class API::InvoicesController < API::ApiController
|
|||||||
|
|
||||||
p = params.require(:query).permit(:number, :customer, :date, :order_by, :page, :size)
|
p = params.require(:query).permit(:number, :customer, :date, :order_by, :page, :size)
|
||||||
|
|
||||||
unless p[:page].is_a? Integer
|
render json: { error: 'page must be an integer' }, status: :unprocessable_entity and return unless p[:page].is_a? Integer
|
||||||
render json: {error: 'page must be an integer'}, status: :unprocessable_entity
|
|
||||||
end
|
|
||||||
|
|
||||||
unless p[:size].is_a? Integer
|
render json: { error: 'size must be an integer' }, status: :unprocessable_entity and return unless p[:size].is_a? Integer
|
||||||
render json: {error: 'size must be an integer'}, status: :unprocessable_entity
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
direction = (p[:order_by][0] == '-' ? 'DESC' : 'ASC')
|
|
||||||
order_key = (p[:order_by][0] == '-' ? p[:order_by][1, p[:order_by].size] : p[:order_by])
|
|
||||||
|
|
||||||
case order_key
|
|
||||||
when 'reference'
|
|
||||||
order_key = 'invoices.reference'
|
|
||||||
when 'date'
|
|
||||||
order_key = 'invoices.created_at'
|
|
||||||
when 'total'
|
|
||||||
order_key = 'invoices.total'
|
|
||||||
when 'name'
|
|
||||||
order_key = 'profiles.first_name'
|
|
||||||
else
|
|
||||||
order_key = 'invoices.id'
|
|
||||||
end
|
|
||||||
|
|
||||||
@invoices = Invoice.includes(:avoir, :invoiced, invoice_items: [:subscription, :invoice_item], user: [:profile, :trainings])
|
|
||||||
.joins(:user => :profile)
|
|
||||||
.order("#{order_key} #{direction}")
|
|
||||||
.page(p[:page])
|
|
||||||
.per(p[:size])
|
|
||||||
|
|
||||||
# ILIKE => PostgreSQL case-insensitive LIKE
|
|
||||||
@invoices = @invoices.where('invoices.reference LIKE :search', search: "#{p[:number].to_s}%") if p[:number].size > 0
|
|
||||||
@invoices = @invoices.where('profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search', search: "%#{p[:customer]}%") if p[:customer].size > 0
|
|
||||||
@invoices = @invoices.where("date_trunc('day', invoices.created_at) = :search", search: "%#{DateTime.iso8601(p[:date]).to_time.to_date.to_s}%") unless p[:date].nil?
|
|
||||||
|
|
||||||
@invoices
|
|
||||||
|
|
||||||
|
order = InvoicesService.parse_order(p[:order_by])
|
||||||
|
@invoices = InvoicesService.list(
|
||||||
|
order[:order_key],
|
||||||
|
order[:direction],
|
||||||
|
p[:page],
|
||||||
|
p[:size],
|
||||||
|
number: p[:number], customer: p[:customer], date: p[:date]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# only for create refund invoices (avoir)
|
# only for create refund invoices (avoir)
|
||||||
@ -64,9 +43,7 @@ class API::InvoicesController < API::ApiController
|
|||||||
@avoir = invoice.build_avoir(avoir_params)
|
@avoir = invoice.build_avoir(avoir_params)
|
||||||
if @avoir.save
|
if @avoir.save
|
||||||
# when saved, expire the subscription if needed
|
# when saved, expire the subscription if needed
|
||||||
if @avoir.subscription_to_expire
|
@avoir.expire_subscription if @avoir.subscription_to_expire
|
||||||
@avoir.expire_subscription
|
|
||||||
end
|
|
||||||
# then answer the API call
|
# then answer the API call
|
||||||
render :avoir, status: :created
|
render :avoir, status: :created
|
||||||
else
|
else
|
||||||
@ -75,8 +52,10 @@ class API::InvoicesController < API::ApiController
|
|||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def avoir_params
|
def avoir_params
|
||||||
params.require(:avoir).permit(:invoice_id, :avoir_date, :avoir_mode, :subscription_to_expire, :description, :invoice_items_ids => [])
|
params.require(:avoir).permit(:invoice_id, :avoir_date, :avoir_mode, :subscription_to_expire, :description,
|
||||||
|
invoice_items_ids: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_invoice
|
def set_invoice
|
||||||
|
62
app/services/invoices_service.rb
Normal file
62
app/services/invoices_service.rb
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Provides methods for accessing Invoices resources and properties
|
||||||
|
class InvoicesService
|
||||||
|
# return a paginated list of invoices, ordered by the given criterion and optionally filtered
|
||||||
|
# @param order_key {string} any column from invoices or joined a table
|
||||||
|
# @param direction {string} 'ASC' or 'DESC', linked to order_key
|
||||||
|
# @param page {number} page number, used to paginate results
|
||||||
|
# @param size {number} number of items per page
|
||||||
|
# @param filters {Hash} allowed filters: number, customer, date.
|
||||||
|
def self.list(order_key, direction, page, size, filters = {})
|
||||||
|
invoices = Invoice.includes(:avoir, :invoiced, invoice_items: %i[subscription invoice_item], user: %i[profile trainings])
|
||||||
|
.joins(user: :profile)
|
||||||
|
.order("#{order_key} #{direction}")
|
||||||
|
.page(page)
|
||||||
|
.per(size)
|
||||||
|
|
||||||
|
|
||||||
|
if filters[:number].size.positive?
|
||||||
|
invoices = invoices.where(
|
||||||
|
'invoices.reference LIKE :search',
|
||||||
|
search: "#{filters[:number]}%"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
if filters[:customer].size.positive?
|
||||||
|
# ILIKE => PostgreSQL case-insensitive LIKE
|
||||||
|
invoices = invoices.where(
|
||||||
|
'profiles.first_name ILIKE :search OR profiles.last_name ILIKE :search',
|
||||||
|
search: "%#{filters[:customer]}%"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
unless filters[:date].nil?
|
||||||
|
invoices = invoices.where(
|
||||||
|
"date_trunc('day', invoices.created_at) = :search",
|
||||||
|
search: "%#{DateTime.iso8601(filters[:date]).to_time.to_date}%"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
invoices
|
||||||
|
end
|
||||||
|
|
||||||
|
# Parse the order_by clause provided by JS client from '-column' form to SQL compatible form
|
||||||
|
# @param order_by {string} expected form: 'column' or '-column'
|
||||||
|
def self.parse_order(order_by)
|
||||||
|
direction = (order_by[0] == '-' ? 'DESC' : 'ASC')
|
||||||
|
key = (order_by[0] == '-' ? order_by[1, order_by.size] : order_by)
|
||||||
|
|
||||||
|
order_key = case key
|
||||||
|
when 'reference'
|
||||||
|
'invoices.reference'
|
||||||
|
when 'date'
|
||||||
|
'invoices.created_at'
|
||||||
|
when 'total'
|
||||||
|
'invoices.total'
|
||||||
|
when 'name'
|
||||||
|
'profiles.first_name'
|
||||||
|
else
|
||||||
|
'invoices.id'
|
||||||
|
end
|
||||||
|
{ direction: direction, order_key: order_key }
|
||||||
|
end
|
||||||
|
end
|
36
test/integration/invoices/as_admin_test.rb
Normal file
36
test/integration/invoices/as_admin_test.rb
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class InvoicesTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
|
# Called before every test method runs. Can be used
|
||||||
|
# to set up fixture information.
|
||||||
|
def setup
|
||||||
|
@admin = User.find_by(username: 'admin')
|
||||||
|
login_as(@admin, scope: :user)
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'admin list invoices' do
|
||||||
|
|
||||||
|
post '/api/invoices/list', { query: {
|
||||||
|
number: '',
|
||||||
|
customer: '',
|
||||||
|
date: nil,
|
||||||
|
order_by: '-reference',
|
||||||
|
page: 1,
|
||||||
|
size: 20 # test db may have < 20 invoices
|
||||||
|
} }.to_json, default_headers
|
||||||
|
|
||||||
|
# Check response format & status
|
||||||
|
assert_equal 200, response.status, response.body
|
||||||
|
assert_equal Mime::JSON, response.content_type
|
||||||
|
|
||||||
|
# Check that we have all invoices
|
||||||
|
invoices = json_response(response.body)
|
||||||
|
assert_equal Invoice.count, invoices.size, 'some invoices are missing'
|
||||||
|
|
||||||
|
# Check that invoices are ordered by reference
|
||||||
|
assert_equal '1604002', invoices.first[:reference]
|
||||||
|
assert_equal '1203001', invoices.last[:reference]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -1,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MemebersTest < ActionDispatch::IntegrationTest
|
class MembersTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
# Called before every test method runs. Can be used
|
# Called before every test method runs. Can be used
|
||||||
# to set up fixture information.
|
# to set up fixture information.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user