diff --git a/core/app/models/spree/tax/item_adjuster.rb b/core/app/models/spree/tax/item_adjuster.rb index 37a862934dd..193fb372947 100644 --- a/core/app/models/spree/tax/item_adjuster.rb +++ b/core/app/models/spree/tax/item_adjuster.rb @@ -20,12 +20,31 @@ def initialize(item, options = {}) @rates_for_default_zone = options[:rates_for_default_zone] end - # Deletes all existing tax adjustments and creates new adjustments for all - # (geographically and category-wise) applicable tax rates. + # This updates the amounts for adjustments which already exist and + # creates and remove adjustments as needed to match the applicable + # (geographically and category-wise) tax rates. def adjust! - item.adjustments.destroy(item.adjustments.select(&:tax?)) + rates = rates_for_item(item) - rates_for_item(item).each { |rate| rate.adjust(nil, item) } + tax_adjustments = item.adjustments.select(&:tax?) + active_adjustments = rates.map do |rate| + # Find an existing adjustment from the same source. + # All tax adjustments already have source_type == 'Spree::TaxRate' so + # we need only check source_id. + adjustment = tax_adjustments.detect{|a| a.source_id == rate.id } + if adjustment + adjustment.update! + adjustment + else + # Create a new adjustment + rate.adjust(nil, item) + end + end + + unmatched_adjustments = tax_adjustments - active_adjustments + + # Remove any tax adjustments tied to rates which no longer match + item.adjustments.destroy(unmatched_adjustments) end end end