module Spree module Core module CalculatedAdjustments module ClassMethods def calculated_adjustments has_one :calculator, :as => :calculable, :dependent => :destroy accepts_nested_attributes_for :calculator attr_accessible :calculator_type, :calculator_attributes validates :calculator, :presence => true def self.calculators Rails.application.config.spree.calculators.send(self.to_s.tableize.gsub('/', '_').sub('spree_', '')) end end end def calculator_type calculator.class.to_s if calculator end def calculator_type=(calculator_type) clazz = calculator_type.constantize if calculator_type self.calculator = clazz.new if clazz and not self.calculator.is_a? clazz 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 calculable argument (Order, LineItems[], Shipment, etc.) # By default the adjustment will not be considered mandatory def create_adjustment(label, target, calculable, mandatory=false) amount = compute_amount(calculable) return if amount == 0 && !mandatory target.adjustments.create({ :amount => amount, :source => calculable, :originator => self, :label => label, :mandatory => mandatory}, :without_protection => true) end # Updates the amount of the adjustment using our Calculator and calling the +compute+ method with the +calculable+ # referenced passed to the method. def update_adjustment(adjustment, calculable) adjustment.update_attribute_without_callbacks(:amount, compute_amount(calculable)) end # Calculate the amount to be used when creating an adjustment def compute_amount(calculable) self.calculator.compute(calculable) end def self.included(receiver) receiver.extend ClassMethods end end end end