Convert CalculatedAdjustments into a proper Concern and remove class_eval

This commit is contained in:
Matt-Yorkley
2021-07-24 16:20:07 +01:00
parent c6743d8c6b
commit 2d69810c5d
8 changed files with 85 additions and 87 deletions

View File

@@ -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

View File

@@ -1,7 +1,7 @@
# frozen_string_literal: true
class EnterpriseFee < ApplicationRecord
include Spree::Core::CalculatedAdjustments
include CalculatedAdjustments
acts_as_paranoid

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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) }