mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
Compute the VAT per item in each invoices, instead of globally
This commit is contained in:
parent
02c7cb801f
commit
cd2c8488c2
@ -1,6 +1,7 @@
|
|||||||
# Changelog Fab Manager
|
# Changelog Fab Manager
|
||||||
|
|
||||||
- Ability to configure and export the accounting data to the ACD accounting software
|
- Ability to configure and export the accounting data to the ACD accounting software
|
||||||
|
- Compute the VAT per item in each invoices, instead of globally
|
||||||
- Fix a bug: invoices with total = 0, are marked as paid on site even if paid by card
|
- Fix a bug: invoices with total = 0, are marked as paid on site even if paid by card
|
||||||
- [TODO DEPLOY] `rake db:migrate`
|
- [TODO DEPLOY] `rake db:migrate`
|
||||||
|
|
||||||
|
@ -21,6 +21,25 @@ class InvoiceItem < ActiveRecord::Base
|
|||||||
footprint == compute_footprint
|
footprint == compute_footprint
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def amount_after_coupon
|
||||||
|
# deduct coupon discount
|
||||||
|
coupon_service = CouponService.new
|
||||||
|
coupon_service.ventilate(invoice.total, amount, invoice.coupon)
|
||||||
|
end
|
||||||
|
|
||||||
|
# return the item amount, coupon discount deducted, if any, and VAT excluded, if applicable
|
||||||
|
def net_amount
|
||||||
|
# deduct VAT
|
||||||
|
vat_service = VatHistoryService.new
|
||||||
|
vat_rate = vat_service.invoice_vat(invoice)
|
||||||
|
Rational(amount_after_coupon / (vat_rate / 100.00 + 1)).round.to_f
|
||||||
|
end
|
||||||
|
|
||||||
|
# return the VAT amount for this item
|
||||||
|
def vat
|
||||||
|
amount_after_coupon - net_amount
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def compute_footprint
|
def compute_footprint
|
||||||
|
@ -121,6 +121,8 @@ class PDF::Invoice < Prawn::Document
|
|||||||
data = [[I18n.t('invoices.details'), I18n.t('invoices.amount')]]
|
data = [[I18n.t('invoices.details'), I18n.t('invoices.amount')]]
|
||||||
|
|
||||||
total_calc = 0
|
total_calc = 0
|
||||||
|
total_ht = 0
|
||||||
|
total_vat = 0
|
||||||
# going through invoice_items
|
# going through invoice_items
|
||||||
invoice.invoice_items.each do |item|
|
invoice.invoice_items.each do |item|
|
||||||
|
|
||||||
@ -184,6 +186,8 @@ class PDF::Invoice < Prawn::Document
|
|||||||
|
|
||||||
data += [[details, number_to_currency(price)]]
|
data += [[details, number_to_currency(price)]]
|
||||||
total_calc += price
|
total_calc += price
|
||||||
|
total_ht += item.net_amount
|
||||||
|
total_vat += item.vat
|
||||||
end
|
end
|
||||||
|
|
||||||
## subtract the coupon, if any
|
## subtract the coupon, if any
|
||||||
@ -210,15 +214,13 @@ class PDF::Invoice < Prawn::Document
|
|||||||
|
|
||||||
# discount textual description
|
# discount textual description
|
||||||
literal_discount = cp.percent_off
|
literal_discount = cp.percent_off
|
||||||
if cp.type == 'amount_off'
|
literal_discount = number_to_currency(cp.amount_off / 100.00) if cp.type == 'amount_off'
|
||||||
literal_discount = number_to_currency(cp.amount_off / 100.00)
|
|
||||||
end
|
|
||||||
|
|
||||||
# add a row for the coupon
|
# add a row for the coupon
|
||||||
data += [[_t('invoices.coupon_CODE_discount_of_DISCOUNT',
|
data += [[_t('invoices.coupon_CODE_discount_of_DISCOUNT',
|
||||||
CODE: cp.code,
|
CODE: cp.code,
|
||||||
DISCOUNT: literal_discount,
|
DISCOUNT: literal_discount,
|
||||||
TYPE: cp.type), number_to_currency(-discount)] ]
|
TYPE: cp.type), number_to_currency(-discount)]]
|
||||||
end
|
end
|
||||||
|
|
||||||
# total verification
|
# total verification
|
||||||
@ -226,20 +228,18 @@ class PDF::Invoice < Prawn::Document
|
|||||||
puts "ERROR: totals are NOT equals => expected: #{total}, computed: #{total_calc}" if total_calc != total
|
puts "ERROR: totals are NOT equals => expected: #{total}, computed: #{total_calc}" if total_calc != total
|
||||||
|
|
||||||
# TVA
|
# TVA
|
||||||
if Setting.find_by(name: 'invoice_VAT-active').value == 'true'
|
vat_service = VatHistoryService.new
|
||||||
|
vat_rate = vat_service.invoice_vat(invoice)
|
||||||
|
if vat_rate != 0
|
||||||
data += [[I18n.t('invoices.total_including_all_taxes'), number_to_currency(total)]]
|
data += [[I18n.t('invoices.total_including_all_taxes'), number_to_currency(total)]]
|
||||||
|
data += [[I18n.t('invoices.including_VAT_RATE', RATE: vat_rate), number_to_currency(total_vat / 100.00)]]
|
||||||
vat_service = VatHistoryService.new
|
data += [[I18n.t('invoices.including_total_excluding_taxes'), number_to_currency(total_ht / 100.00)]]
|
||||||
vat_rate = vat_service.invoice_vat(invoice)
|
|
||||||
vat = total / (vat_rate / 100.00 + 1)
|
|
||||||
data += [[I18n.t('invoices.including_VAT_RATE', RATE: vat_rate), number_to_currency(total - vat)]]
|
|
||||||
data += [[I18n.t('invoices.including_total_excluding_taxes'), number_to_currency(vat)]]
|
|
||||||
data += [[I18n.t('invoices.including_amount_payed_on_ordering'), number_to_currency(total)]]
|
data += [[I18n.t('invoices.including_amount_payed_on_ordering'), number_to_currency(total)]]
|
||||||
|
|
||||||
# checking the round number
|
# checking the round number
|
||||||
rounded = sprintf('%.2f', vat).to_f + sprintf('%.2f', total - vat).to_f
|
rounded = sprintf('%.2f', total_vat / 100.00).to_f + sprintf('%.2f', total_ht / 100.00).to_f
|
||||||
if rounded != sprintf('%.2f', total_calc).to_f
|
if rounded != sprintf('%.2f', total_calc).to_f
|
||||||
puts 'ERROR: rounding the numbers cause an invoice inconsistency. ' +
|
puts 'ERROR: rounding the numbers cause an invoice inconsistency. ' \
|
||||||
"Total expected: #{sprintf('%.2f', total_calc)}, total computed: #{rounded}"
|
"Total expected: #{sprintf('%.2f', total_calc)}, total computed: #{rounded}"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -7,7 +7,7 @@ class FootprintService
|
|||||||
# @param item an instance of the provided class
|
# @param item an instance of the provided class
|
||||||
# @param sort the items in database by the provided criterion, to find the previous one
|
# @param sort the items in database by the provided criterion, to find the previous one
|
||||||
def self.compute_footprint(klass, item, sort_on = 'id')
|
def self.compute_footprint(klass, item, sort_on = 'id')
|
||||||
raise TypeError unless item.class.name == klass.name
|
raise TypeError unless item.is_a? klass
|
||||||
|
|
||||||
previous = klass.where("#{sort_on} < ?", item[sort_on])
|
previous = klass.where("#{sort_on} < ?", item[sort_on])
|
||||||
.order("#{sort_on} DESC")
|
.order("#{sort_on} DESC")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user