Skip to content

Commit

Permalink
Fix(anrok): return zero-tax breakdown if client facing taxes sum is 0 (
Browse files Browse the repository at this point in the history
…#2797)

## Context

If taxes are payable by seller, line_items.tax_amount_cents will be 0,
but tax_breakdown might be not 0 (these taxes the seller will pay), so
we don't need to create applied taxes if in taxes returned from the tax
provider, the tax_amount_cents of the line_item is 0

## Description

updated `Invoice::ApplyProviderTaxes` and `Fee::ApplyProviderTaxes` to
create zero-taxes if fee.tax_amount_cents is 0, but tax_breakdown
contains some taxes;
  • Loading branch information
annvelents authored Nov 8, 2024
1 parent 347506b commit c308ead
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 10 deletions.
30 changes: 21 additions & 9 deletions app/services/integrations/aggregator/taxes/base_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ def process_response(body)

if fees
result.fees = fees.map do |fee|
taxes_to_pay = fee['tax_amount_cents']

OpenStruct.new(
item_id: fee['item_id'],
item_code: fee['item_code'],
amount_cents: fee['amount_cents'],
tax_amount_cents: fee['tax_amount_cents'],
tax_breakdown: tax_breakdown(fee['tax_breakdown'])
tax_amount_cents: taxes_to_pay,
tax_breakdown: tax_breakdown(fee['tax_breakdown'], taxes_to_pay)
)
end
result.succeeded_id = body['succeededInvoices'].first['id']
Expand All @@ -62,7 +64,7 @@ def process_response(body)
end
end

def tax_breakdown(breakdown)
def tax_breakdown(breakdown, taxes_to_pay)
breakdown.map do |b|
if SPECIAL_TAXATION_TYPES.include?(b['type'])
OpenStruct.new(
Expand All @@ -72,12 +74,22 @@ def tax_breakdown(breakdown)
type: b['type']
)
elsif b['rate']
OpenStruct.new(
name: b['name'],
rate: b['rate'],
tax_amount: b['tax_amount'],
type: b['type']
)
# If there are taxes, that client shouldn't pay, we nullify the taxes
if taxes_to_pay.zero?
OpenStruct.new(
name: 'Tax',
rate: '0.00',
tax_amount: 0,
type: 'tax'
)
else
OpenStruct.new(
name: b['name'],
rate: b['rate'],
tax_amount: b['tax_amount'],
type: b['type']
)
end
else
OpenStruct.new(
name: humanize_tax_name(b['reason'].presence || b['type'] || 'unknown_taxation'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"succeededInvoices": [
{
"issuing_date": "2024-03-07",
"sub_total_excluding_taxes": 9900,
"taxes_amount_cents": 0,
"currency": "USD",
"contact": {
"external_id": "cus_lago_12345",
"name": "John Doe",
"taxable": true,
"tax_number": "1234567890"
},
"fees": [
{
"item_id": "lago_fee_id",
"item_code": "lago_default_b2b",
"amount_cents": 9900,
"tax_amount_cents": 0,
"tax_breakdown": [
{
"name": "GST/HST",
"rate": "0.10",
"tax_amount": 990,
"type": "tax_exempt"
}
]
}
]
}
],
"failedInvoices": []
}
33 changes: 32 additions & 1 deletion spec/services/fees/apply_provider_taxes_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@

let(:invoice) { create(:invoice, organization:, customer:) }

let(:fee) { create(:fee, invoice:, amount_cents: 1000, precise_amount_cents: 1000.0, precise_coupons_amount_cents:) }
let(:fee) do
create(:fee, invoice:, amount_cents: 1000, precise_amount_cents: 1000.0, precise_coupons_amount_cents:,
taxes_amount_cents: 0, taxes_precise_amount_cents: 0.0, taxes_rate: 0, taxes_base_rate: 0.0)
end
let(:precise_coupons_amount_cents) { 0 }

let(:fee_taxes) do
OpenStruct.new(
tax_amount_cents: 170,
tax_breakdown: [
OpenStruct.new(name: 'tax 2', type: 'type2', rate: '0.12', tax_amount: 120),
OpenStruct.new(name: 'tax 3', type: 'type3', rate: '0.05', tax_amount: 50)
Expand Down Expand Up @@ -45,6 +49,7 @@
context 'when there is tax deduction' do
let(:fee_taxes) do
OpenStruct.new(
tax_amount_cents: 136,
tax_breakdown: [
OpenStruct.new(name: 'tax 2', type: 'type2', rate: '0.12', tax_amount: 96),
OpenStruct.new(name: 'tax 3', type: 'type3', rate: '0.05', tax_amount: 40)
Expand All @@ -71,6 +76,31 @@
end
end
end

context 'when taxes are paid by the seller' do
let(:fee_taxes) do
OpenStruct.new(
tax_amount_cents: 0,
tax_breakdown: [OpenStruct.new(name: 'Tax', type: 'tax', rate: '0.00', tax_amount: 0)]
)
end

it 'does not create applied_taxes' do
result = apply_service.call

aggregate_failures do
expect(result).to be_success

applied_taxes = result.applied_taxes
expect(applied_taxes.count).to eq(1)
expect(fee).to have_attributes(
taxes_amount_cents: 0,
taxes_precise_amount_cents: 0.0,
taxes_rate: 0
)
end
end
end
end

context 'when fee already have taxes' do
Expand All @@ -96,6 +126,7 @@
context "when tax provider returned specific rule applied to fees - #{applied_rule[:expected_name]}" do
let(:fee_taxes) do
OpenStruct.new(
tax_amount_cents: 0,
tax_breakdown: [
OpenStruct.new(name: applied_rule[:expected_name], type: applied_rule[:received_type], rate: '0.00', tax_amount: 0)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
context 'when special rules applied' do
before do
parsed_body = JSON.parse(body)
parsed_body['succeededInvoices'].first['fees'].first['tax_amount_cents'] = 0
parsed_body['succeededInvoices'].first['fees'].first['tax_breakdown'] = [
{
reason: "",
Expand Down Expand Up @@ -172,6 +173,24 @@
end
end
end

context 'when taxes are paid by seller' do
let(:body) do
path = Rails.root.join('spec/fixtures/integration_aggregator/taxes/invoices/success_response_seller_pays_taxes.json')
File.read(path)
end

it 'returns fee object with empty tax breakdown' do
result = service_call
aggregate_failures do
expect(result).to be_success
expect(result.fees.first['tax_breakdown'].last['name']).to eq('Tax')
expect(result.fees.first['tax_breakdown'].last['type']).to eq('tax')
expect(result.fees.first['tax_breakdown'].last['rate']).to eq('0.00')
expect(result.fees.first['tax_breakdown'].last['tax_amount']).to eq(0)
end
end
end
end

context 'when taxes are not successfully fetched' do
Expand Down
51 changes: 51 additions & 0 deletions spec/services/invoices/apply_provider_taxes_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -234,12 +234,14 @@
let(:fee_taxes) do
[
OpenStruct.new(
tax_amount_cents: 0,
tax_breakdown: [
OpenStruct.new(name: applied_rule[:expected_name], type: applied_rule[:received_type],
rate: '0.00', tax_amount: 0)
]
),
OpenStruct.new(
tax_amount_cents: 0,
tax_breakdown: [
OpenStruct.new(name: applied_rule[:expected_name], type: applied_rule[:received_type],
rate: '0.00', tax_amount: 0)
Expand Down Expand Up @@ -282,6 +284,55 @@
end
end
end

context 'with seller paying taxes' do
let(:fee_taxes) do
[
OpenStruct.new(
tax_amount_cents: 0,
tax_breakdown: [OpenStruct.new(name: 'Tax', type: 'tax', rate: '0.00', tax_amount: 0)]
),
OpenStruct.new(
tax_amount_cents: 0,
tax_breakdown: [OpenStruct.new(name: 'Tax', type: 'tax', rate: '0.00', tax_amount: 0)]
)
]
end
let(:fee1) { create(:fee, invoice:, amount_cents: 1000, precise_coupons_amount_cents: 0) }
let(:fee2) { create(:fee, invoice:, amount_cents: 2000, precise_coupons_amount_cents: 0) }
let(:fee1_applied_tax) do
create(:fee_applied_tax, fee: fee1, amount_cents: 0, tax_name: 'Tax', tax_code: 'tax', tax_rate: 0.0, tax_description: 'tax')
end
let(:fee2_applied_tax) do
create(:fee_applied_tax, fee: fee2, amount_cents: 0, tax_name: 'Tax', tax_code: 'tax', tax_rate: 0.0, tax_description: 'tax')
end

before do
fee1_applied_tax
fee2_applied_tax
end

it "does creates zero-tax" do
result = apply_service.call

aggregate_failures do
expect(result).to be_success

applied_taxes = result.applied_taxes
expect(applied_taxes.count).to eq(1)
expect(applied_taxes.find { |item| item.tax_code == 'tax' }).to have_attributes(
invoice:,
tax_description: 'tax',
tax_code: 'tax',
tax_name: 'Tax',
tax_rate: 0,
amount_currency: invoice.currency,
amount_cents: 0,
fees_amount_cents: 3000
)
end
end
end
end
end

Expand Down

0 comments on commit c308ead

Please sign in to comment.