From 2663c550fa1aee229679e9d407b12b5a2a5c0369 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 4 Feb 2020 16:00:24 +0500 Subject: [PATCH 1/4] Add idempotent Que job for e-invoice sending --- app/jobs/send_e_invoice_job.rb | 39 +++++++++++++++++++ ...103125_add_e_invoice_sent_at_to_invoice.rb | 5 +++ db/structure.sql | 4 +- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20200204103125_add_e_invoice_sent_at_to_invoice.rb diff --git a/app/jobs/send_e_invoice_job.rb b/app/jobs/send_e_invoice_job.rb index e69de29bb..9e8af7c65 100644 --- a/app/jobs/send_e_invoice_job.rb +++ b/app/jobs/send_e_invoice_job.rb @@ -0,0 +1,39 @@ +class SendEInvoiceJob < Que::Job + + def run(invoice) + return if invoice.e_invoice_sent_at + + e_invoice = invoice.to_e_invoice + e_invoice.deliver + + ActiveRecord::Base.transaction do + invoice.update(e_invoice_sent_at: Time.zone.now) + log_success(invoice) + destroy + end + + rescue Savon::Error => e + log_error(invoice: invoice, error: e) + end + + private + + def log_success(invoice) + message = "E-Invoice for an invoice with ID # #{invoice.id} was sent successfully" + logger.info message + end + + def log_error(invoice:, error:) + message = <<~TEXT.squish + There was an error sending e-invoice for invoice with ID # #{invoice.id}. + The error message was the following: #{error}. + This job will retry + TEXT + logger.error message + end + + def logger + Rails.logger + end + +end diff --git a/db/migrate/20200204103125_add_e_invoice_sent_at_to_invoice.rb b/db/migrate/20200204103125_add_e_invoice_sent_at_to_invoice.rb new file mode 100644 index 000000000..e0e5f2cd0 --- /dev/null +++ b/db/migrate/20200204103125_add_e_invoice_sent_at_to_invoice.rb @@ -0,0 +1,5 @@ +class AddEInvoiceSentAtToInvoice < ActiveRecord::Migration[5.0] + def change + add_column :invoices, :e_invoice_sent_at, :datetime + end +end diff --git a/db/structure.sql b/db/structure.sql index a23623bae..cd2998c07 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -886,6 +886,7 @@ CREATE TABLE public.invoices ( in_directo boolean DEFAULT false, buyer_vat_no character varying, issue_date date NOT NULL, + e_invoice_sent_at timestamp without time zone, CONSTRAINT invoices_due_date_is_not_before_issue_date CHECK ((due_date >= issue_date)) ); @@ -4339,6 +4340,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20191212133136'), ('20191227110904'), ('20200113091254'), -('20200115102202'); +('20200115102202'), +('20200204103125'); From 47e601f3cdce75e1ce5e5f362cb9406c6a8cd33f Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 4 Feb 2020 16:20:07 +0500 Subject: [PATCH 2/4] Add test to check if job works --- app/jobs/send_e_invoice_job.rb | 9 ++---- app/models/registrar.rb | 3 +- test/jobs/send_e_invoice_job_test.rb | 45 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 test/jobs/send_e_invoice_job_test.rb diff --git a/app/jobs/send_e_invoice_job.rb b/app/jobs/send_e_invoice_job.rb index 9e8af7c65..36e024b1d 100644 --- a/app/jobs/send_e_invoice_job.rb +++ b/app/jobs/send_e_invoice_job.rb @@ -1,19 +1,17 @@ class SendEInvoiceJob < Que::Job - def run(invoice) return if invoice.e_invoice_sent_at - e_invoice = invoice.to_e_invoice - e_invoice.deliver + invoice.to_e_invoice.deliver ActiveRecord::Base.transaction do invoice.update(e_invoice_sent_at: Time.zone.now) log_success(invoice) destroy end - - rescue Savon::Error => e + rescue StandardError => e log_error(invoice: invoice, error: e) + raise e end private @@ -35,5 +33,4 @@ class SendEInvoiceJob < Que::Job def logger Rails.logger end - end diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 88aa1c629..94b01517e 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -100,8 +100,7 @@ class Registrar < ApplicationRecord ] ) - e_invoice = invoice.to_e_invoice - e_invoice.deliver + SendEInvoiceJob.enqueue(invoice) invoice end diff --git a/test/jobs/send_e_invoice_job_test.rb b/test/jobs/send_e_invoice_job_test.rb new file mode 100644 index 000000000..5ea09e576 --- /dev/null +++ b/test/jobs/send_e_invoice_job_test.rb @@ -0,0 +1,45 @@ +require 'test_helper' + +class SendEInvoiceJobTest < ActiveSupport::TestCase + + def teardown + EInvoice.provider = EInvoice::Providers::TestProvider.new + EInvoice::Providers::TestProvider.deliveries.clear + end + + def test_if_invoice_is_sended + @invoice = invoices(:one) + EInvoice.provider = EInvoice::Providers::TestProvider.new + EInvoice::Providers::TestProvider.deliveries.clear + + assert_nothing_raised do + SendEInvoiceJob.enqueue(@invoice) + end + + assert_not @invoice.e_invoice_sent_at.blank? + assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count + end + + def test_if_invoice_sending_retries + @invoice = invoices(:one) + provider_config = { password: nil, + test_mode: true } + EInvoice.provider = EInvoice::Providers::OmnivaProvider.new(provider_config) + stub_request(:get, "https://testfinance.post.ee/finance/erp/erpServices.wsdl").to_timeout + + assert_raise HTTPClient::TimeoutError do + SendEInvoiceJob.enqueue(@invoice) + end + assert @invoicee_invoice_sent_at.blank? + + EInvoice.provider = EInvoice::Providers::TestProvider.new + EInvoice::Providers::TestProvider.deliveries.clear + + assert_nothing_raised do + SendEInvoiceJob.enqueue(@invoice) + end + + assert_not @invoice.e_invoice_sent_at.blank? + assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count + end +end From 187ce318a221681928e7fd3366253d134cc0803a Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 5 Feb 2020 14:24:09 +0500 Subject: [PATCH 3/4] Destroy e-invoice sending job if invoice sent, cancelled or paid --- app/jobs/send_e_invoice_job.rb | 10 ++++++---- app/models/invoice.rb | 10 +++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/jobs/send_e_invoice_job.rb b/app/jobs/send_e_invoice_job.rb index 36e024b1d..6e7b5edb8 100644 --- a/app/jobs/send_e_invoice_job.rb +++ b/app/jobs/send_e_invoice_job.rb @@ -1,6 +1,6 @@ class SendEInvoiceJob < Que::Job def run(invoice) - return if invoice.e_invoice_sent_at + destroy if invoice.do_not_send_e_invoice? invoice.to_e_invoice.deliver @@ -9,7 +9,7 @@ class SendEInvoiceJob < Que::Job log_success(invoice) destroy end - rescue StandardError => e + rescue Exception => e log_error(invoice: invoice, error: e) raise e end @@ -17,13 +17,15 @@ class SendEInvoiceJob < Que::Job private def log_success(invoice) - message = "E-Invoice for an invoice with ID # #{invoice.id} was sent successfully" + id = invoice.try(:id) || invoice + message = "E-Invoice for an invoice with ID # #{id} was sent successfully" logger.info message end def log_error(invoice:, error:) + id = invoice.try(:id) || invoice message = <<~TEXT.squish - There was an error sending e-invoice for invoice with ID # #{invoice.id}. + There was an error sending e-invoice for invoice with ID # #{id}. The error message was the following: #{error}. This job will retry TEXT diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 7f1dea825..4b35b71fb 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -102,6 +102,14 @@ class Invoice < ApplicationRecord generator.generate end + def do_not_send_e_invoice? + e_invoice_sent? || cancelled? || paid? + end + + def e_invoice_sent? + e_invoice_sent_at.present? + end + private def apply_default_buyer_vat_no @@ -111,4 +119,4 @@ class Invoice < ApplicationRecord def calculate_total self.total = subtotal + vat_amount end -end \ No newline at end of file +end From 1d6040cd5bdf8c0a6ee02b4a686f42a01a6041a3 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Wed, 19 Feb 2020 17:47:13 +0500 Subject: [PATCH 4/4] Fix async que job calling --- app/jobs/send_e_invoice_job.rb | 17 +++++++++++------ app/models/registrar.rb | 3 +-- test/jobs/send_e_invoice_job_test.rb | 8 +++++--- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/jobs/send_e_invoice_job.rb b/app/jobs/send_e_invoice_job.rb index 6e7b5edb8..e281db14d 100644 --- a/app/jobs/send_e_invoice_job.rb +++ b/app/jobs/send_e_invoice_job.rb @@ -1,21 +1,26 @@ class SendEInvoiceJob < Que::Job - def run(invoice) - destroy if invoice.do_not_send_e_invoice? + def run(invoice_id) + invoice = run_condition(Invoice.find_by(id: invoice_id)) invoice.to_e_invoice.deliver - ActiveRecord::Base.transaction do invoice.update(e_invoice_sent_at: Time.zone.now) log_success(invoice) destroy end - rescue Exception => e + rescue StandardError => e log_error(invoice: invoice, error: e) raise e end private + def run_condition(invoice) + destroy unless invoice + destroy if invoice.do_not_send_e_invoice? + invoice + end + def log_success(invoice) id = invoice.try(:id) || invoice message = "E-Invoice for an invoice with ID # #{id} was sent successfully" @@ -26,8 +31,8 @@ class SendEInvoiceJob < Que::Job id = invoice.try(:id) || invoice message = <<~TEXT.squish There was an error sending e-invoice for invoice with ID # #{id}. - The error message was the following: #{error}. - This job will retry + The error message was the following: #{error} + This job will retry. TEXT logger.error message end diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 94b01517e..f657cdc74 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -99,8 +99,7 @@ class Registrar < ApplicationRecord } ] ) - - SendEInvoiceJob.enqueue(invoice) + SendEInvoiceJob.enqueue(invoice.id) invoice end diff --git a/test/jobs/send_e_invoice_job_test.rb b/test/jobs/send_e_invoice_job_test.rb index 5ea09e576..384479e92 100644 --- a/test/jobs/send_e_invoice_job_test.rb +++ b/test/jobs/send_e_invoice_job_test.rb @@ -13,8 +13,9 @@ class SendEInvoiceJobTest < ActiveSupport::TestCase EInvoice::Providers::TestProvider.deliveries.clear assert_nothing_raised do - SendEInvoiceJob.enqueue(@invoice) + SendEInvoiceJob.enqueue(@invoice.id) end + @invoice.reload assert_not @invoice.e_invoice_sent_at.blank? assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count @@ -28,7 +29,7 @@ class SendEInvoiceJobTest < ActiveSupport::TestCase stub_request(:get, "https://testfinance.post.ee/finance/erp/erpServices.wsdl").to_timeout assert_raise HTTPClient::TimeoutError do - SendEInvoiceJob.enqueue(@invoice) + SendEInvoiceJob.enqueue(@invoice.id) end assert @invoicee_invoice_sent_at.blank? @@ -36,8 +37,9 @@ class SendEInvoiceJobTest < ActiveSupport::TestCase EInvoice::Providers::TestProvider.deliveries.clear assert_nothing_raised do - SendEInvoiceJob.enqueue(@invoice) + SendEInvoiceJob.enqueue(@invoice.id) end + @invoice.reload assert_not @invoice.e_invoice_sent_at.blank? assert_equal 1, EInvoice::Providers::TestProvider.deliveries.count