mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2024-11-29 10:24:20 +01:00
generate invoice with multi vat
This commit is contained in:
parent
5e8c90458b
commit
c5211e98e3
@ -27,7 +27,7 @@ class InvoiceItem < Footprintable
|
|||||||
def net_amount
|
def net_amount
|
||||||
# deduct VAT
|
# deduct VAT
|
||||||
vat_service = VatHistoryService.new
|
vat_service = VatHistoryService.new
|
||||||
vat_rate = vat_service.invoice_vat(invoice)
|
vat_rate = vat_service.invoice_vat(self)
|
||||||
Rational(amount_after_coupon / (vat_rate / 100.00 + 1)).round.to_f
|
Rational(amount_after_coupon / (vat_rate / 100.00 + 1)).round.to_f
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -36,6 +36,21 @@ class InvoiceItem < Footprintable
|
|||||||
amount_after_coupon - net_amount
|
amount_after_coupon - net_amount
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# return invoice item type (Matchine/Training/Space/Event/Subscription)
|
||||||
|
def invoice_item_type
|
||||||
|
if object_type == Reservation.name
|
||||||
|
reservable_type = object.try(:reservable_type)
|
||||||
|
if reservable_type
|
||||||
|
return reservable_type
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
elsif object_type == Subscription.name
|
||||||
|
return Subscription.name
|
||||||
|
end
|
||||||
|
''
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def log_changes
|
def log_changes
|
||||||
|
@ -230,10 +230,18 @@ class PDF::Invoice < Prawn::Document
|
|||||||
|
|
||||||
# TVA
|
# TVA
|
||||||
vat_service = VatHistoryService.new
|
vat_service = VatHistoryService.new
|
||||||
vat_rate = vat_service.invoice_vat(invoice)
|
vat_rate_group = {}
|
||||||
if vat_rate != 0
|
invoice.invoice_items.each do |item|
|
||||||
|
vat_type = item.invoice_item_type
|
||||||
|
vat_rate_group[vat_type] = { vat_rate: vat_service.invoice_vat(item), total_vat: 0, amount: 0 } unless vat_rate_group[vat_type]
|
||||||
|
vat_rate_group[vat_type][:total_vat] += item.vat
|
||||||
|
vat_rate_group[vat_type][:amount] += item.amount.to_i
|
||||||
|
end
|
||||||
|
if total_vat != 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_rate_group.each do |_type, rate|
|
||||||
|
data += [[I18n.t('invoices.including_VAT_RATE', RATE: rate[:vat_rate], AMOUNT: number_to_currency(rate[:amount] / 100.00)), number_to_currency(rate[:total_vat] / 100.00)]]
|
||||||
|
end
|
||||||
data += [[I18n.t('invoices.including_total_excluding_taxes'), number_to_currency(total_ht / 100.00)]]
|
data += [[I18n.t('invoices.including_total_excluding_taxes'), number_to_currency(total_ht / 100.00)]]
|
||||||
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)]]
|
||||||
|
|
||||||
@ -252,23 +260,25 @@ class PDF::Invoice < Prawn::Document
|
|||||||
row(0).font_style = :bold
|
row(0).font_style = :bold
|
||||||
column(1).style align: :right
|
column(1).style align: :right
|
||||||
|
|
||||||
if Setting.get('invoice_VAT-active')
|
if total_vat != 0
|
||||||
# Total incl. taxes
|
# Total incl. taxes
|
||||||
row(-1).style align: :right
|
row(-1).style align: :right
|
||||||
row(-1).background_color = 'E4E4E4'
|
row(-1).background_color = 'E4E4E4'
|
||||||
row(-1).font_style = :bold
|
row(-1).font_style = :bold
|
||||||
# including VAT xx%
|
vat_rate_group.size.times do |i|
|
||||||
row(-2).style align: :right
|
# including VAT xx%
|
||||||
row(-2).background_color = 'E4E4E4'
|
row(-2 - i).style align: :right
|
||||||
row(-2).font_style = :italic
|
row(-2 - i).background_color = 'E4E4E4'
|
||||||
|
row(-2 - i).font_style = :italic
|
||||||
|
end
|
||||||
# including total excl. taxes
|
# including total excl. taxes
|
||||||
row(-3).style align: :right
|
row(-3 - vat_rate_group.size + 1).style align: :right
|
||||||
row(-3).background_color = 'E4E4E4'
|
row(-3 - vat_rate_group.size + 1).background_color = 'E4E4E4'
|
||||||
row(-3).font_style = :italic
|
row(-3 - vat_rate_group.size + 1).font_style = :italic
|
||||||
# including amount payed on ordering
|
# including amount payed on ordering
|
||||||
row(-4).style align: :right
|
row(-4 - vat_rate_group.size + 1).style align: :right
|
||||||
row(-4).background_color = 'E4E4E4'
|
row(-4 - vat_rate_group.size + 1).background_color = 'E4E4E4'
|
||||||
row(-4).font_style = :bold
|
row(-4 - vat_rate_group.size + 1).font_style = :bold
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -2,35 +2,29 @@
|
|||||||
|
|
||||||
# Provides the VAT rate in use at the given date
|
# Provides the VAT rate in use at the given date
|
||||||
class VatHistoryService
|
class VatHistoryService
|
||||||
# return the VAT rate for the given Invoice/Avoir
|
# return the VAT rate for the given InvoiceItem
|
||||||
def invoice_vat(invoice_item)
|
def invoice_vat(invoice_item)
|
||||||
if invoice_item.invoice.is_a?(Avoir)
|
if invoice_item.invoice.is_a?(Avoir)
|
||||||
vat_rate(invoice.avoir_date, vat_type(invoice_item))
|
vat_rate(invoice_item.invoice.avoir_date, invoice_item.invoice_item_type)
|
||||||
else
|
else
|
||||||
vat_rate(invoice.created_at, vat_type(invoice_item))
|
vat_rate(invoice_item.invoice.created_at, invoice_item.invoice_item_type)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# return the VAT rate for the given date
|
# return the VAT rate for the given date and vat type
|
||||||
def vat_rate(date, vat_rate_type)
|
def vat_rate(date, vat_rate_type)
|
||||||
@vat_rates = vat_history(vat_rate_type) if @vat_rates.nil?
|
vat_rates = vat_history(vat_rate_type)
|
||||||
|
|
||||||
first_rate = @vat_rates.first
|
first_rate = vat_rates.first
|
||||||
return first_rate[:rate] if date < first_rate[:date]
|
return first_rate[:rate] if date < first_rate[:date]
|
||||||
|
|
||||||
@vat_rates.each_index do |i|
|
vat_rates.each_index do |i|
|
||||||
return @vat_rates[i][:rate] if date >= @vat_rates[i][:date] && (@vat_rates[i + 1].nil? || date < @vat_rates[i + 1][:date])
|
return vat_rates[i][:rate] if date >= vat_rates[i][:date] && (vat_rates[i + 1].nil? || date < vat_rates[i + 1][:date])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def vat_type(invoice_item)
|
|
||||||
return invoice_item.object.reservable_type if invoice_item.object_type == 'Reservation'
|
|
||||||
|
|
||||||
'Subscription'
|
|
||||||
end
|
|
||||||
|
|
||||||
def vat_history(vat_rate_type)
|
def vat_history(vat_rate_type)
|
||||||
chronology = []
|
chronology = []
|
||||||
end_date = DateTime.current
|
end_date = DateTime.current
|
||||||
@ -41,28 +35,32 @@ class VatHistoryService
|
|||||||
chronology.push(start: DateTime.new(0), end: end_date, enabled: false)
|
chronology.push(start: DateTime.new(0), end: end_date, enabled: false)
|
||||||
date_rates = []
|
date_rates = []
|
||||||
vat_rate_history_values = []
|
vat_rate_history_values = []
|
||||||
vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC')
|
if vat_rate_type.present?
|
||||||
first_vat_rate_by_type = vat_rate_by_type.select { |v| v.value.present? }.first
|
vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC')
|
||||||
if first_vat_rate_by_type
|
first_vat_rate_by_type = vat_rate_by_type.select { |v| v.value.present? }.first
|
||||||
vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC').to_a
|
if first_vat_rate_by_type
|
||||||
vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}").history_values.where('created_at >= ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC')
|
vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC').to_a
|
||||||
vat_rate_by_type.each do |rate|
|
vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}").history_values.where('created_at >= ?', first_vat_rate_by_type.created_at).order(created_at: 'ASC')
|
||||||
if rate.value.blank?
|
vat_rate_by_type.each do |rate|
|
||||||
vat_rate = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', rate.created_at).order(created_at: 'DESC').first
|
if rate.value.blank?
|
||||||
rate.value = vat_rate.value
|
vat_rate = Setting.find_by(name: 'invoice_VAT-rate').history_values.where('created_at < ?', rate.created_at).order(created_at: 'DESC').first
|
||||||
|
rate.value = vat_rate.value
|
||||||
|
end
|
||||||
|
vat_rate_history_values.push(rate)
|
||||||
end
|
end
|
||||||
vat_rate_history_values.push(rate)
|
else
|
||||||
|
vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').to_a
|
||||||
|
end
|
||||||
|
vat_rate_history_values.each do |rate|
|
||||||
|
range = chronology.select { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }.first
|
||||||
|
date = range[:enabled] ? rate.created_at : range[:end]
|
||||||
|
date_rates.push(date: date, rate: rate.value.to_i)
|
||||||
|
end
|
||||||
|
chronology.reverse_each do |period|
|
||||||
|
date_rates.push(date: period[:start], rate: 0) unless period[:enabled]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').to_a
|
date_rates.push(date: chronology[-1][:start], rate: 0)
|
||||||
end
|
|
||||||
vat_rate_history_values.each do |rate|
|
|
||||||
range = chronology.select { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }.first
|
|
||||||
date = range[:enabled] ? rate.created_at : range[:end]
|
|
||||||
date_rates.push(date: date, rate: rate.value.to_i)
|
|
||||||
end
|
|
||||||
chronology.reverse_each do |period|
|
|
||||||
date_rates.push(date: period[:start], rate: 0) unless period[:enabled]
|
|
||||||
end
|
end
|
||||||
date_rates.sort_by { |k| k[:date] }
|
date_rates.sort_by { |k| k[:date] }
|
||||||
end
|
end
|
||||||
|
@ -90,7 +90,7 @@ de:
|
|||||||
other: "%{count} %{NAME}-Tickets"
|
other: "%{count} %{NAME}-Tickets"
|
||||||
coupon_CODE_discount_of_DISCOUNT: "Gutschein {CODE}: Rabatt von {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
coupon_CODE_discount_of_DISCOUNT: "Gutschein {CODE}: Rabatt von {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
||||||
total_including_all_taxes: "Gesamtpreis inkl. Steuern"
|
total_including_all_taxes: "Gesamtpreis inkl. Steuern"
|
||||||
including_VAT_RATE: "Inklusive MwSt. %{RATE}%"
|
including_VAT_RATE: "Inklusive MwSt. %{RATE} von %{AMOUNT}"
|
||||||
including_total_excluding_taxes: "Gesamtbetrag zzgl. Steuern"
|
including_total_excluding_taxes: "Gesamtbetrag zzgl. Steuern"
|
||||||
including_amount_payed_on_ordering: "Inklusive bei Bestellung bezahlter Betrag"
|
including_amount_payed_on_ordering: "Inklusive bei Bestellung bezahlter Betrag"
|
||||||
total_amount: "Gesamtbetrag"
|
total_amount: "Gesamtbetrag"
|
||||||
|
@ -90,7 +90,7 @@ en:
|
|||||||
other: "%{count} %{NAME} tickets"
|
other: "%{count} %{NAME} tickets"
|
||||||
coupon_CODE_discount_of_DISCOUNT: "Coupon {CODE}: discount of {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
coupon_CODE_discount_of_DISCOUNT: "Coupon {CODE}: discount of {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
||||||
total_including_all_taxes: "Total incl. all taxes"
|
total_including_all_taxes: "Total incl. all taxes"
|
||||||
including_VAT_RATE: "Including VAT %{RATE}%"
|
including_VAT_RATE: "Including VAT %{RATE}% of %{AMOUNT}"
|
||||||
including_total_excluding_taxes: "Including Total excl. taxes"
|
including_total_excluding_taxes: "Including Total excl. taxes"
|
||||||
including_amount_payed_on_ordering: "Including amount payed on ordering"
|
including_amount_payed_on_ordering: "Including amount payed on ordering"
|
||||||
total_amount: "Total amount"
|
total_amount: "Total amount"
|
||||||
|
@ -90,7 +90,7 @@ es:
|
|||||||
other: "%{count} %{NAME} entradas"
|
other: "%{count} %{NAME} entradas"
|
||||||
coupon_CODE_discount_of_DISCOUNT: "Cupón {CODE}: descuento de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
coupon_CODE_discount_of_DISCOUNT: "Cupón {CODE}: descuento de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
||||||
total_including_all_taxes: "Total impuestos incluidos"
|
total_including_all_taxes: "Total impuestos incluidos"
|
||||||
including_VAT_RATE: "Incluyendo IVA %{RATE}%"
|
including_VAT_RATE: "Incluyendo IVA %{RATE}% de %{AMOUNT}"
|
||||||
including_total_excluding_taxes: "Excluyendo IVA"
|
including_total_excluding_taxes: "Excluyendo IVA"
|
||||||
including_amount_payed_on_ordering: "Incluyendo cantidad pagada en el pedido"
|
including_amount_payed_on_ordering: "Incluyendo cantidad pagada en el pedido"
|
||||||
total_amount: "Precio total"
|
total_amount: "Precio total"
|
||||||
|
@ -90,7 +90,7 @@ fr:
|
|||||||
other: "%{count} places %{NAME}"
|
other: "%{count} places %{NAME}"
|
||||||
coupon_CODE_discount_of_DISCOUNT: "Code {CODE} : remise de {DISCOUNT} {TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
coupon_CODE_discount_of_DISCOUNT: "Code {CODE} : remise de {DISCOUNT} {TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
||||||
total_including_all_taxes: "Total TTC"
|
total_including_all_taxes: "Total TTC"
|
||||||
including_VAT_RATE: "Dont TVA %{RATE}%"
|
including_VAT_RATE: "Dont TVA %{RATE}% de %{AMOUNT}"
|
||||||
including_total_excluding_taxes: "Dont total HT"
|
including_total_excluding_taxes: "Dont total HT"
|
||||||
including_amount_payed_on_ordering: "Dont montant payé à la commande"
|
including_amount_payed_on_ordering: "Dont montant payé à la commande"
|
||||||
total_amount: "Montant total"
|
total_amount: "Montant total"
|
||||||
|
@ -90,7 +90,7 @@
|
|||||||
other: "%{count} %{NAME} tickets"
|
other: "%{count} %{NAME} tickets"
|
||||||
coupon_CODE_discount_of_DISCOUNT: "Kupong {CODE}: rabatt på {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
coupon_CODE_discount_of_DISCOUNT: "Kupong {CODE}: rabatt på {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
||||||
total_including_all_taxes: "Sum inkl. MVA"
|
total_including_all_taxes: "Sum inkl. MVA"
|
||||||
including_VAT_RATE: "Inkludert MVA %{RATE}%"
|
including_VAT_RATE: "Inkludert MVA %{RATE}% %{AMOUNT}"
|
||||||
including_total_excluding_taxes: "Inkludert total ekskl. MVA"
|
including_total_excluding_taxes: "Inkludert total ekskl. MVA"
|
||||||
including_amount_payed_on_ordering: "Inkludert beløp betalt ved bestilling"
|
including_amount_payed_on_ordering: "Inkludert beløp betalt ved bestilling"
|
||||||
total_amount: "Totalbeløp"
|
total_amount: "Totalbeløp"
|
||||||
|
@ -90,7 +90,7 @@ pt:
|
|||||||
other: "%{count} %{NAME} tickets"
|
other: "%{count} %{NAME} tickets"
|
||||||
coupon_CODE_discount_of_DISCOUNT: "Cupom {CODE}: desconto de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
coupon_CODE_discount_of_DISCOUNT: "Cupom {CODE}: desconto de {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation
|
||||||
total_including_all_taxes: "Total de taxas inclusas"
|
total_including_all_taxes: "Total de taxas inclusas"
|
||||||
including_VAT_RATE: "Incluindo VAT %{RATE}%"
|
including_VAT_RATE: "Incluindo VAT %{RATE}% de %{AMOUNT}"
|
||||||
including_total_excluding_taxes: "Incluindo total de faixas exclusas"
|
including_total_excluding_taxes: "Incluindo total de faixas exclusas"
|
||||||
including_amount_payed_on_ordering: "Incluindo o valor pago na encomenda"
|
including_amount_payed_on_ordering: "Incluindo o valor pago na encomenda"
|
||||||
total_amount: "Montante total"
|
total_amount: "Montante total"
|
||||||
|
Loading…
Reference in New Issue
Block a user