diff --git a/app/controllers/admin/bank_statements_controller.rb b/app/controllers/admin/bank_statements_controller.rb index d7b6edae2..d7bb81fb1 100644 --- a/app/controllers/admin/bank_statements_controller.rb +++ b/app/controllers/admin/bank_statements_controller.rb @@ -24,7 +24,7 @@ module Admin @invoice = Invoice.find_by(id: params[:invoice_id]) @bank_transaction = @bank_statement.bank_transactions.build( description: @invoice.to_s, - sum: @invoice.sum, + sum: @invoice.amount, reference_no: @invoice.reference_no, paid_at: Time.zone.now.to_date, currency: 'EUR' diff --git a/app/controllers/registrar/invoices_controller.rb b/app/controllers/registrar/invoices_controller.rb index ac762e712..735df91a3 100644 --- a/app/controllers/registrar/invoices_controller.rb +++ b/app/controllers/registrar/invoices_controller.rb @@ -55,8 +55,8 @@ class Registrar end def normalize_search_parameters - params[:q][:sum_cache_gteq].gsub!(',', '.') if params[:q][:sum_cache_gteq] - params[:q][:sum_cache_lteq].gsub!(',', '.') if params[:q][:sum_cache_lteq] + params[:q][:total_gteq].gsub!(',', '.') if params[:q][:total_gteq] + params[:q][:total_lteq].gsub!(',', '.') if params[:q][:total_lteq] ca_cache = params[:q][:due_date_lteq] begin diff --git a/app/models/bank_link.rb b/app/models/bank_link.rb index 24c94a771..e388a0f8b 100644 --- a/app/models/bank_link.rb +++ b/app/models/bank_link.rb @@ -29,7 +29,7 @@ class BankLink hash["VK_VERSION"] = "008" hash["VK_SND_ID"] = ENV["payments_#{type}_seller_account"] hash["VK_STAMP"] = invoice.number - hash["VK_AMOUNT"] = number_with_precision(invoice.sum_cache, :precision => 2, :separator => ".") + hash["VK_AMOUNT"] = number_with_precision(invoice.total, :precision => 2, :separator => ".") hash["VK_CURR"] = invoice.currency hash["VK_REF"] = "" hash["VK_MSG"] = invoice.order @@ -140,7 +140,7 @@ class BankLink def validate_amount source = number_with_precision(BigDecimal.new(params["VK_AMOUNT"].to_s), precision: 2, separator: ".") - target = number_with_precision(invoice.sum_cache, precision: 2, separator: ".") + target = number_with_precision(invoice.total, precision: 2, separator: ".") source == target end diff --git a/app/models/bank_transaction.rb b/app/models/bank_transaction.rb index daf6abc29..3749f92b5 100644 --- a/app/models/bank_transaction.rb +++ b/app/models/bank_transaction.rb @@ -47,7 +47,7 @@ class BankTransaction < ActiveRecord::Base return if invoice.binded? return if invoice.cancelled? - return if invoice.sum != sum + return if invoice.total != sum create_activity(registrar, invoice) end # rubocop: enable Metrics/PerceivedComplexity @@ -76,7 +76,7 @@ class BankTransaction < ActiveRecord::Base return end - if invoice.sum != sum + if invoice.total != sum errors.add(:base, I18n.t('invoice_and_transaction_sums_do_not_match')) return end @@ -88,7 +88,7 @@ class BankTransaction < ActiveRecord::Base create_account_activity( account: registrar.cash_account, invoice: invoice, - sum: invoice.sum_without_vat, + sum: invoice.subtotal, currency: currency, description: description, activity_type: AccountActivity::ADD_CREDIT diff --git a/app/models/directo.rb b/app/models/directo.rb index f3a506ff3..2b794b0e4 100644 --- a/app/models/directo.rb +++ b/app/models/directo.rb @@ -15,7 +15,7 @@ class Directo < ActiveRecord::Base group.each do |invoice| if invoice.account_activity.nil? || invoice.account_activity.bank_transaction.nil? || - invoice.account_activity.bank_transaction.sum.nil? || invoice.account_activity.bank_transaction.sum != invoice.sum_cache + invoice.account_activity.bank_transaction.sum.nil? || invoice.account_activity.bank_transaction.sum != invoice.total Rails.logger.info("[DIRECTO] Invoice #{invoice.number} has been skipped") next end @@ -34,7 +34,7 @@ class Directo < ActiveRecord::Base xml.line( "ProductID" => Setting.directo_receipt_product_name, "Quantity" => 1, - "UnitPriceWoVAT" => ActionController::Base.helpers.number_with_precision(invoice.sum_cache/(1+invoice.vat_rate), precision: 2, separator: "."), + "UnitPriceWoVAT" => ActionController::Base.helpers.number_with_precision(invoice.total/(1+invoice.vat_rate), precision: 2, separator: "."), "ProductName" => invoice.order ) } diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 7dd8bbe67..19e25d5c9 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -34,6 +34,7 @@ class Invoice < ActiveRecord::Base before_create :set_invoice_number before_create :apply_default_vat_rate, unless: :vat_rate? + before_create :save_total attribute :vat_rate, ::Type::VATRate.new attr_readonly :vat_rate @@ -54,8 +55,6 @@ class Invoice < ActiveRecord::Base false end - before_save -> { self.sum_cache = sum } - class << self def cancel_overdue_invoices STDOUT << "#{Time.zone.now.utc} - Cancelling overdue invoices\n" unless Rails.env.test? @@ -150,17 +149,13 @@ class Invoice < ActiveRecord::Base invoice_items end - def sum_without_vat + def subtotal (items.map(&:item_sum_without_vat).sum).round(2) end def vat return 0 unless vat_rate - sum_without_vat * vat_rate / 100 - end - - def sum - (sum_without_vat + vat).round(2) + subtotal * vat_rate / 100 end private @@ -168,4 +163,8 @@ class Invoice < ActiveRecord::Base def apply_default_vat_rate self.vat_rate = buyer.effective_vat_rate end + + def calculate_total + # (sum_without_vat + vat).round(2) + end end diff --git a/app/views/registrar/invoices/index.haml b/app/views/registrar/invoices/index.haml index b8c825c36..61d955708 100644 --- a/app/views/registrar/invoices/index.haml +++ b/app/views/registrar/invoices/index.haml @@ -33,11 +33,11 @@ .col-md-3 .form-group = f.label t(:minimum_total) - = f.search_field :sum_cache_gteq, class: 'form-control', placeholder: t(:minimum_total), autocomplete: 'off' + = f.search_field :total_gteq, class: 'form-control', placeholder: t(:minimum_total), autocomplete: 'off' .col-md-3 .form-group = f.label t(:maximum_total) - = f.search_field :sum_cache_lteq, class: 'form-control', placeholder: t(:maximum_total), autocomplete: 'off' + = f.search_field :total_lteq, class: 'form-control', placeholder: t(:maximum_total), autocomplete: 'off' .col-md-3{style: 'padding-top: 25px;'} %button.btn.btn-default   @@ -67,7 +67,7 @@ %td{class: 'text-danger'}= t(:unpaid) %td= l(x.due_date, format: :date_long) - %td= currency(x.sum) + %td= currency(x.total) .row .col-md-12 = paginate @invoices diff --git a/app/views/registrar/invoices/partials/_items.haml b/app/views/registrar/invoices/partials/_items.haml index eef06c1ce..560b3e1f6 100644 --- a/app/views/registrar/invoices/partials/_items.haml +++ b/app/views/registrar/invoices/partials/_items.haml @@ -21,7 +21,7 @@ %tr %th{colspan: 3} %th= t(:total_without_vat) - %td= currency(@invoice.sum_without_vat) + %td= currency(@invoice.subtotal) %tr %th.no-border{colspan: 3} %th= t('vat', rate: number_to_percentage(@invoice.vat_rate, precision: 1)) @@ -29,4 +29,4 @@ %tr %th.no-border{colspan: 3} %th= t(:total) - %td= currency(@invoice.sum) + %td= currency(@invoice.total) diff --git a/app/views/registrar/invoices/pdf.haml b/app/views/registrar/invoices/pdf.haml index a5f035fe0..e59ca618b 100644 --- a/app/views/registrar/invoices/pdf.haml +++ b/app/views/registrar/invoices/pdf.haml @@ -239,7 +239,7 @@ %tr %th{colspan: 3} %th= t(:total_without_vat) - %td= "#{currency(@invoice.sum_without_vat)} #{@invoice.currency}" + %td= "#{currency(@invoice.subtotal)} #{@invoice.currency}" %tr %th.no-border{colspan: 3} %th= t('vat', rate: number_to_percentage(@invoice.vat_rate, precision: 1)) @@ -247,7 +247,7 @@ %tr %th.no-border{colspan: 3} %th= t(:total) - %td= "#{currency(@invoice.sum)} #{@invoice.currency}" + %td= "#{currency(@invoice.total)} #{@invoice.currency}" #footer %hr diff --git a/db/migrate/20180313090437_rename_invoices_sum_cache_to_total.rb b/db/migrate/20180313090437_rename_invoices_sum_cache_to_total.rb new file mode 100644 index 000000000..43e827dfc --- /dev/null +++ b/db/migrate/20180313090437_rename_invoices_sum_cache_to_total.rb @@ -0,0 +1,5 @@ +class RenameInvoicesSumCacheToTotal < ActiveRecord::Migration + def change + rename_column :invoices, :sum_cache, :total + end +end diff --git a/db/structure.sql b/db/structure.sql index d54caef91..6df03a91a 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1036,7 +1036,7 @@ CREATE TABLE invoices ( updator_str character varying, number integer, cancelled_at timestamp without time zone, - sum_cache numeric(10,2), + total numeric(10,2), in_directo boolean DEFAULT false ); @@ -4714,3 +4714,5 @@ INSERT INTO schema_migrations (version) VALUES ('20180309054510'); INSERT INTO schema_migrations (version) VALUES ('20180310142630'); +INSERT INTO schema_migrations (version) VALUES ('20180313090437'); + diff --git a/doc/models_complete.svg b/doc/models_complete.svg index b3194a90a..235aa433b 100644 --- a/doc/models_complete.svg +++ b/doc/models_complete.svg @@ -1651,7 +1651,7 @@ updator_str :string number :integer cancelled_at :datetime -sum_cache :decimal +total :decimal Registrar->Invoice diff --git a/test/fixtures/invoices.yml b/test/fixtures/invoices.yml index 6d1e0fc73..c395da425 100644 --- a/test/fixtures/invoices.yml +++ b/test/fixtures/invoices.yml @@ -7,6 +7,7 @@ DEFAULTS: &DEFAULTS buyer: bestnames buyer_name: Jane Doe vat_rate: 0.1 + total: 16.50 valid: <<: *DEFAULTS @@ -21,7 +22,7 @@ cancelled: paid: <<: *DEFAULTS - sum_cache: 1 + total: 1 outstanding: <<: *DEFAULTS diff --git a/test/integration/registrar/billing/balance_top_up_test.rb b/test/integration/registrar/billing/balance_top_up_test.rb index 36109e4c4..3c36b5f42 100644 --- a/test/integration/registrar/billing/balance_top_up_test.rb +++ b/test/integration/registrar/billing/balance_top_up_test.rb @@ -6,19 +6,20 @@ class BalanceTopUpTest < ActionDispatch::IntegrationTest end def test_creates_new_invoice + Setting.registry_vat_prc = 0.1 + visit registrar_invoices_url click_link_or_button 'Add deposit' fill_in 'Amount', with: '25.5' - Registry.instance.stub(:vat_rate, 10) do - assert_difference 'Invoice.count' do - click_link_or_button 'Add' - end + assert_difference 'Invoice.count' do + click_link_or_button 'Add' end invoice = Invoice.last - assert_equal BigDecimal('28.05'), invoice.sum_cache + assert_equal BigDecimal(10), invoice.vat_rate + assert_equal BigDecimal('28.05'), invoice.total assert_text 'Please pay the following invoice' end end diff --git a/test/models/invoice/vat_rate_test.rb b/test/models/invoice/vat_rate_test.rb deleted file mode 100644 index d1e892b72..000000000 --- a/test/models/invoice/vat_rate_test.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'test_helper' - -class InvoiceVATRateTest < ActiveSupport::TestCase - def setup - @invoice = invoices(:valid) - end - - def test_optional_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) - invoice = @invoice.dup - invoice.vat_rate = nil - invoice.buyer = registrar - invoice.invoice_items = @invoice.invoice_items - - registrar.stub(:effective_vat_rate, BigDecimal(55)) do - invoice.save! - end - - assert_equal BigDecimal(55), invoice.vat_rate - end - - def test_vat_rate_cannot_be_updated - @invoice.vat_rate = BigDecimal(21) - @invoice.save! - @invoice.reload - refute_equal BigDecimal(21), @invoice.vat_rate - end -end diff --git a/test/models/invoice_test.rb b/test/models/invoice_test.rb index f7f2900aa..fb7e66821 100644 --- a/test/models/invoice_test.rb +++ b/test/models/invoice_test.rb @@ -9,15 +9,81 @@ class InvoiceTest < ActiveSupport::TestCase assert @invoice.valid? end - def test_calculates_subtotal - assert_equal BigDecimal('15'), @invoice.sum_without_vat + def test_optional_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) + invoice = @invoice.dup + invoice.vat_rate = nil + invoice.buyer = registrar + invoice.invoice_items = @invoice.invoice_items + + registrar.stub(:effective_vat_rate, BigDecimal(55)) do + invoice.save! + end + + assert_equal BigDecimal(55), invoice.vat_rate + end + + def test_vat_rate_cannot_be_updated + @invoice.vat_rate = BigDecimal(21) + @invoice.save! + @invoice.reload + refute_equal BigDecimal(21), @invoice.vat_rate end def test_calculates_vat_amount assert_equal BigDecimal('1.5'), @invoice.vat end + def test_vat_amount_is_zero_when_vat_rate_is_blank + @invoice.vat_rate = nil + assert_equal 0, @invoice.vat + end + + def test_calculates_subtotal + line_item = InvoiceItem.new + invoice = Invoice.new(invoice_items: [line_item, line_item]) + + line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do + assert_equal BigDecimal(5), invoice.subtotal + end + end + def test_calculates_total - assert_equal BigDecimal('16.5'), @invoice.sum + line_item = InvoiceItem.new + invoice = Invoice.new + invoice.vat_rate = 10 + invoice.invoice_items = [line_item, line_item] + + line_item.stub(:item_sum_without_vat, BigDecimal('2.5')) do + assert_equal BigDecimal('5.50'), invoice.total + end end end