app/api/bookyt/api/invoices.rb
module Bookyt
class API
class Invoices < Grape::API
helpers do
def create_debit_invoice?
declared(params)[:type] == 'debit'
end
def invoice_params
attributes = declared(params).except(:line_items, :type, :address_id)
attributes.merge! addressee_attributes
attributes[:line_items_attributes] = line_items_attributes
attributes
end
def addressee_attributes
return {} unless declared(params)[:type]
if create_debit_invoice?
{
customer_id: params[:address_id],
company_id: current_tenant.company.id,
}
else
{
customer_id: current_tenant.company.id,
company_id: params[:address_id],
}
end
end
def line_items_attributes
persistable_line_items_attributes | removable_line_items_attributes
end
def persistable_line_items_attributes
line_items_param.map do |line_item|
item = line_item.except(:credit_account_code, :debit_account_code)
item[:credit_account] = Account.find_by_code(line_item[:credit_account_code])
item[:debit_account] = Account.find_by_code(line_item[:debit_account_code])
item
end
end
def removable_line_items_attributes
return [] unless params[:id]
Invoice.find(params[:id]).line_items.map do |line_item|
next if line_items_param.detect { |item| item[:id] == line_item.id }
{ id: line_item.id, _destroy: true }
end.compact
end
def line_items_param
declared(params)[:line_items]
end
end
resource :invoices do
desc 'Fetch all the invoices'
get do
invoices = Invoice.all
present invoices, with: Bookyt::Entities::Invoice
end
before do
Rails.logger.info params.inspect
end
desc 'Create a new invoice'
params do
requires :title, type: String, desc: 'Title of the invoice'
requires :address_id, type: Integer, desc: 'ID of the company or customer'
requires :type, type: String, values: %w(debit credit), desc: 'Type of the invoice (debit or credit)'
requires :state, type: String, values: Invoice::STATES, default: 'booked', desc: 'Current state'
requires :value_date, type: Date, desc: 'Value date of the invoice'
requires :due_date, type: Date, desc: 'Due date of the invoice'
optional :duration_from, type: Date, desc: 'Duration start of the invoice'
optional :duration_to, type: Date, desc: 'Duration end of the invoice'
optional :text, type: String, desc: 'Additional invoice text'
optional :remarks, type: String, desc: 'Internal remarks'
requires :line_items, type: Array do
requires :title, type: String, desc: 'Title/Description of the line item'
requires :times, type: BigDecimal, default: 1, desc: 'Price multiplier'
requires :quantity, type: String, default: 'x', values: %w(x hours overall %), desc: 'Quantity'
requires :price, type: BigDecimal, desc: 'Price of the line item, without modifiers applied'
requires :credit_account_code, type: String, values: -> { Account.pluck(:code) }, desc: 'Code of the credit account'
requires :debit_account_code, type: String, values: -> { Account.pluck(:code) }, desc: 'Code of the debit account'
optional :date, type: Date, desc: 'Date of the line item'
end
end
post do
invoice_klass = create_debit_invoice? ? DebitInvoice : CreditInvoice
invoice = invoice_klass.create!(invoice_params)
present invoice, with: Bookyt::Entities::Invoice
end
route_param :id do
desc 'Fetch a invoice'
get do
invoice = Invoice.find(params[:id])
present invoice, with: Bookyt::Entities::Invoice
end
desc 'Fetch a debit invoice as pdf'
get 'pdf' do
invoice = DebitInvoice.find(params[:id])
pdf = DebitInvoicePDF.new(invoice, current_tenant)
content_type Mime::Type.lookup_by_extension('pdf').to_s
env['api.format'] = :binary
header 'Content-Disposition', "attachment; filename=#{URI.escape(pdf.filename)}"
pdf.call
end
desc 'Update a invoice'
params do
requires :title, type: String, desc: 'Title of the invoice'
requires :state, type: String, values: Invoice::STATES, default: 'booked', desc: 'Current state'
requires :value_date, type: Date, desc: 'Value date of the invoice'
requires :due_date, type: Date, desc: 'Due date of the invoice'
optional :duration_from, type: Date, desc: 'Duration start of the invoice'
optional :duration_to, type: Date, desc: 'Duration end of the invoice'
optional :text, type: String, desc: 'Additional invoice text, visible to customer'
optional :remarks, type: String, desc: 'Internal remarks, not visible to customer'
requires :line_items, type: Array do
optional :id, type: Integer, desc: 'The ID of the line item'
requires :title, type: String, desc: 'Title/Description of the line item'
requires :times, type: BigDecimal, default: 1, desc: 'Price multiplier'
requires :quantity, type: String, default: 'x', values: %w(x hours overall %), desc: 'Quantity'
requires :price, type: BigDecimal, desc: 'Price of the line item, without modifiers applied'
requires :credit_account_code, type: String, values: -> { Account.pluck(:code) }, desc: 'Code of the credit account'
requires :debit_account_code, type: String, values: -> { Account.pluck(:code) }, desc: 'Code of the debit account'
optional :date, type: Date, desc: 'Date of the line item'
end
end
put do
invoice = Invoice.find(params[:id])
invoice.update_attributes!(invoice_params)
present invoice, with: Bookyt::Entities::Invoice
end
desc 'Delete a invoice'
delete do
Invoice.find(params[:id]).destroy
body false
status 204
end
end
end
end
end
end