diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 165b7f614..d78c24d07 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -32,9 +32,11 @@ class Invoice < ActiveRecord::Base validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 }, allow_nil: true - before_create :set_invoice_number, :check_vat + after_initialize :apply_defaults + before_create :set_invoice_number - before_save :check_vat + attribute :vat_rate, ::Type::VATRate.new + attr_readonly :vat_rate def set_invoice_number last_no = Invoice.order(number: :desc).where('number IS NOT NULL').limit(1).pluck(:number).first @@ -52,12 +54,6 @@ class Invoice < ActiveRecord::Base false end - def check_vat - if buyer.country_code != 'EE' && buyer.vat_no.present? - self.vat_rate = 0 - end - end - before_save -> { self.sum_cache = sum } class << self @@ -159,10 +155,17 @@ class Invoice < ActiveRecord::Base end def vat + return 0 unless vat_rate (sum_without_vat * vat_rate).round(2) end def sum (sum_without_vat + vat).round(2) end + + private + + def apply_defaults + self.vat_rate = buyer.effective_vat_rate unless vat_rate + end end diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 0f9cdae06..9e7d84a7b 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -18,8 +18,8 @@ class Registrar < ActiveRecord::Base validates :accounting_customer_code, presence: true validates :language, presence: true - validates :vat_rate, presence: true, if: :vat_rate_required? - validates :vat_rate, absence: true, if: :local_vat_payer? + validates :vat_rate, presence: true, if: 'foreign_vat_payer? && vat_no.blank?' + validates :vat_rate, absence: true, if: :home_vat_payer? validates :vat_rate, absence: true, if: 'foreign_vat_payer? && vat_no?' validates :vat_rate, numericality: { greater_than_or_equal_to: 0, less_than: 100 }, allow_nil: true @@ -56,22 +56,11 @@ class Registrar < ActiveRecord::Base # rubocop:disable Metrics/MethodLength # rubocop:disable Metrics/AbcSize def issue_prepayment_invoice(amount, description = nil) - vat_rate = if local_vat_payer? - Registry.instance.vat_rate - else - if vat_no.blank? - self.vat_rate - else - nil - end - end - invoices.create( due_date: (Time.zone.now.to_date + Setting.days_to_keep_invoices_active.days).end_of_day, payment_term: 'prepayment', description: description, currency: 'EUR', - vat_rate: vat_rate, seller_name: Setting.registry_juridical_name, seller_reg_no: Setting.registry_reg_no, seller_iban: Setting.registry_iban, @@ -157,6 +146,14 @@ class Registrar < ActiveRecord::Base end end + def effective_vat_rate + if home_vat_payer? + Registry.instance.vat_rate + else + vat_rate + end + end + private def set_defaults @@ -188,15 +185,11 @@ class Registrar < ActiveRecord::Base end end - def local_vat_payer? + def home_vat_payer? country == Registry.instance.legal_address_country end def foreign_vat_payer? - !local_vat_payer? - end - - def vat_rate_required? - foreign_vat_payer? && vat_no.blank? + !home_vat_payer? end end diff --git a/app/models/type/vat_rate.rb b/app/models/type/vat_rate.rb index 466b076f8..5ee993211 100644 --- a/app/models/type/vat_rate.rb +++ b/app/models/type/vat_rate.rb @@ -1,19 +1,11 @@ module Type - class VATRate < ActiveRecord::Type::Value - def type_cast_from_user(value) - if value.blank? - nil - else - super - end - end - + class VATRate < ActiveRecord::Type::Decimal def type_cast_from_database(value) - BigDecimal(value) * 100 if value + super * 100 if value end def type_cast_for_database(value) - BigDecimal(value) / 100.0 if value + super / 100.0 if value end end end diff --git a/test/fixtures/invoices.yml b/test/fixtures/invoices.yml index 6fbfa282b..ffb53f938 100644 --- a/test/fixtures/invoices.yml +++ b/test/fixtures/invoices.yml @@ -4,6 +4,7 @@ DEFAULTS: &DEFAULTS currency: EUR seller_name: John Doe seller_iban: 1234 + buyer: bestnames buyer_name: Jane Doe vat_rate: 0.2 diff --git a/test/fixtures/registrars.yml b/test/fixtures/registrars.yml index b0cc371a7..a0faee8b4 100644 --- a/test/fixtures/registrars.yml +++ b/test/fixtures/registrars.yml @@ -17,7 +17,8 @@ goodnames: reg_no: 12345 code: goodnames email: info@goodnames.test - country_code: US + country_code: DE + vat_no: DE123456789 accounting_customer_code: goodnames language: en diff --git a/test/models/invoice/vat_rate_test.rb b/test/models/invoice/vat_rate_test.rb new file mode 100644 index 000000000..cb2bd9f19 --- /dev/null +++ b/test/models/invoice/vat_rate_test.rb @@ -0,0 +1,51 @@ +require 'test_helper' + +class InvoiceVATRateTest < ActiveSupport::TestCase + def setup + @invoice = invoices(:valid) + end + + def test_valid_without_vat_rate + @invoice.vat_rate = nil + assert @invoice.valid? + end + + def test_vat_rate_validation + @invoice.vat_rate = -1 + assert @invoice.invalid? + + @invoice.vat_rate = 0 + assert @invoice.valid? + + @invoice.vat_rate = 99.9 + assert @invoice.valid? + + @invoice.vat_rate = 100 + assert @invoice.invalid? + end + + def test_serializes_and_deserializes_vat_rate + invoice = @invoice.dup + invoice.invoice_items = @invoice.invoice_items + invoice.vat_rate = BigDecimal('25.5') + invoice.save! + invoice.reload + assert_equal BigDecimal('25.5'), invoice.vat_rate + end + + def test_vat_rate_defaults_to_effective_vat_rate_of_a_registrar + registrar = registrars(:bestnames) + + registrar.stub(:effective_vat_rate, 55) do + invoice = Invoice.new(buyer: registrar) + assert_equal 55, invoice.vat_rate + end + end + + def test_vat_rate_cannot_be_updated + @invoice.vat_rate = 21 + @invoice.save! + @invoice.reload + refute_equal 21, @invoice.vat_rate + end +end diff --git a/test/models/invoice_test.rb b/test/models/invoice_test.rb index 4a2457be3..29af6fab8 100644 --- a/test/models/invoice_test.rb +++ b/test/models/invoice_test.rb @@ -8,23 +8,4 @@ class InvoiceTest < ActiveSupport::TestCase def test_valid assert @invoice.valid? end - - def test_valid_without_vat_rate - @invoice.vat_rate = nil - assert @invoice.valid? - end - - def test_vat_rate_validation - @invoice.vat_rate = -1 - assert @invoice.invalid? - - @invoice.vat_rate = 1 - assert @invoice.valid? - - @invoice.vat_rate = 99.9 - assert @invoice.valid? - - @invoice.vat_rate = 100 - assert @invoice.invalid? - end end diff --git a/test/models/registrar/vat_test.rb b/test/models/registrar/vat_test.rb index cf36b6266..802a0d987 100644 --- a/test/models/registrar/vat_test.rb +++ b/test/models/registrar/vat_test.rb @@ -13,28 +13,6 @@ class RegistrarVATTest < ActiveSupport::TestCase assert @registrar.valid? end - def test_requires_vat_rate_when_registrar_is_foreign_vat_payer_and_vat_no_is_absent - @registrar.vat_no = '' - - Registry.instance.stub(:legal_address_country, Country.new('GB')) do - @registrar.vat_rate = '' - assert @registrar.invalid? - assert @registrar.errors.added?(:vat_rate, :blank) - - @registrar.vat_rate = -1 - assert @registrar.invalid? - - @registrar.vat_rate = 1 - assert @registrar.valid? - - @registrar.vat_rate = 99.9 - assert @registrar.valid? - - @registrar.vat_rate = 100 - assert @registrar.invalid? - end - end - def test_vat_is_not_applied_when_registrar_is_local_vat_payer @registrar.vat_rate = 1 assert @registrar.invalid? @@ -43,30 +21,57 @@ class RegistrarVATTest < ActiveSupport::TestCase assert @registrar.valid? end + def test_requires_vat_rate_when_registrar_is_foreign_vat_payer_and_vat_no_is_absent + @registrar.country_code = 'DE' + @registrar.vat_no = '' + + @registrar.vat_rate = '' + assert @registrar.invalid? + assert @registrar.errors.added?(:vat_rate, :blank) + end + def test_vat_is_not_applied_when_registrar_is_foreign_vat_payer_and_vat_no_is_present + @registrar.country_code = 'DE' @registrar.vat_no = 'valid' - Registry.instance.stub(:legal_address_country, Country.new('GB')) do - @registrar.vat_rate = 1 - assert @registrar.invalid? + @registrar.vat_rate = 1 + assert @registrar.invalid? - @registrar.vat_rate = nil - assert @registrar.valid? - end + @registrar.vat_rate = nil + assert @registrar.valid? + end + + def test_vat_rate_validation + @registrar.country_code = 'DE' + @registrar.vat_no = '' + + @registrar.vat_rate = -1 + assert @registrar.invalid? + + @registrar.vat_rate = 0 + assert @registrar.valid? + + @registrar.vat_rate = 99.9 + assert @registrar.valid? + + @registrar.vat_rate = 100 + assert @registrar.invalid? end def test_serializes_and_deserializes_vat_rate - @registrar.vat_rate = '25.5' - - Registry.instance.stub(:legal_address_country, Country.new('GB')) do - @registrar.save! - end - + @registrar.country_code = 'DE' + @registrar.vat_rate = BigDecimal('25.5') + @registrar.save! @registrar.reload - assert_equal 25.5, @registrar.vat_rate + assert_equal BigDecimal('25.5'), @registrar.vat_rate end - def test_treats_empty_vat_rate_as_absent + def test_parses_vat_rate_as_a_string + @registrar.vat_rate = '25.5' + assert_equal BigDecimal('25.5'), @registrar.vat_rate + end + + def test_treats_empty_vat_rate_as_nil @registrar.vat_rate = '' assert_nil @registrar.vat_rate end