-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(anrok): make api calls async in dedicated service #3002
base: main
Are you sure you want to change the base?
Changes from all commits
0eace7c
64d8697
81bdf29
02294af
faa2e07
3a315d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# frozen_string_literal: true | ||
|
||
module Types | ||
module Invoices | ||
class TaxStatusTypeEnum < Types::BaseEnum | ||
graphql_name 'InvoiceTaxStatusTypeEnum' | ||
|
||
Invoice::TAX_STATUSES.keys.each do |type| | ||
value type | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# frozen_string_literal: true | ||
|
||
module Invoices | ||
class ComputeTaxesAndTotalsService < BaseService | ||
def initialize(invoice:, finalizing: true) | ||
@invoice = invoice | ||
@finalizing = finalizing | ||
|
||
super | ||
end | ||
|
||
def call | ||
return result.not_found_failure!(resource: 'invoice') unless invoice | ||
|
||
if customer_provider_taxation? | ||
invoice.status = 'pending' if finalizing | ||
invoice.tax_status = 'pending' | ||
invoice.save! | ||
after_commit { Invoices::ProviderTaxes::PullTaxesAndApplyJob.perform_later(invoice:) } | ||
|
||
return result.unknown_tax_failure!(code: 'tax_error', message: 'unknown taxes') | ||
else | ||
Invoices::ComputeAmountsFromFees.call(invoice:) | ||
end | ||
|
||
result.invoice = invoice | ||
result | ||
end | ||
|
||
private | ||
|
||
attr_reader :invoice, :finalizing | ||
|
||
def customer_provider_taxation? | ||
@customer_provider_taxation ||= invoice.customer.anrok_customer | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,19 +22,10 @@ def call | |
Credits::ProgressiveBillingService.call(invoice:) | ||
Credits::AppliedCouponsService.call(invoice:) | ||
|
||
if customer_provider_taxation? | ||
taxes_result = Integrations::Aggregator::Taxes::Invoices::CreateService.call(invoice:, fees: invoice.fees) | ||
totals_result = Invoices::ComputeTaxesAndTotalsService.call(invoice:) | ||
return totals_result if !totals_result.success? && totals_result.error.is_a?(BaseService::UnknownTaxFailure) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why we don't raise the error if it is an Maybe the naming of the failure is not the best as I would expect to raise unknown failures more than known ones... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe naming is confusing, but I couldn't find better one:) The idea is:
|
||
|
||
unless taxes_result.success? | ||
create_error_detail(taxes_result.error) | ||
invoice.failed! | ||
|
||
return result.service_failure!(code: 'tax_error', message: taxes_result.error.code) | ||
end | ||
Invoices::ComputeAmountsFromFees.call(invoice:, provider_taxes: taxes_result.fees) | ||
else | ||
Invoices::ComputeAmountsFromFees.call(invoice:) | ||
end | ||
totals_result.raise_if_error! | ||
|
||
create_credit_note_credit | ||
create_applied_prepaid_credit | ||
|
@@ -149,25 +140,5 @@ def create_applied_prepaid_credit | |
|
||
invoice.total_amount_cents -= prepaid_credit_result.prepaid_credit_amount_cents | ||
end | ||
|
||
def customer_provider_taxation? | ||
@customer_provider_taxation ||= invoice.customer.anrok_customer | ||
end | ||
|
||
def create_error_detail(error) | ||
error_result = ErrorDetails::CreateService.call( | ||
owner: invoice, | ||
organization: invoice.organization, | ||
params: { | ||
error_code: :tax_error, | ||
details: { | ||
tax_error: error.code | ||
}.tap do |details| | ||
details[:tax_error_message] = error.error_message if error.code == 'validationError' | ||
end | ||
} | ||
) | ||
error_result.raise_if_error! | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,18 +34,19 @@ def call | |
provider_taxes = taxes_result.fees | ||
|
||
ActiveRecord::Base.transaction do | ||
unless invoice.draft? | ||
invoice.issuing_date = issuing_date | ||
invoice.payment_due_date = payment_due_date | ||
Comment on lines
+38
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we expect to overwrite invoice There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you are right, draft invoice can already have this informations. However, when we are in the finalize mode, we need to overwrite those informations since finalization can happen also before original issuing date (if it is triggered manually) |
||
end | ||
|
||
Invoices::ComputeAmountsFromFees.call(invoice:, provider_taxes:) | ||
|
||
create_credit_note_credit if should_create_credit_note_credit? | ||
create_applied_prepaid_credit if should_create_applied_prepaid_credit? | ||
|
||
invoice.payment_status = invoice.total_amount_cents.positive? ? :pending : :succeeded | ||
invoice.tax_status = 'succeeded' | ||
if invoice.draft? | ||
invoice.status = :draft | ||
else | ||
Invoices::TransitionToFinalStatusService.call(invoice:) | ||
end | ||
Invoices::TransitionToFinalStatusService.call(invoice:) unless invoice.draft? | ||
|
||
invoice.save! | ||
invoice.reload | ||
|
@@ -115,6 +116,14 @@ def create_applied_prepaid_credit | |
invoice.total_amount_cents -= prepaid_credit_result.prepaid_credit_amount_cents | ||
end | ||
|
||
def issuing_date | ||
@issuing_date ||= Time.current.in_time_zone(customer.applicable_timezone).to_date | ||
end | ||
|
||
def payment_due_date | ||
@payment_due_date ||= issuing_date + customer.applicable_net_payment_term.days | ||
end | ||
|
||
def customer | ||
@customer ||= invoice.customer | ||
end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ def call | |
ActiveRecord::Base.transaction do | ||
invoice.issuing_date = issuing_date | ||
refresh_result = Invoices::RefreshDraftService.call(invoice:, context: :finalize) | ||
if tax_error?(refresh_result.error) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch, will remove it |
||
if invoice.tax_pending? | ||
invoice.update!(issuing_date: drafted_issuing_date) | ||
return refresh_result | ||
end | ||
|
@@ -78,11 +78,5 @@ def should_deliver_email? | |
License.premium? && | ||
invoice.organization.email_settings.include?('invoice.finalized') | ||
end | ||
|
||
def tax_error?(error) | ||
return false unless error.is_a?(BaseService::ValidationFailure) | ||
|
||
error&.messages&.dig(:tax_error).present? | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we always return a failure if customer is on anrok? Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This specific error is returned to indicate the path where invoice is missing taxes and is not complete, which is always the case for Anrok, at least until the
Invoices::ProviderTaxes::PullTaxesAndApplyJob
process the invoiceThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but then this is the expected behavior not a failure, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invoice is not complete without taxes so that's why I wanted to clearly indicate this state in the service. Probably it is just style preference. Other option could be that I check wherever needed if
invoice.tax_status = 'pending'
or something similar, but I wanted to return different type of response in the service level:)