-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1892 from adammathys/tax-calculator-configuration
New configurable tax calculator interface
- Loading branch information
Showing
16 changed files
with
476 additions
and
217 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
module Spree | ||
# Relatively simple class used to apply a {Spree::Tax::OrderTax} to a | ||
# {Spree::Order}. | ||
# | ||
# This class will create or update adjustments on the taxed items and remove | ||
# any now inapplicable tax adjustments from the order. | ||
class OrderTaxation | ||
# Create a new order taxation. | ||
# | ||
# @param [Spree::Order] order the order to apply taxes to | ||
# @return [Spree::OrderTaxation] a {Spree::OrderTaxation} object | ||
def initialize(order) | ||
@order = order | ||
end | ||
|
||
# Apply taxes to the order. | ||
# | ||
# This method will create or update adjustments on all line items and | ||
# shipments in the order to reflect the appropriate taxes passed in. It | ||
# will also remove any now inapplicable tax adjustments. | ||
# | ||
# @param [Spree::Tax::OrderTax] taxes the taxes to apply to the order | ||
# @return [void] | ||
def apply(taxes) | ||
@order.line_items.each do |item| | ||
taxed_items = taxes.line_item_taxes.select { |i| i.item_id == item.id } | ||
update_adjustments(item, taxed_items) | ||
end | ||
|
||
@order.shipments.each do |item| | ||
taxed_items = taxes.shipment_taxes.select { |i| i.item_id == item.id } | ||
update_adjustments(item, taxed_items) | ||
end | ||
end | ||
|
||
private | ||
|
||
# Walk through the taxes for an item and update adjustments for it. Once | ||
# all of the taxes have been added as adjustments, remove any old tax | ||
# adjustments that weren't touched. | ||
# | ||
# @private | ||
# @param [#adjustments] item a {Spree::LineItem} or {Spree::Shipment} | ||
# @param [Array<Spree::Tax::ItemTax>] taxed_items a list of calculated taxes for an item | ||
# @return [void] | ||
def update_adjustments(item, taxed_items) | ||
tax_adjustments = item.adjustments.select(&:tax?) | ||
|
||
active_adjustments = taxed_items.map do |tax_item| | ||
update_adjustment(item, tax_item) | ||
end | ||
|
||
# Remove any tax adjustments tied to rates which no longer match. | ||
unmatched_adjustments = tax_adjustments - active_adjustments | ||
item.adjustments.destroy(unmatched_adjustments) | ||
end | ||
|
||
# Update or create a new tax adjustment on an item. | ||
# | ||
# @private | ||
# @param [#adjustments] item a {Spree::LineItem} or {Spree::Shipment} | ||
# @param [Spree::Tax::ItemTax] tax_item calculated taxes for an item | ||
# @return [Spree::Adjustment] the created or updated tax adjustment | ||
def update_adjustment(item, tax_item) | ||
tax_adjustment = item.adjustments.detect do |adjustment| | ||
adjustment.source == tax_item.tax_rate | ||
end | ||
|
||
tax_adjustment ||= item.adjustments.new( | ||
source: tax_item.tax_rate, | ||
order_id: item.order_id, | ||
label: tax_item.label, | ||
included: tax_item.included_in_price | ||
) | ||
tax_adjustment.update_attributes!(amount: tax_item.amount) | ||
tax_adjustment | ||
end | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module Spree | ||
module Tax | ||
# Simple object used to hold tax data for an item. | ||
# | ||
# This generic object will hold the amount of tax that should be applied to | ||
# an item. (Either a {Spree::LineItem} or a {Spree::Shipment}.) | ||
# | ||
# @attr_reader [Integer] item_id the {Spree::LineItem} or {Spree::Shipment} ID | ||
# @attr_reader [String] label information about the taxes | ||
# @attr_reader [Spree::TaxRate] tax_rate will be used as the source for tax | ||
# adjustments | ||
# @attr_reader [BigDecimal] amount the amount of tax applied to the item | ||
# @attr_reader [Boolean] included_in_price whether the amount is included | ||
# in the items price, or additional tax. | ||
class ItemTax | ||
include ActiveModel::Model | ||
attr_accessor :item_id, :label, :tax_rate, :amount, :included_in_price | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module Spree | ||
module Tax | ||
# Simple object to pass back tax data from a calculator. | ||
# | ||
# Will be used by {Spree::OrderTaxation} to create or update tax | ||
# adjustments on an order. | ||
# | ||
# @attr_reader [Integer] order_id the {Spree::Order} these taxes apply to | ||
# @attr_reader [Array<Spree::Tax::ItemTax>] line_item_taxes an array of | ||
# tax data for order's line items | ||
# @attr_reader [Array<Spree::Tax::ItemTax>] shipment_taxes an array of | ||
# tax data for the order's shipments | ||
class OrderTax | ||
include ActiveModel::Model | ||
attr_accessor :order_id, :line_item_taxes, :shipment_taxes | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
module Spree | ||
module TaxCalculator | ||
# Default implementation for tax calculations. Will go through all line | ||
# items and shipments and calculate their tax based on tax rates in the DB. | ||
# | ||
# The class used for tax calculation is configurable, so that the | ||
# calculation can easily be pushed to third-party services. Users looking | ||
# to provide their own calculator should adhere to the API of this class. | ||
# | ||
# @api experimental | ||
# @note This API is currently in development and likely to change. | ||
# Specifically, the input format is not yet finalized. | ||
class Default | ||
include Spree::Tax::TaxHelpers | ||
|
||
# Create a new tax calculator. | ||
# | ||
# @param [Spree::Order] order the order to calculator taxes on | ||
# @return [Spree::TaxCalculator::Default] a Spree::TaxCalculator::Default object | ||
def initialize(order) | ||
@order = order | ||
end | ||
|
||
# Calculate taxes for an order. | ||
# | ||
# @return [Spree::Tax::OrderTax] the calculated taxes for the order | ||
def calculate | ||
Spree::Tax::OrderTax.new( | ||
order_id: order.id, | ||
line_item_taxes: line_item_rates, | ||
shipment_taxes: shipment_rates | ||
) | ||
end | ||
|
||
private | ||
|
||
attr_reader :order | ||
|
||
# Calculate the taxes for line items. | ||
# | ||
# @private | ||
# @return [Array<Spree::Tax::ItemTax>] calculated taxes for the line items | ||
def line_item_rates | ||
order.line_items.flat_map do |line_item| | ||
calculate_rates(line_item) | ||
end | ||
end | ||
|
||
# Calculate the taxes for shipments. | ||
# | ||
# @private | ||
# @return [Array<Spree::Tax::ItemTax>] calculated taxes for the shipments | ||
def shipment_rates | ||
order.shipments.flat_map do |shipment| | ||
calculate_rates(shipment) | ||
end | ||
end | ||
|
||
# Calculate the taxes for a single item. | ||
# | ||
# The item could be either a {Spree::LineItem} or a {Spree::Shipment}. | ||
# | ||
# Will go through all applicable rates for an item and create a new | ||
# {Spree::Tax::ItemTax} containing the calculated taxes for the item. | ||
# | ||
# @private | ||
# @return [Array<Spree::Tax::ItemTax>] calculated taxes for the item | ||
def calculate_rates(item) | ||
rates_for_item(item).map do |rate| | ||
amount = rate.compute_amount(item) | ||
|
||
Spree::Tax::ItemTax.new( | ||
item_id: item.id, | ||
label: rate.adjustment_label(amount), | ||
tax_rate: rate, | ||
amount: amount, | ||
included_in_price: rate.included_in_price | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.