Class: Spree::Promotion

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/spree/promotion.rb,
app/models/spree/promotion/rules/user.rb,
app/models/spree/promotion/rules/product.rb,
app/models/spree/promotion/rules/item_total.rb,
app/models/spree/promotion/rules/first_order.rb,
app/models/spree/promotion/rules/user_logged_in.rb,
app/models/spree/promotion/actions/free_shipping.rb,
app/models/spree/promotion/actions/create_adjustment.rb,
app/models/spree/promotion/actions/create_line_items.rb,
app/models/spree/promotion/actions/create_item_adjustments.rb

Defined Under Namespace

Modules: Actions, Rules

Constant Summary collapse

MATCH_POLICIES =
%w(all any)
UNACTIVATABLE_ORDER_STATES =
["complete", "awaiting_return", "returned"]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.activeObject


33
34
35
36
# File 'app/models/spree/promotion.rb', line 33

def self.active
  where('starts_at IS NULL OR starts_at < ?', Time.now).
    where('expires_at IS NULL OR expires_at > ?', Time.now)
end

.advertisedObject


25
26
27
# File 'app/models/spree/promotion.rb', line 25

def self.advertised
  where(advertise: true)
end

.order_activatable?(order) ⇒ Boolean

Returns:

  • (Boolean)

38
39
40
# File 'app/models/spree/promotion.rb', line 38

def self.order_activatable?(order)
  order && !UNACTIVATABLE_ORDER_STATES.include?(order.state)
end

.with_coupon_code(coupon_code) ⇒ Object


29
30
31
# File 'app/models/spree/promotion.rb', line 29

def self.with_coupon_code(coupon_code)
  where("lower(code) = ?", coupon_code.strip.downcase).first
end

Instance Method Details

#activate(payload) ⇒ Object


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'app/models/spree/promotion.rb', line 46

def activate(payload)
  order = payload[:order]
  return unless self.class.order_activatable?(order)

  # Track results from actions to see if any action has been taken.
  # Actions should return nil/false if no action has been taken.
  # If an action returns true, then an action has been taken.
  results = actions.map do |action|
    action.perform(payload)
  end
  # If an action has been taken, report back to whatever activated this promotion.
  action_taken = results.include?(true)

  if action_taken
  # connect to the order
  # create the join_table entry.
    self.orders << order
    self.save
  end

  return action_taken
end

#adjusted_credits_count(promotable) ⇒ Object


107
108
109
# File 'app/models/spree/promotion.rb', line 107

def adjusted_credits_count(promotable)
  credits_count - promotable.adjustments.promotion.where(:source_id => actions.pluck(:id)).count
end

#creditsObject


111
112
113
# File 'app/models/spree/promotion.rb', line 111

def credits
  Adjustment.eligible.promotion.where(source_id: actions.map(&:id))
end

#credits_countObject


115
116
117
# File 'app/models/spree/promotion.rb', line 115

def credits_count
  credits.count
end

#eligible?(promotable) ⇒ Boolean

called anytime order.update! happens

Returns:

  • (Boolean)

70
71
72
73
# File 'app/models/spree/promotion.rb', line 70

def eligible?(promotable)
  return false if expired? || usage_limit_exceeded?(promotable)
  rules_are_eligible?(promotable, {})
end

#expired?Boolean

Returns:

  • (Boolean)

42
43
44
# File 'app/models/spree/promotion.rb', line 42

def expired?
  !!(starts_at && Time.now < starts_at || expires_at && Time.now > expires_at)
end

#product_idsObject


99
100
101
# File 'app/models/spree/promotion.rb', line 99

def product_ids
  products.map(&:id)
end

#productsObject

Products assigned to all product rules


93
94
95
96
97
# File 'app/models/spree/promotion.rb', line 93

def products
  @products ||= self.rules.to_a.inject([]) do |products, rule|
    rule.respond_to?(:products) ? products << rule.products : products
  end.flatten.uniq
end

#rules_are_eligible?(promotable, options = {}) ⇒ Boolean

Returns:

  • (Boolean)

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'app/models/spree/promotion.rb', line 75

def rules_are_eligible?(promotable, options = {})
  # Promotions without rules are eligible by default.
  return true if rules.none?
  eligible = lambda { |r| r.eligible?(promotable, options) }
  specific_rules = rules.for(promotable)
  return true if specific_rules.none?
  if match_policy == 'all'
    # If there are rules for this promotion, but no rules for this
    # particular promotable, then the promotion is ineligible by default.
    specific_rules.any? && specific_rules.all?(&eligible)
  else
    # If there are no rules for this promotable, then this will return false.
    # If there are rules for this promotable, but they are ineligible, this will return false.
    specific_rules.any?(&eligible)
  end
end

#usage_limit_exceeded?(promotable) ⇒ Boolean

Returns:

  • (Boolean)

103
104
105
# File 'app/models/spree/promotion.rb', line 103

def usage_limit_exceeded?(promotable)
  usage_limit.present? && usage_limit > 0 && adjusted_credits_count(promotable) >= usage_limit
end