Skip to content

Commit

Permalink
feat(taxes): Assign tax to a charge
Browse files Browse the repository at this point in the history
  • Loading branch information
rsempe committed Jul 11, 2023
1 parent 013f031 commit 7a46e51
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/controllers/api/v1/plans_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def input_params
{ values: {} },
],
},
{ tax_codes: [] },
],
)
end
Expand Down
35 changes: 35 additions & 0 deletions app/services/charges/apply_taxes_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

module Charges
class ApplyTaxesService < BaseService
def initialize(charge:, tax_codes:)
@charge = charge
@tax_codes = tax_codes

super
end

def call
return result.not_found_failure!(resource: 'charge') unless charge
return result.not_found_failure!(resource: 'tax') if (tax_codes - taxes.pluck(:code)).present?

result.applied_taxes = tax_codes.map do |tax_code|
charge.applied_taxes.find_or_create_by!(tax: taxes.find_by(code: tax_code))
end

Invoices::RefreshBatchJob.perform_later(charge.plan.invoices.draft.pluck(:id))

result
rescue ActiveRecord::RecordInvalid => e
result.record_validation_failure!(record: e.record)
end

private

attr_reader :charge, :tax_codes

def taxes
@taxes ||= charge.plan.organization.taxes.where(code: tax_codes)
end
end
end
10 changes: 9 additions & 1 deletion app/services/plans/create_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,15 @@ def create(**args)
ActiveRecord::Base.transaction do
plan.save!

args[:charges].each { |c| create_charge(plan, c) } if args[:charges].present?
if args[:charges].present?
args[:charges].each do |charge|
new_charge = create_charge(plan, charge)

if charge[:tax_codes].present?
Charges::ApplyTaxesService.call(charge: new_charge, tax_codes: charge[:tax_codes])
end
end
end
end

result.plan = plan
Expand Down
3 changes: 3 additions & 0 deletions spec/requests/api/v1/plans_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
require 'rails_helper'

RSpec.describe Api::V1::PlansController, type: :request do
let(:tax) { create(:tax, organization:) }
let(:organization) { create(:organization) }
let(:billable_metric) { create(:billable_metric, organization:) }
let(:plan) { create(:plan, code: 'plan_code') }

describe 'create' do
let(:create_params) do
Expand All @@ -24,6 +26,7 @@
properties: {
amount: '0.22',
},
tax_codes: [tax.code],
},
],
}
Expand Down
75 changes: 75 additions & 0 deletions spec/services/charges/apply_taxes_service_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Charges::ApplyTaxesService, type: :service do
subject(:apply_service) { described_class.new(charge:, tax_codes:) }

let(:plan) { create(:plan) }
let(:charge) { create(:standard_charge, plan:) }
let(:tax1) { create(:tax, organization: plan.organization, code: 'tax1') }
let(:tax2) { create(:tax, organization: plan.organization, code: 'tax2') }
let(:tax_codes) { [tax1.code, tax2.code] }

describe 'call' do
it 'applies taxes to the charge' do
expect { apply_service.call }.to change { charge.applied_taxes.count }.from(0).to(2)
end

it 'refreshes draft invoices' do
subscription = create(:subscription, plan:)
invoice = create(:invoice, :draft, organization: plan.organization)
create(:invoice_subscription, invoice:, subscription:)

expect do
apply_service.call
end.to have_enqueued_job(Invoices::RefreshBatchJob).with([invoice.id])
end

it 'returns applied taxes' do
result = apply_service.call
expect(result.applied_taxes.count).to eq(2)
end

context 'when charge is not found' do
let(:charge) { nil }

it 'returns an error' do
result = apply_service.call

aggregate_failures do
expect(result).not_to be_success
expect(result.error.error_code).to eq('charge_not_found')
end
end
end

context 'when tax is not found' do
let(:tax_codes) { ['unknown'] }

it 'returns an error' do
result = apply_service.call

aggregate_failures do
expect(result).not_to be_success
expect(result.error.error_code).to eq('tax_not_found')
end
end
end

context 'when applied tax is already present' do
it 'does not create a new applied tax' do
create(:charge_applied_tax, charge:, tax: tax1)
expect { apply_service.call }.to change { charge.applied_taxes.count }.from(1).to(2)
end
end

context 'when trying to apply twice the same tax' do
let(:tax_codes) { [tax1.code, tax1.code] }

it 'assigns it only once' do
expect { apply_service.call }.to change { charge.applied_taxes.count }.from(0).to(1)
end
end
end
end

0 comments on commit 7a46e51

Please sign in to comment.