2019-08-01 11:26:40 +02:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# Provides the VAT rate in use at the given date
|
|
|
|
class VatHistoryService
|
2021-12-28 19:42:04 +01:00
|
|
|
# @return the VAT rate for the given Invoice
|
|
|
|
def invoice_vat(invoice)
|
|
|
|
vat_rate_group = {}
|
|
|
|
invoice.invoice_items.each do |item|
|
|
|
|
vat_type = item.invoice_item_type
|
|
|
|
vat_rate_group[vat_type] = { vat_rate: invoice_item_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
|
|
|
|
vat_rate_group
|
|
|
|
end
|
|
|
|
|
2021-12-23 19:36:23 +01:00
|
|
|
# return the VAT rate for the given InvoiceItem
|
2021-12-28 19:42:04 +01:00
|
|
|
def invoice_item_vat(invoice_item)
|
2021-12-23 09:25:48 +01:00
|
|
|
if invoice_item.invoice.is_a?(Avoir)
|
2021-12-23 19:36:23 +01:00
|
|
|
vat_rate(invoice_item.invoice.avoir_date, invoice_item.invoice_item_type)
|
2019-08-01 11:26:40 +02:00
|
|
|
else
|
2021-12-23 19:36:23 +01:00
|
|
|
vat_rate(invoice_item.invoice.created_at, invoice_item.invoice_item_type)
|
2019-08-01 11:26:40 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-12-23 19:36:23 +01:00
|
|
|
# return the VAT rate for the given date and vat type
|
2021-12-23 09:25:48 +01:00
|
|
|
def vat_rate(date, vat_rate_type)
|
2021-12-23 19:36:23 +01:00
|
|
|
vat_rates = vat_history(vat_rate_type)
|
2019-08-01 11:26:40 +02:00
|
|
|
|
2021-12-23 19:36:23 +01:00
|
|
|
first_rate = vat_rates.first
|
2019-08-01 11:26:40 +02:00
|
|
|
return first_rate[:rate] if date < first_rate[:date]
|
|
|
|
|
2021-12-23 19:36:23 +01:00
|
|
|
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])
|
2019-08-01 11:26:40 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2022-10-26 17:35:02 +02:00
|
|
|
# This method is really complex and cannot be simplified using the current data model
|
|
|
|
# As a futur improvement, we should save the VAT rate for each invoice_item in the DB
|
|
|
|
def vat_history(vat_rate_type) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
2019-09-18 13:28:53 +02:00
|
|
|
chronology = []
|
2019-12-02 11:57:25 +01:00
|
|
|
end_date = DateTime.current
|
2019-09-18 13:28:53 +02:00
|
|
|
Setting.find_by(name: 'invoice_VAT-active').history_values.order(created_at: 'DESC').each do |v|
|
|
|
|
chronology.push(start: v.created_at, end: end_date, enabled: v.value == 'true')
|
|
|
|
end_date = v.created_at
|
2019-08-01 11:26:40 +02:00
|
|
|
end
|
2019-10-29 15:20:25 +01:00
|
|
|
chronology.push(start: DateTime.new(0), end: end_date, enabled: false)
|
2021-12-29 10:57:59 +01:00
|
|
|
# now chronology contains something like one of the following:
|
|
|
|
# - [{start: 0000-01-01, end: now, enabled: false}] => VAT was never enabled
|
|
|
|
# - [
|
|
|
|
# {start: fab-manager initial setup date, end: now, enabled: true},
|
|
|
|
# {start: 0000-01-01, end: fab-manager initial setup date, enabled: false}
|
|
|
|
# ] => VAT was enabled from the beginning
|
|
|
|
# - [
|
|
|
|
# {start: [date disabled], end: now, enabled: false},
|
|
|
|
# {start: [date enable], end: [date disabled], enabled: true},
|
|
|
|
# {start: fab-manager initial setup date, end: [date enabled], enabled: false},
|
|
|
|
# {start: 0000-01-01, end: fab-manager initial setup date, enabled: false}
|
|
|
|
# ] => VAT was enabled at some point, and disabled at some other point later
|
|
|
|
|
2021-12-29 12:08:41 +01:00
|
|
|
date_rates = []
|
2021-12-23 19:36:23 +01:00
|
|
|
if vat_rate_type.present?
|
|
|
|
vat_rate_by_type = Setting.find_by(name: "invoice_VAT-rate_#{vat_rate_type}")&.history_values&.order(created_at: 'ASC')
|
2021-12-24 19:05:03 +01:00
|
|
|
first_vat_rate_by_type = vat_rate_by_type&.select { |v| v.value.present? }&.first
|
2021-12-23 19:36:23 +01:00
|
|
|
if first_vat_rate_by_type
|
2021-12-29 10:57:59 +01:00
|
|
|
# before the first VAT rate was defined for the given type, the general VAT rate is used
|
|
|
|
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
|
|
|
|
# after that, the VAT rate for the given type is used
|
|
|
|
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')
|
2021-12-23 19:36:23 +01:00
|
|
|
vat_rate_by_type.each do |rate|
|
2022-06-01 12:41:19 +02:00
|
|
|
if rate.value.blank? || rate.value == 'null' || rate.value == 'undefined' || rate.value == 'NaN'
|
2021-12-29 10:57:59 +01:00
|
|
|
# if, at some point in the history, a blank rate was set, the general VAT rate is used instead
|
|
|
|
vat_rate = Setting.find_by(name: 'invoice_VAT-rate')
|
|
|
|
.history_values.where('created_at < ?', rate.created_at)
|
|
|
|
.order(created_at: 'DESC')
|
|
|
|
.first
|
2021-12-23 19:36:23 +01:00
|
|
|
rate.value = vat_rate.value
|
|
|
|
end
|
|
|
|
vat_rate_history_values.push(rate)
|
2021-12-23 09:25:48 +01:00
|
|
|
end
|
2021-12-23 19:36:23 +01:00
|
|
|
else
|
2021-12-29 10:57:59 +01:00
|
|
|
# if no VAT rate is defined for the given type, the general VAT rate is always used
|
2021-12-23 19:36:23 +01:00
|
|
|
vat_rate_history_values = Setting.find_by(name: 'invoice_VAT-rate').history_values.order(created_at: 'ASC').to_a
|
|
|
|
end
|
2021-12-29 10:57:59 +01:00
|
|
|
|
|
|
|
# Now we have all the rates history, we can build the final chronology, depending on whether VAT was enabled or not
|
2022-01-12 14:57:56 +01:00
|
|
|
vat_rate_history_values.reverse_each do |rate|
|
2021-12-29 10:57:59 +01:00
|
|
|
# when the VAT rate was enabled, set the date it was enabled and the rate
|
2022-01-12 14:57:56 +01:00
|
|
|
range = chronology.find { |p| rate.created_at.to_i.between?(p[:start].to_i, p[:end].to_i) }
|
2021-12-23 19:36:23 +01:00
|
|
|
date = range[:enabled] ? rate.created_at : range[:end]
|
2022-10-26 17:35:02 +02:00
|
|
|
date_rates.push(date: date, rate: rate.value.to_f) unless date_rates.find { |d| d[:date] == date }
|
2021-12-23 19:36:23 +01:00
|
|
|
end
|
|
|
|
chronology.reverse_each do |period|
|
2021-12-29 10:57:59 +01:00
|
|
|
# when the VAT rate was disabled, set the date it was disabled and rate=0
|
2021-12-23 19:36:23 +01:00
|
|
|
date_rates.push(date: period[:start], rate: 0) unless period[:enabled]
|
2021-12-23 09:25:48 +01:00
|
|
|
end
|
|
|
|
else
|
2021-12-29 10:57:59 +01:00
|
|
|
# if no VAT rate type is given, we return rate=0 from 0000-01-01
|
2021-12-23 19:36:23 +01:00
|
|
|
date_rates.push(date: chronology[-1][:start], rate: 0)
|
2019-09-18 13:28:53 +02:00
|
|
|
end
|
2021-12-29 10:57:59 +01:00
|
|
|
|
|
|
|
# finally, we return the chronology, sorted by dates (ascending)
|
2019-09-18 13:28:53 +02:00
|
|
|
date_rates.sort_by { |k| k[:date] }
|
2019-08-01 11:26:40 +02:00
|
|
|
end
|
2019-09-18 13:28:53 +02:00
|
|
|
end
|