diff --git a/app/models/concerns/calculated_adjustments.rb b/app/models/concerns/calculated_adjustments.rb new file mode 100644 index 0000000000..af55dfa5b2 --- /dev/null +++ b/app/models/concerns/calculated_adjustments.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require "active_support/concern" + +module CalculatedAdjustments + extend ActiveSupport::Concern + + included do + has_one :calculator, as: :calculable, class_name: "Spree::Calculator", dependent: :destroy + accepts_nested_attributes_for :calculator + validates :calculator, presence: true + end + + class_methods do + def calculators + spree_calculators.__send__(model_name_without_spree_namespace) + end + + private + + def model_name_without_spree_namespace + to_s.tableize.gsub('/', '_').sub('spree_', '') + end + + def spree_calculators + Rails.application.config.spree.calculators + end + end + + def calculator_type + calculator.class.to_s if calculator + end + + def calculator_type=(calculator_type) + klass = calculator_type.constantize if calculator_type + self.calculator = klass.new if klass && !calculator.is_a?(klass) + end + + # Creates a new adjustment for the target object + # (which is any class that has_many :adjustments) and sets amount based on the + # calculator as applied to the given calculable (Order, LineItems[], Shipment, etc.) + # By default the adjustment will not be considered mandatory + def create_adjustment(label, adjustable, mandatory = false, state = "closed", tax_category = nil) + amount = compute_amount(adjustable) + return if amount.zero? && !mandatory + + adjustment_attributes = { + amount: amount, + originator: self, + order: order_object_for(adjustable), + label: label, + mandatory: mandatory, + state: state, + tax_category: tax_category + } + + if adjustable.respond_to?(:adjustments) + adjustable.adjustments.create(adjustment_attributes) + else + adjustable.create_adjustment(adjustment_attributes) + end + end + + # Calculate the amount to be used when creating an adjustment + # NOTE: May be overriden by classes where this module is included into. + def compute_amount(calculable) + calculator.compute(calculable) + end + + private + + def order_object_for(target) + # Temporary method for adjustments transition. + if target.is_a? Spree::Order + target + elsif target.respond_to?(:order) + target.order + end + end +end diff --git a/app/models/enterprise_fee.rb b/app/models/enterprise_fee.rb index 91b262e279..9ceed01020 100644 --- a/app/models/enterprise_fee.rb +++ b/app/models/enterprise_fee.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class EnterpriseFee < ApplicationRecord - include Spree::Core::CalculatedAdjustments + include CalculatedAdjustments acts_as_paranoid diff --git a/app/models/spree/payment_method.rb b/app/models/spree/payment_method.rb index c055842951..50ea9da5e0 100644 --- a/app/models/spree/payment_method.rb +++ b/app/models/spree/payment_method.rb @@ -1,11 +1,10 @@ # frozen_string_literal: true require 'concerns/payment_method_distributors' -require 'spree/core/calculated_adjustments' module Spree class PaymentMethod < ApplicationRecord - include Spree::Core::CalculatedAdjustments + include CalculatedAdjustments include PaymentMethodDistributors acts_as_taggable diff --git a/app/models/spree/shipping_method.rb b/app/models/spree/shipping_method.rb index 931186f28b..53d77d60c2 100644 --- a/app/models/spree/shipping_method.rb +++ b/app/models/spree/shipping_method.rb @@ -2,7 +2,7 @@ module Spree class ShippingMethod < ApplicationRecord - include Spree::Core::CalculatedAdjustments + include CalculatedAdjustments DISPLAY = [:both, :front_end, :back_end].freeze acts_as_paranoid diff --git a/app/models/spree/tax_rate.rb b/app/models/spree/tax_rate.rb index f0a7be6e11..0bc308f971 100644 --- a/app/models/spree/tax_rate.rb +++ b/app/models/spree/tax_rate.rb @@ -15,7 +15,7 @@ end module Spree class TaxRate < ApplicationRecord acts_as_paranoid - include Spree::Core::CalculatedAdjustments + include CalculatedAdjustments belongs_to :zone, class_name: "Spree::Zone", inverse_of: :tax_rates belongs_to :tax_category, class_name: "Spree::TaxCategory", inverse_of: :tax_rates diff --git a/lib/spree/core.rb b/lib/spree/core.rb index 0b766960d1..d737c6e7da 100644 --- a/lib/spree/core.rb +++ b/lib/spree/core.rb @@ -47,7 +47,6 @@ require 'spree/money' require 'spree/core/delegate_belongs_to' require 'spree/core/permalinks' require 'spree/core/token_resource' -require 'spree/core/calculated_adjustments' require 'spree/core/product_duplicator' require 'spree/core/gateway_error' diff --git a/lib/spree/core/calculated_adjustments.rb b/lib/spree/core/calculated_adjustments.rb deleted file mode 100644 index 3e06a95179..0000000000 --- a/lib/spree/core/calculated_adjustments.rb +++ /dev/null @@ -1,80 +0,0 @@ -# frozen_string_literal: true - -module Spree - module Core - module CalculatedAdjustments - def self.included(klass) - klass.class_eval do - has_one :calculator, class_name: "Spree::Calculator", as: :calculable, dependent: :destroy - accepts_nested_attributes_for :calculator - validates :calculator, presence: true - - def self.calculators - spree_calculators.__send__(model_name_without_spree_namespace) - end - - def calculator_type - calculator.class.to_s if calculator - end - - def calculator_type=(calculator_type) - klass = calculator_type.constantize if calculator_type - self.calculator = klass.new if klass && !calculator.is_a?(klass) - end - - # Creates a new adjustment for the target object - # (which is any class that has_many :adjustments) and sets amount based on the - # calculator as applied to the given calculable (Order, LineItems[], Shipment, etc.) - # By default the adjustment will not be considered mandatory - def create_adjustment(label, adjustable, mandatory = false, state = "closed", tax_category = nil) - amount = compute_amount(adjustable) - return if amount.zero? && !mandatory - - adjustment_attributes = { - amount: amount, - originator: self, - order: order_object_for(adjustable), - label: label, - mandatory: mandatory, - state: state, - tax_category: tax_category - } - - if adjustable.respond_to?(:adjustments) - adjustable.adjustments.create(adjustment_attributes) - else - adjustable.create_adjustment(adjustment_attributes) - end - end - - # Calculate the amount to be used when creating an adjustment - # NOTE: May be overriden by classes where this module is included into. - def compute_amount(calculable) - calculator.compute(calculable) - end - - def self.model_name_without_spree_namespace - to_s.tableize.gsub('/', '_').sub('spree_', '') - end - private_class_method :model_name_without_spree_namespace - - def self.spree_calculators - Rails.application.config.spree.calculators - end - private_class_method :spree_calculators - - private - - def order_object_for(target) - # Temporary method for adjustments transition. - if target.is_a? Spree::Order - target - elsif target.respond_to?(:order) - target.order - end - end - end - end - end - end -end diff --git a/spec/lib/spree/core/calculated_adjustments_spec.rb b/spec/models/concerns/calculated_adjustments_spec.rb similarity index 98% rename from spec/lib/spree/core/calculated_adjustments_spec.rb rename to spec/models/concerns/calculated_adjustments_spec.rb index 218ef63c92..b024c679e4 100644 --- a/spec/lib/spree/core/calculated_adjustments_spec.rb +++ b/spec/models/concerns/calculated_adjustments_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' # Its pretty difficult to test this module in isolation b/c it needs to work in conjunction # with an actual class that extends ActiveRecord::Base and has a corresponding table in the DB. # So we'll just test it using Order and ShippingMethod. These classes are including the module. -describe Spree::Core::CalculatedAdjustments do +describe CalculatedAdjustments do let(:calculator) { build(:calculator) } let(:tax_rate) { Spree::TaxRate.new(calculator: calculator) }