mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-29 21:17:17 +00:00
101 lines
3.2 KiB
Ruby
101 lines
3.2 KiB
Ruby
# frozen_string_literal: false
|
|
|
|
require 'open_food_network/enterprise_fee_calculator'
|
|
|
|
module Calculator
|
|
class DefaultTax < Spree::Calculator
|
|
def self.description
|
|
Spree.t(:default_tax)
|
|
end
|
|
|
|
def compute(computable)
|
|
case computable
|
|
when Spree::Order
|
|
compute_order(computable)
|
|
when Spree::Shipment, Spree::LineItem, Spree::Adjustment
|
|
compute_item(computable)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def rate
|
|
calculable
|
|
end
|
|
|
|
def compute_order(order)
|
|
# This legacy tax calculation applies to additional taxes only, and is no longer used.
|
|
# In theory it should never be called any more after this has been deployed.
|
|
# If the message below doesn't show up in Bugsnag, we can safely delete this method and all
|
|
# the related methods below it.
|
|
Alert.raise("Calculator::DefaultTax was called with legacy tax calculations")
|
|
|
|
calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor,
|
|
order.order_cycle)
|
|
|
|
[
|
|
line_items_total(order),
|
|
shipments_total(order),
|
|
per_item_fees_total(order, calculator),
|
|
per_order_fees_total(order, calculator)
|
|
].sum do |total|
|
|
round_to_two_places(total * rate.amount)
|
|
end
|
|
end
|
|
|
|
def line_items_total(order)
|
|
matched_line_items = order.line_items.select do |line_item|
|
|
line_item.variant.tax_category == rate.tax_category
|
|
end
|
|
|
|
matched_line_items.sum(&:total)
|
|
end
|
|
|
|
def shipments_total(order)
|
|
order.shipments.select do |shipment|
|
|
shipment.tax_category == rate.tax_category
|
|
end.sum(&:cost)
|
|
end
|
|
|
|
# Finds relevant fees for each line_item,
|
|
# calculates the tax on them, and returns the total tax
|
|
def per_item_fees_total(order, calculator)
|
|
order.line_items.to_a.sum do |line_item|
|
|
calculator.per_item_enterprise_fee_applicators_for(line_item.variant)
|
|
.select { |applicator| applicable_rate?(applicator, line_item) }
|
|
.sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) }
|
|
end
|
|
end
|
|
|
|
def applicable_rate?(applicator, line_item)
|
|
fee = applicator.enterprise_fee
|
|
(!fee.inherits_tax_category && fee.tax_category == rate.tax_category) ||
|
|
(fee.inherits_tax_category && line_item.variant.tax_category == rate.tax_category)
|
|
end
|
|
|
|
# Finds relevant fees for whole order,
|
|
# calculates the tax on them, and returns the total tax
|
|
def per_order_fees_total(order, calculator)
|
|
calculator.per_order_enterprise_fee_applicators_for(order)
|
|
.select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category }
|
|
.sum { |applicator| applicator.enterprise_fee.compute_amount(order) }
|
|
end
|
|
|
|
def compute_item(item)
|
|
if rate.included_in_price
|
|
deduced_total_by_rate(item.amount, rate)
|
|
else
|
|
round_to_two_places(item.amount * rate.amount)
|
|
end
|
|
end
|
|
|
|
def round_to_two_places(amount)
|
|
BigDecimal(amount.to_s).round(2, BigDecimal::ROUND_HALF_UP)
|
|
end
|
|
|
|
def deduced_total_by_rate(total, rate)
|
|
round_to_two_places(total - ( total / (1 + rate.amount) ) )
|
|
end
|
|
end
|
|
end
|