Files
openfoodnetwork/spec/services/voucher_adjustments_service_spec.rb
2024-05-09 12:24:41 +10:00

355 lines
11 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
RSpec.describe VoucherAdjustmentsService do
describe '#update' do
let(:enterprise) { build(:enterprise) }
context 'with a flat rate voucher' do
let(:voucher) do
create(:voucher_flat_rate, code: 'new_code', enterprise:, amount: 10)
end
context 'when voucher covers the order total' do
subject { order.voucher_adjustments.first }
let(:order) { create(:order_with_totals) }
it 'updates the adjustment amount to -order.total' do
voucher.create_adjustment(voucher.code, order)
order.update_columns(item_total: 6)
VoucherAdjustmentsService.new(order).update
expect(subject.amount.to_f).to eq(-6.0)
end
end
context 'with tax included in order price' do
subject { order.voucher_adjustments.first }
let(:order) do
create(
:order_with_taxes,
distributor: enterprise,
ship_address: create(:address),
product_price: 110,
tax_rate_amount: 0.10,
included_in_price: true,
tax_rate_name: "Tax 1"
)
end
before do
add_voucher(order, voucher)
VoucherAdjustmentsService.new(order).update
end
it 'updates the adjustment included_tax' do
# voucher_rate = amount / order.total
# -10 / 160 = -0.0625
# included_tax = voucher_rate * order.included_tax_total
# -0.625 * 10 = -0.63
expect(subject.included_tax.to_f).to eq(-0.63)
end
context "when re calculating" do
it "does not update the adjustment amount" do
expect do
VoucherAdjustmentsService.new(order).update
end.not_to change { subject.reload.amount }
end
it "does not update the tax adjustment" do
expect do
VoucherAdjustmentsService.new(order).update
end.not_to change { subject.reload.included_tax }
end
context "when the order changed" do
before do
order.update_columns(item_total: 200)
end
it "does update the adjustment amount" do
expect do
VoucherAdjustmentsService.new(order).update
end.not_to change { subject.reload.amount }
end
it "updates the tax adjustment" do
expect do
VoucherAdjustmentsService.new(order).update
end.to change { subject.reload.included_tax }
end
end
end
end
context 'with tax not included in order price' do
let(:order) do
create(
:order_with_taxes,
distributor: enterprise,
ship_address: create(:address),
product_price: 110,
tax_rate_amount: 0.10,
included_in_price: false,
tax_rate_name: "Tax 1"
)
end
let(:adjustment) { order.voucher_adjustments.first }
let(:tax_adjustment) { order.voucher_adjustments.second }
before do
add_voucher(order, voucher)
VoucherAdjustmentsService.new(order).update
end
it 'includes amount without tax' do
# voucher_rate = amount / order.total
# -10 / 171 = -0.058479532
# amount = voucher_rate * (order.total - order.additional_tax_total)
# -0.058479532 * (171 -11) = -9.36
expect(adjustment.amount.to_f).to eq(-9.36)
end
it 'creates a tax adjustment' do
# voucher_rate = amount / order.total
# -10 / 171 = -0.058479532
# amount = voucher_rate * order.additional_tax_total
# -0.058479532 * 11 = -0.64
expect(tax_adjustment.amount.to_f).to eq(-0.64)
expect(tax_adjustment.label).to match("Tax")
expect(tax_adjustment.metadata.enterprise_id).to eq(
tax_adjustment.originator.enterprise.id
)
expect(tax_adjustment.metadata.fee_name).to eq("Tax")
expect(tax_adjustment.metadata.fee_type).to eq("Voucher")
end
context "when re calculating" do
it "does not update the adjustment amount" do
expect do
VoucherAdjustmentsService.new(order).update
end.not_to change { adjustment.reload.amount }
end
it "does not update the tax adjustment" do
expect do
VoucherAdjustmentsService.new(order).update
end.not_to change { tax_adjustment.reload.amount }
end
context "when the order changed" do
before do
order.update_columns(item_total: 200)
end
it "updates the adjustment amount" do
expect do
VoucherAdjustmentsService.new(order).update
end.to change { adjustment.reload.amount }
end
it "updates the tax adjustment" do
expect do
VoucherAdjustmentsService.new(order).update
end.to change { tax_adjustment.reload.amount }
end
end
end
end
end
context 'with a percentage rate voucher' do
let(:voucher) do
create(:voucher_percentage_rate, code: 'new_code', enterprise:, amount: 10)
end
let(:adjustment) { order.voucher_adjustments.first }
let(:tax_adjustment) { order.voucher_adjustments.second }
context 'when voucher covers the order total' do
subject { order.voucher_adjustments.first }
let(:voucher) do
create(:voucher_percentage_rate, code: 'new_code', enterprise:, amount: 100)
end
let(:order) { create(:order_with_totals) }
it 'updates the adjustment amount to -order.total' do
voucher.create_adjustment(voucher.code, order)
order.update_columns(item_total: 150)
VoucherAdjustmentsService.new(order).update
expect(subject.amount.to_f).to eq(-150.0)
end
end
context 'with tax included in order price' do
subject { order.voucher_adjustments.first }
let(:order) do
create(
:order_with_taxes,
distributor: enterprise,
ship_address: create(:address),
product_price: 110,
tax_rate_amount: 0.10,
included_in_price: true,
tax_rate_name: "Tax 1"
)
end
before do
add_voucher(order, voucher)
VoucherAdjustmentsService.new(order).update
end
it 'updates the adjustment included_tax' do
# voucher_rate = voucher.amount / 100
# 10 / 100 = 0.1
# included_tax = -voucher_rate * included_tax_total
# -0.1 * 10 = -1
expect(subject.included_tax.to_f).to eq(-1)
end
end
context 'with tax not included in order price' do
let(:order) do
create(
:order_with_taxes,
distributor: enterprise,
ship_address: create(:address),
product_price: 110,
tax_rate_amount: 0.10,
included_in_price: false,
tax_rate_name: "Tax 1"
)
end
before do
add_voucher(order, voucher)
VoucherAdjustmentsService.new(order).update
end
it 'includes amount without tax' do
adjustment = order.voucher_adjustments.first
# voucher_rate = voucher.amount / 100
# 10 / 100 = 0.1
# amount = -voucher_rate * (order.total - order.additional_tax_total)
# -0.1 * (171 -11) = -16.0
expect(adjustment.amount.to_f).to eq(-16.0)
end
it 'creates a tax adjustment' do
# voucher_rate = voucher.amount / 100
# 10 / 100 = 0.1
# amount = -voucher_rate * order.additional_tax_total
# -0.1 * 11 = -1.1
tax_adjustment = order.voucher_adjustments.second
expect(tax_adjustment.amount.to_f).to eq(-1.1)
expect(tax_adjustment.label).to match("Tax")
end
end
end
context 'when no order given' do
it "doesn't blow up" do
expect { VoucherAdjustmentsService.new(nil).update }.not_to raise_error
end
end
context 'when no voucher used on the given order' do
let(:order) { create(:order_with_line_items, line_items_count: 1, distributor: enterprise) }
it "doesn't blow up" do
expect { VoucherAdjustmentsService.new(order).update }.not_to raise_error
end
end
end
describe "#voucher_included_tax" do
subject(:voucher_included_tax) { VoucherAdjustmentsService.new(order).voucher_included_tax }
let(:order) { create(:order_with_totals) }
let(:enterprise) { build(:enterprise) }
let(:voucher) do
create(:voucher_flat_rate, code: 'new_code', enterprise:, amount: 10)
end
it "returns included tax from voucher adjusment" do
voucher_adjustment = voucher.create_adjustment(voucher.code, order)
# Manually update included tax, so we don't have to do a big data setup to be able to use
# VoucherAdjustmentsService.update
voucher_adjustment.update(included_tax: 0.5)
expect(voucher_included_tax).to eq(0.5)
end
context "When no voucher adjustment linked to the order" do
it "returns 0.0" do
expect(voucher_included_tax).to eq(0.0)
end
end
end
describe "#voucher_excluded_tax" do
subject(:voucher_excluded_tax) { VoucherAdjustmentsService.new(order).voucher_excluded_tax }
let(:order) do
create(
:order_with_taxes,
distributor: enterprise,
ship_address: create(:address),
product_price: 110,
tax_rate_amount: 0.10,
included_in_price: false,
tax_rate_name: "Tax 1"
)
end
let(:enterprise) { build(:enterprise) }
let(:voucher) do
create(:voucher_flat_rate, code: 'new_code', enterprise:, amount: 10)
end
it "returns the amount from the tax voucher adjustment" do
add_voucher(order, voucher)
VoucherAdjustmentsService.new(order).update
expect(voucher_excluded_tax).to eq(-0.64)
end
context "when no voucher adjustment tax" do
it "returns 0" do
voucher_adjustment = voucher.create_adjustment(voucher.code, order)
expect(voucher_excluded_tax).to eq(0.0)
end
end
context "when no voucher adjustment linked to the order" do
it "returns 0.0" do
expect(voucher_excluded_tax).to eq(0.0)
end
end
end
def add_voucher(order, voucher)
voucher.create_adjustment(voucher.code, order)
# Update taxes
order.create_tax_charge!
order.update_shipping_fees!
order.update_order!
end
end