From bf7300b9055e29d60eb564f109b30296afb67929 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Tue, 2 Jan 2024 15:19:44 +0200 Subject: [PATCH 1/4] changed vat rate calculation logic --- Gemfile | 8 +++-- Gemfile.lock | 26 ++++++++++++++ app/models/invoice.rb | 33 ++++++++--------- app/models/invoice_creator.rb | 48 +++++++++++++------------ lib/tasks/assign_invoices_vat_rate.rake | 19 ++++++++++ test/fixtures/invoices.yml | 2 ++ test/models/invoice_creator_test.rb | 39 ++++++++++++++++++++ 7 files changed, 132 insertions(+), 43 deletions(-) create mode 100644 lib/tasks/assign_invoices_vat_rate.rake diff --git a/Gemfile b/Gemfile index ca9dd8c45..5b7598fb9 100644 --- a/Gemfile +++ b/Gemfile @@ -26,14 +26,12 @@ gem 'pg', '>= 0.18', '< 2.0' gem 'puma', '~> 6.4.0' gem 'rails', '>= 6.0.3.5' gem 'rails-i18n' -# gem 'rails_semantic_logger' gem 'recaptcha' gem 'ruby-openai' gem 'scenic' gem 'simpleidn' gem 'skylight' gem 'sprockets', '~> 4.0' -# gem 'turbolinks', '~> 5' gem 'turbo-rails' gem 'webpacker', '~> 6.0.0.rc.5' gem 'webpush' @@ -49,6 +47,12 @@ group :development, :test do # https://github.com/rubocop/rubocop-performance gem 'rubocop-performance', require: false + gem "ruby-lsp" + gem "rubocop" + gem "rubocop-packaging" + gem "rubocop-rspec" + gem "rubocop-shopify" + gem "rubocop-thread_safety" end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 170b56902..14635b3d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -264,6 +264,7 @@ GEM pg_search (2.3.6) activerecord (>= 5.2) activesupport (>= 5.2) + prism (0.19.0) pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) @@ -346,9 +347,27 @@ GEM unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.29.0) parser (>= 3.2.1.0) + rubocop-capybara (2.19.0) + rubocop (~> 1.41) + rubocop-factory_bot (2.24.0) + rubocop (~> 1.33) + rubocop-packaging (0.5.2) + rubocop (>= 1.33, < 2.0) rubocop-performance (1.18.0) rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) + rubocop-rspec (2.25.0) + rubocop (~> 1.40) + rubocop-capybara (~> 2.17) + rubocop-factory_bot (~> 2.22) + rubocop-shopify (2.14.0) + rubocop (~> 1.51) + rubocop-thread_safety (0.5.1) + rubocop (>= 0.90.0) + ruby-lsp (0.13.2) + language_server-protocol (~> 3.17.0) + prism (>= 0.19.0, < 0.20) + sorbet-runtime (>= 0.5.5685) ruby-openai (4.2.0) faraday (>= 1) faraday-multipart (>= 1) @@ -372,6 +391,7 @@ GEM unf (~> 0.1.4) skylight (5.3.4) activesupport (>= 5.2.0) + sorbet-runtime (0.5.11164) sprockets (4.2.0) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) @@ -474,7 +494,13 @@ DEPENDENCIES rails-i18n recaptcha redis (~> 5.0) + rubocop + rubocop-packaging rubocop-performance + rubocop-rspec + rubocop-shopify + rubocop-thread_safety + ruby-lsp ruby-openai scenic selenium-webdriver diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 2925c5ca6..ae28071e7 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -30,12 +30,11 @@ class Invoice < ApplicationRecord before_update :update_billing_info before_create :set_invoice_number + before_update :recalculate_vat_rate delegate :enable_deposit?, to: :enable_deposit? delegate :deposit, to: :deposit - attr_accessor :vat_rate - scope :with_search_scope, (lambda do |origin| if origin.present? if numeric?(origin) @@ -118,6 +117,20 @@ def deposit result.auction.deposit end + def recalculate_vat_rate + return if billing_profile_id == billing_profile_id_was + + self.vat_rate = assign_vat_rate + end + + def assign_vat_rate + return BigDecimal(Setting.find_by(code: :estonian_vat_rate).retrieve, 2) if country_code == 'EE' + + return BigDecimal('0') if vat_code.present? + + Countries.vat_rate_from_alpha2_code(country_code) + end + def billing_restrictions_issue errors.add(:base, I18n.t('cannot get access')) logger.error('PROBLEM WITH TOKEN') @@ -190,22 +203,6 @@ def address [street, postal_code_with_city, country_name].compact.join(', ') end - def vat_rate - return tax_fresh_rate if country_code == 'EE' - - return BigDecimal('0') if vat_code.present? - - Countries.vat_rate_from_alpha2_code(country_code) - end - - def tax_fresh_rate - if created_at.year < 2024 - BigDecimal(OLD_EST_RATE_VAT) - else - BigDecimal(Setting.find_by(code: :estonian_vat_rate).retrieve, 2) - end - end - def filename return unless title diff --git a/app/models/invoice_creator.rb b/app/models/invoice_creator.rb index 16a8ca996..4c3f9ffb0 100644 --- a/app/models/invoice_creator.rb +++ b/app/models/invoice_creator.rb @@ -1,7 +1,5 @@ class InvoiceCreator - attr_reader :result_id - attr_reader :result - attr_reader :invoice + attr_reader :result_id, :result, :invoice def initialize(result_id) @result_id = result_id @@ -45,7 +43,7 @@ def assign_invoice_associations end def send_invoice_to_billing_system(invoice) - response = EisBilling::Invoice.call(invoice: invoice) + response = EisBilling::Invoice.call(invoice:) if response.result? link = response.instance['everypay_link'] invoice.update(payment_link: link) @@ -56,14 +54,7 @@ def send_invoice_to_billing_system(invoice) def assign_price invoice.cents = result_offer.cents - invoice.invoice_items = [ - InvoiceItem.new(invoice: invoice, - cents: result_offer.cents, - name: I18n.t('invoice_items.name', - domain_name: result_auction.domain_name, - auction_end: result_auction.ends_at.to_date, - locale: I18n.default_locale)), - ] + invoice.invoice_items = [assign_invoice_item] end def assign_billing_address @@ -86,6 +77,7 @@ def create_invoice ActiveRecord::Base.transaction do assign_invoice_associations + invoice.vat_rate = assign_vat_rate result_auction.enable_deposit ? assign_price_with_deposit : assign_price set_issue_and_due_date assign_billing_address @@ -95,18 +87,17 @@ def create_invoice end def assign_price_with_deposit - # total = result_offer.cents - result_auction.requirement_deposit_in_cents - - # invoice.cents = total invoice.cents = result_offer.cents - invoice.invoice_items = [ - InvoiceItem.new(invoice: invoice, - cents: result_offer.cents, - name: I18n.t('invoice_items.name', - domain_name: result_auction.domain_name, - auction_end: result_auction.ends_at.to_date, - locale: I18n.default_locale)), - ] + invoice.invoice_items = [assign_invoice_item] + end + + def assign_invoice_item + InvoiceItem.new(invoice:, + cents: result_offer.cents, + name: I18n.t('invoice_items.name', + domain_name: result_auction.domain_name, + auction_end: result_auction.ends_at.to_date, + locale: I18n.default_locale)) end def mark_as_paid_if_sum_is_zero @@ -114,4 +105,15 @@ def mark_as_paid_if_sum_is_zero invoice.mark_as_paid_at(Time.zone.now) end + + def assign_vat_rate + if invoice.billing_alpha_two_country_code == 'EE' + return BigDecimal(Setting.find_by(code: :estonian_vat_rate).retrieve, + 2) + end + + return BigDecimal('0') if invoice.vat_code.present? + + Countries.vat_rate_from_alpha2_code(invoice.billing_alpha_two_country_code) + end end diff --git a/lib/tasks/assign_invoices_vat_rate.rake b/lib/tasks/assign_invoices_vat_rate.rake new file mode 100644 index 000000000..1d23c1131 --- /dev/null +++ b/lib/tasks/assign_invoices_vat_rate.rake @@ -0,0 +1,19 @@ +namespace :invoices do + desc 'Assign vat rate to invoices what have vat rate of nil' + task assign_invoices_vat_rate: :environment do + Invoice.where(vat_rate: nil, country_code: 'EE', vat_code: nil).in_batches do |batch_invoices| + batch_invoices.where('created_at < ?', '2024-01-01').update_all(vat_rate: 0.2) + batch_invoices.where('created_at >= ?', '2024-01-01').update_all(vat_rate: 0.22) + end + + Invoice.where.not(country_code: 'EE').where(vat_rate: nil).in_batches do |batch_invoices| + batch_invoices.each do |invoice| + invoice.update(vat_rate: Countries.vat_rate_from_alpha2_code(invoice.country_code)) + end + end + + Invoice.where(vat_rate: nil).where.not(vat_code: nil).in_batches do |batch_invoices| + batch_invoices.update_all(vat_rate: 0.0) + end + end +end diff --git a/test/fixtures/invoices.yml b/test/fixtures/invoices.yml index cdf7e6cab..2312f741f 100644 --- a/test/fixtures/invoices.yml +++ b/test/fixtures/invoices.yml @@ -20,6 +20,7 @@ payable: billing_address: "Baker Street 221B, NW1 6XE London, United Kingdom" billing_vat_code: "12234567890" billing_alpha_two_country_code: "GB" + vat_rate: 0.0 orphaned: result: orphaned @@ -39,3 +40,4 @@ orphaned: billing_name: "Orphan Profile" billing_address: "Baker Street 221B, NW1 6XE London, United Kingdom" billing_alpha_two_country_code: "GB" + vat_rate: 0.0 diff --git a/test/models/invoice_creator_test.rb b/test/models/invoice_creator_test.rb index 82b3b0e74..17fb7a14a 100644 --- a/test/models/invoice_creator_test.rb +++ b/test/models/invoice_creator_test.rb @@ -267,4 +267,43 @@ def test_should_be_assigned_billing_profile_information assert_equal result.invoice.billing_vat_code, @billing_company.vat_code assert_equal result.invoice.billing_alpha_two_country_code, @billing_company.country_code end + + def test_should_be_assigned_estonian_vat_rate + offer_bid_value = 10_000 + + user = users(:participant) + auction = auctions(:english) + + mid_day = Time.new(Time.now.year, Time.now.month, Time.now.day, 12, 0, 0) + auction.update(starts_at: mid_day - 1.day, ends_at: Time.zone.now + 10.minutes) + auction.reload + assert auction.offers.empty? + + billing_profile = user.billing_profiles.first + billing_profile.update!(country_code: 'EE', alpha_two_country_code: 'EE', vat_code: 'IE6388047V') && billing_profile.reload + + Offer.create!( + auction: auction, + user: user, + cents: offer_bid_value, + billing_profile: billing_profile + ) + + assert auction.offers.present? + auction.update(ends_at: Time.zone.now - 1.minute) && auction.reload + + ResultCreationJob.perform_now + auction.reload + + result = Result.last + assert_equal result.auction.domain_name, auction.domain_name + assert_equal result.invoice.status, 'issued' + + assert_equal billing_profile.country_code, 'EE' + assert_equal result.invoice.billing_vat_code, billing_profile.vat_code + assert_equal result.invoice.billing_alpha_two_country_code, billing_profile.country_code + + assert_equal result.invoice.vat_rate, BigDecimal(Setting.find_by(code: :estonian_vat_rate).retrieve, 2) + assert_equal result.invoice.vat_rate, 0.22 + end end From 5f5f833593b7840c5b15c16aab8e81c5e5cd120f Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Wed, 3 Jan 2024 11:15:09 +0200 Subject: [PATCH 2/4] allowed recalculate tax only for payable invoices, updated rake task --- app/models/invoice.rb | 1 + lib/tasks/assign_invoices_vat_rate.rake | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/models/invoice.rb b/app/models/invoice.rb index ae28071e7..ebc87287b 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -119,6 +119,7 @@ def deposit def recalculate_vat_rate return if billing_profile_id == billing_profile_id_was + return unless payable? self.vat_rate = assign_vat_rate end diff --git a/lib/tasks/assign_invoices_vat_rate.rake b/lib/tasks/assign_invoices_vat_rate.rake index 1d23c1131..edabfb37c 100644 --- a/lib/tasks/assign_invoices_vat_rate.rake +++ b/lib/tasks/assign_invoices_vat_rate.rake @@ -6,14 +6,14 @@ namespace :invoices do batch_invoices.where('created_at >= ?', '2024-01-01').update_all(vat_rate: 0.22) end + Invoice.where(vat_rate: nil).where.not(vat_code: nil).in_batches do |batch_invoices| + batch_invoices.update_all(vat_rate: 0.0) + end + Invoice.where.not(country_code: 'EE').where(vat_rate: nil).in_batches do |batch_invoices| batch_invoices.each do |invoice| invoice.update(vat_rate: Countries.vat_rate_from_alpha2_code(invoice.country_code)) end end - - Invoice.where(vat_rate: nil).where.not(vat_code: nil).in_batches do |batch_invoices| - batch_invoices.update_all(vat_rate: 0.0) - end end end From 505f2e448ad483726825d26e9cf087470c17710c Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Wed, 3 Jan 2024 12:23:44 +0200 Subject: [PATCH 3/4] added invoice updater in billing side when billing profile has been changed --- app/models/invoice.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/invoice.rb b/app/models/invoice.rb index ebc87287b..9dc446b07 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -27,9 +27,10 @@ class Invoice < ApplicationRecord validates :billing_profile, presence: true, on: :create validate :user_id_must_be_the_same_as_on_billing_profile_or_nil - before_update :update_billing_info before_create :set_invoice_number + + before_update :update_billing_info before_update :recalculate_vat_rate delegate :enable_deposit?, to: :enable_deposit? @@ -84,7 +85,7 @@ def self.search(params = {}) when 'channel' query.left_outer_joins(:paid_with_payment_order) .select("invoices.*, REPLACE(payment_orders.type, 'PaymentOrders::', '') AS payment_order_channel") - .order(Arel.sql("payment_order_channel #{sort_direction} NULLS LAST")) + .order(Arel.sql("payment_order_channel #{sort_direction} NULLS LAST")) when 'billing_profile_name' query.left_outer_joins(:billing_profile).order("billing_profiles.name #{sort_direction}") when 'total' @@ -122,6 +123,8 @@ def recalculate_vat_rate return unless payable? self.vat_rate = assign_vat_rate + + send_updated_invoice_infromation_to_billing_service end def assign_vat_rate From 1024b929be2b8647efef26c83de1f86a0c59ceb2 Mon Sep 17 00:00:00 2001 From: Oleg Hasjanov Date: Mon, 22 Jan 2024 13:15:54 +0200 Subject: [PATCH 4/4] updated condition for rake task --- lib/tasks/assign_invoices_vat_rate.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/assign_invoices_vat_rate.rake b/lib/tasks/assign_invoices_vat_rate.rake index edabfb37c..6a216d471 100644 --- a/lib/tasks/assign_invoices_vat_rate.rake +++ b/lib/tasks/assign_invoices_vat_rate.rake @@ -1,7 +1,7 @@ namespace :invoices do desc 'Assign vat rate to invoices what have vat rate of nil' task assign_invoices_vat_rate: :environment do - Invoice.where(vat_rate: nil, country_code: 'EE', vat_code: nil).in_batches do |batch_invoices| + Invoice.where(vat_rate: [nil, 0.0], country_code: 'EE').in_batches do |batch_invoices| batch_invoices.where('created_at < ?', '2024-01-01').update_all(vat_rate: 0.2) batch_invoices.where('created_at >= ?', '2024-01-01').update_all(vat_rate: 0.22) end