module Returnly class DiscountCalculator attr_accessor :order DISCOUNTER_CLASSES = { 'Spree::Order' => Returnly::Discounts::Order, 'Spree::LineItem' => Returnly::Discounts::LineItem }.freeze def initialize(order) @order = order end def calculate(line_items = []) line_items.inject(0) do |discount_amount, item| line_item = find_line_item(item[:order_line_item_id]) next discount_amount if line_item.nil? discount_amount += discount_amount_for(line_item, item[:units].to_i) discount_amount end end private def discount_amount_for(line_item, units) discounters.inject(0) do |amount, discounter| amount += discounter.discount_amount(line_item, units) amount end end def discounters order_promotion_adjustments.map { |promotion_adjustment| build_discounter_by(promotion_adjustment) }.compact end def build_discounter_by(promotion_adjustment) discounter_class = DISCOUNTER_CLASSES[promotion_adjustment.adjustable_type] return nil if discounter_class.nil? discounter_class.new(order, promotion_adjustment) end def order_promotion_adjustments order.all_adjustments.where(source_type: 'Spree::PromotionAction', eligible: true) end def find_line_item(id) order.line_items.find_by(id: id) end end end