Skip to content
This repository
Browse code

Explicitly nest promotion classes.

Fixes #1548
  • Loading branch information...
commit 215dec3d587efdb29d4e1812fae1c1cd9705c72e 1 parent 9ac1182
Jeff Dutil JDutil authored radar committed
68 promo/app/models/spree/promotion/actions/create_adjustment.rb
... ... @@ -1,43 +1,47 @@
1 1 module Spree
2   - class Promotion::Actions::CreateAdjustment < PromotionAction
3   - calculated_adjustments
  2 + class Promotion
  3 + module Actions
  4 + class CreateAdjustment < PromotionAction
  5 + calculated_adjustments
4 6
5   - delegate :eligible?, :to => :promotion
  7 + delegate :eligible?, :to => :promotion
6 8
7   - before_validation :ensure_action_has_calculator
  9 + before_validation :ensure_action_has_calculator
8 10
9   - def perform(options = {})
10   - return unless order = options[:order]
11   - # Nothing to do if the promotion is already associated with the order
12   - return if order.promotion_credit_exists?(promotion)
  11 + def perform(options = {})
  12 + return unless order = options[:order]
  13 + # Nothing to do if the promotion is already associated with the order
  14 + return if order.promotion_credit_exists?(promotion)
13 15
14   - order.adjustments.promotion.reload.clear
15   - order.update!
16   - create_adjustment("#{I18n.t(:promotion)} (#{promotion.name})", order, order)
17   - end
  16 + order.adjustments.promotion.reload.clear
  17 + order.update!
  18 + create_adjustment("#{I18n.t(:promotion)} (#{promotion.name})", order, order)
  19 + end
18 20
19   - # override of CalculatedAdjustments#create_adjustment so promotional
20   - # adjustments are added all the time. They will get their eligability
21   - # set to false if the amount is 0
22   - def create_adjustment(label, target, calculable, mandatory=false)
23   - amount = compute_amount(calculable)
24   - params = { :amount => amount,
25   - :source => calculable,
26   - :originator => self,
27   - :label => label,
28   - :mandatory => mandatory }
29   - target.adjustments.create(params, :without_protection => true)
30   - end
  21 + # override of CalculatedAdjustments#create_adjustment so promotional
  22 + # adjustments are added all the time. They will get their eligability
  23 + # set to false if the amount is 0
  24 + def create_adjustment(label, target, calculable, mandatory=false)
  25 + amount = compute_amount(calculable)
  26 + params = { :amount => amount,
  27 + :source => calculable,
  28 + :originator => self,
  29 + :label => label,
  30 + :mandatory => mandatory }
  31 + target.adjustments.create(params, :without_protection => true)
  32 + end
31 33
32   - # Ensure a negative amount which does not exceed the sum of the order's item_total and ship_total
33   - def compute_amount(calculable)
34   - [(calculable.item_total + calculable.ship_total), super.to_f.abs].min * -1
35   - end
  34 + # Ensure a negative amount which does not exceed the sum of the order's item_total and ship_total
  35 + def compute_amount(calculable)
  36 + [(calculable.item_total + calculable.ship_total), super.to_f.abs].min * -1
  37 + end
36 38
37   - private
38   - def ensure_action_has_calculator
39   - return if self.calculator
40   - self.calculator = Calculator::FlatPercentItemTotal.new
  39 + private
  40 + def ensure_action_has_calculator
  41 + return if self.calculator
  42 + self.calculator = Calculator::FlatPercentItemTotal.new
  43 + end
  44 + end
41 45 end
42 46 end
43 47 end
44 promo/app/models/spree/promotion/actions/create_line_items.rb
... ... @@ -1,29 +1,33 @@
1 1 module Spree
2   - class Promotion::Actions::CreateLineItems < PromotionAction
3   - has_many :promotion_action_line_items, :foreign_key => 'promotion_action_id'
  2 + class Promotion
  3 + module Actions
  4 + class CreateLineItems < PromotionAction
  5 + has_many :promotion_action_line_items, :foreign_key => 'promotion_action_id'
4 6
5   - attr_accessor :line_items_string
  7 + attr_accessor :line_items_string
6 8
7   - def perform(options = {})
8   - return unless order = options[:order]
9   - promotion_action_line_items.each do |item|
10   - current_quantity = order.quantity_of(item.variant)
11   - if current_quantity < item.quantity
12   - order.add_variant(item.variant, item.quantity - current_quantity)
  9 + def perform(options = {})
  10 + return unless order = options[:order]
  11 + promotion_action_line_items.each do |item|
  12 + current_quantity = order.quantity_of(item.variant)
  13 + if current_quantity < item.quantity
  14 + order.add_variant(item.variant, item.quantity - current_quantity)
  15 + end
  16 + end
13 17 end
14   - end
15   - end
16 18
17   - def line_items_string
18   - promotion_action_line_items.map { |li| "#{li.variant_id}x#{li.quantity}" }.join(',')
19   - end
  19 + def line_items_string
  20 + promotion_action_line_items.map { |li| "#{li.variant_id}x#{li.quantity}" }.join(',')
  21 + end
20 22
21   - def line_items_string=(value)
22   - promotion_action_line_items.destroy_all
23   - value.to_s.split(',').each do |str|
24   - variant_id, quantity = str.split('x')
25   - if variant_id && quantity && variant = Variant.find_by_id(variant_id)
26   - promotion_action_line_items.create({:variant => variant, :quantity => quantity.to_i}, :without_protection => true)
  23 + def line_items_string=(value)
  24 + promotion_action_line_items.destroy_all
  25 + value.to_s.split(',').each do |str|
  26 + variant_id, quantity = str.split('x')
  27 + if variant_id && quantity && variant = Variant.find_by_id(variant_id)
  28 + promotion_action_line_items.create({:variant => variant, :quantity => quantity.to_i}, :without_protection => true)
  29 + end
  30 + end
27 31 end
28 32 end
29 33 end
12 promo/app/models/spree/promotion/rules/first_order.rb
... ... @@ -1,8 +1,12 @@
1 1 module Spree
2   - class Promotion::Rules::FirstOrder < PromotionRule
3   - def eligible?(order, options = {})
4   - user = order.try(:user) || options[:user]
5   - !!(user && user.orders.complete.count == 0)
  2 + class Promotion
  3 + module Rules
  4 + class FirstOrder < PromotionRule
  5 + def eligible?(order, options = {})
  6 + user = order.try(:user) || options[:user]
  7 + !!(user && user.orders.complete.count == 0)
  8 + end
  9 + end
6 10 end
7 11 end
8 12 end
20 promo/app/models/spree/promotion/rules/item_total.rb
... ... @@ -1,16 +1,20 @@
1 1 # A rule to limit a promotion to a specific user.
2 2 module Spree
3   - class Promotion::Rules::ItemTotal < PromotionRule
4   - preference :amount, :decimal, :default => 100.00
5   - preference :operator, :string, :default => '>'
  3 + class Promotion
  4 + module Rules
  5 + class ItemTotal < PromotionRule
  6 + preference :amount, :decimal, :default => 100.00
  7 + preference :operator, :string, :default => '>'
6 8
7   - attr_accessible :preferred_amount, :preferred_operator
  9 + attr_accessible :preferred_amount, :preferred_operator
8 10
9   - OPERATORS = ['gt', 'gte']
  11 + OPERATORS = ['gt', 'gte']
10 12
11   - def eligible?(order, options = {})
12   - item_total = order.line_items.map(&:amount).sum
13   - item_total.send(preferred_operator == 'gte' ? :>= : :>, BigDecimal.new(preferred_amount.to_s))
  13 + def eligible?(order, options = {})
  14 + item_total = order.line_items.map(&:amount).sum
  15 + item_total.send(preferred_operator == 'gte' ? :>= : :>, BigDecimal.new(preferred_amount.to_s))
  16 + end
  17 + end
14 18 end
15 19 end
16 20 end
60 promo/app/models/spree/promotion/rules/product.rb
@@ -2,39 +2,45 @@
2 2 # Can require all or any of the products to be present.
3 3 # Valid products either come from assigned product group or are assingned directly to the rule.
4 4 module Spree
5   - class Promotion::Rules::Product < PromotionRule
6   - has_and_belongs_to_many :products, :class_name => '::Spree::Product', :join_table => 'spree_products_promotion_rules', :foreign_key => 'promotion_rule_id'
7   - validate :only_one_promotion_per_product
  5 + class Promotion
  6 + module Rules
  7 + class Product < PromotionRule
  8 + has_and_belongs_to_many :products, :class_name => '::Spree::Product', :join_table => 'spree_products_promotion_rules', :foreign_key => 'promotion_rule_id'
  9 + validate :only_one_promotion_per_product
8 10
9   - MATCH_POLICIES = %w(any all)
10   - preference :match_policy, :string, :default => MATCH_POLICIES.first
  11 + MATCH_POLICIES = %w(any all)
  12 + preference :match_policy, :string, :default => MATCH_POLICIES.first
11 13
12   - # scope/association that is used to test eligibility
13   - def eligible_products
14   - products
15   - end
  14 + # scope/association that is used to test eligibility
  15 + def eligible_products
  16 + products
  17 + end
16 18
17   - def only_one_promotion_per_product
18   - if Spree::Promotion::Rules::Product.all.map(&:products).flatten.uniq!
19   - errors[:base] << "You can't create two promotions for the same product"
20   - end
21   - end
  19 + def eligible?(order, options = {})
  20 + return true if eligible_products.empty?
  21 + if preferred_match_policy == 'all'
  22 + eligible_products.all? {|p| order.products.include?(p) }
  23 + else
  24 + order.products.any? {|p| eligible_products.include?(p) }
  25 + end
  26 + end
22 27
23   - def eligible?(order, options = {})
24   - return true if eligible_products.empty?
25   - if preferred_match_policy == 'all'
26   - eligible_products.all? {|p| order.products.include?(p) }
27   - else
28   - order.products.any? {|p| eligible_products.include?(p) }
29   - end
30   - end
  28 + def product_ids_string
  29 + product_ids.join(',')
  30 + end
31 31
32   - def product_ids_string
33   - product_ids.join(',')
34   - end
  32 + def product_ids_string=(s)
  33 + self.product_ids = s.to_s.split(',').map(&:strip)
  34 + end
35 35
36   - def product_ids_string=(s)
37   - self.product_ids = s.to_s.split(',').map(&:strip)
  36 + private
  37 +
  38 + def only_one_promotion_per_product
  39 + if Spree::Promotion::Rules::Product.all.map(&:products).flatten.uniq!
  40 + errors[:base] << "You can't create two promotions for the same product"
  41 + end
  42 + end
  43 + end
38 44 end
39 45 end
40 46 end
28 promo/app/models/spree/promotion/rules/user.rb
... ... @@ -1,20 +1,24 @@
1 1 module Spree
2   - class Promotion::Rules::User < PromotionRule
3   - belongs_to :user, :class_name => Spree.user_class.to_s
4   - has_and_belongs_to_many :users, :class_name => Spree.user_class.to_s, :join_table => 'spree_promotion_rules_users', :foreign_key => 'promotion_rule_id'
  2 + class Promotion
  3 + module Rules
  4 + class User < PromotionRule
  5 + attr_accessible :user_ids_string
5 6
6   - attr_accessible :user_ids_string
  7 + belongs_to :user, :class_name => Spree.user_class.to_s
  8 + has_and_belongs_to_many :users, :class_name => '::Spree::User', :join_table => 'spree_promotion_rules_users', :foreign_key => 'promotion_rule_id'
7 9
8   - def eligible?(order, options = {})
9   - users.none? or users.include?(order.user)
10   - end
  10 + def eligible?(order, options = {})
  11 + users.none? or users.include?(order.user)
  12 + end
11 13
12   - def user_ids_string
13   - user_ids.join(',')
14   - end
  14 + def user_ids_string
  15 + user_ids.join(',')
  16 + end
15 17
16   - def user_ids_string=(s)
17   - self.user_ids = s.to_s.split(',').map(&:strip)
  18 + def user_ids_string=(s)
  19 + self.user_ids = s.to_s.split(',').map(&:strip)
  20 + end
  21 + end
18 22 end
19 23 end
20 24 end
21 promo/app/models/spree/promotion/rules/user_logged_in.rb
... ... @@ -1,15 +1,20 @@
1 1 module Spree
2   - class Promotion::Rules::UserLoggedIn < PromotionRule
3   - def eligible?(order, options = {})
  2 + class Promotion
  3 + module Rules
  4 + class UserLoggedIn < PromotionRule
4 5
5   - # this is tricky. We couldn't use any of the devise methods since we aren't in the controller.
6   - # we need to rely on the controller already having done this for us.
  6 + def eligible?(order, options = {})
  7 + # this is tricky. We couldn't use any of the devise methods since we aren't in the controller.
  8 + # we need to rely on the controller already having done this for us.
7 9
8   - # The thinking is that the controller should have some sense of what state
9   - # we should be in before firing events,
10   - # so the controller will have to set this field.
  10 + # The thinking is that the controller should have some sense of what state
  11 + # we should be in before firing events,
  12 + # so the controller will have to set this field.
11 13
12   - return options && options[:user_signed_in]
  14 + return options && options[:user_signed_in]
  15 + end
  16 +
  17 + end
13 18 end
14 19 end
15 20 end

0 comments on commit 215dec3

Please sign in to comment.
Something went wrong with that request. Please try again.