forked from spree/spree
-
Notifications
You must be signed in to change notification settings - Fork 0
/
promotion.rb
109 lines (87 loc) · 3.44 KB
/
promotion.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
module Spree
class Promotion < Spree::Activator
MATCH_POLICIES = %w(all any)
UNACTIVATABLE_ORDER_STATES = ["complete", "awaiting_return", "returned"]
Activator.event_names << 'spree.checkout.coupon_code_added'
Activator.event_names << 'spree.content.visited'
has_many :promotion_rules, :foreign_key => 'activator_id', :autosave => true, :dependent => :destroy
alias_method :rules, :promotion_rules
accepts_nested_attributes_for :promotion_rules
has_many :promotion_actions, :foreign_key => 'activator_id', :autosave => true, :dependent => :destroy
alias_method :actions, :promotion_actions
accepts_nested_attributes_for :promotion_actions
validates_associated :rules
attr_accessible :name, :event_name, :code, :match_policy,
:path, :advertise, :description, :usage_limit,
:starts_at, :expires_at, :promotion_rules_attributes,
:promotion_actions_attributes
# TODO: This shouldn't be necessary with :autosave option but nested attribute updating of actions is broken without it
after_save :save_rules_and_actions
def save_rules_and_actions
(rules + actions).each &:save
end
validates :name, :presence => true
validates :code, :presence => true, :if => lambda{|r| r.event_name == 'spree.checkout.coupon_code_added' }
validates :path, :presence => true, :if => lambda{|r| r.event_name == 'spree.content.visited' }
validates :usage_limit, :numericality => { :greater_than => 0, :allow_nil => true }
def self.advertised
where(:advertise => true)
end
# TODO: Remove that after fix for https://rails.lighthouseapp.com/projects/8994/tickets/4329-has_many-through-association-does-not-link-models-on-association-save
# is provided
def save(*)
if super
promotion_rules.each(&:save)
end
end
def activate(payload)
return unless order_activatable? payload[:order]
if code.present?
event_code = payload[:coupon_code].to_s.strip.downcase
return unless event_code == self.code.to_s.strip.downcase
end
if path.present?
return unless path == payload[:path]
end
actions.each do |action|
action.perform(payload)
end
end
# called anytime order.update! happens
def eligible?(order)
return false if expired? || usage_limit_exceeded?(order)
rules_are_eligible?(order, {})
end
def rules_are_eligible?(order, options = {})
return true if rules.none?
eligible = lambda { |r| r.eligible?(order, options) }
if match_policy == 'all'
rules.all?(&eligible)
else
rules.any?(&eligible)
end
end
def order_activatable?(order)
order &&
created_at.to_i < order.created_at.to_i &&
!UNACTIVATABLE_ORDER_STATES.include?(order.state)
end
# Products assigned to all product rules
def products
@products ||= rules.of_type('Spree::Promotion::Rules::Product').map(&:products).flatten.uniq
end
def usage_limit_exceeded?(order = nil)
usage_limit.present? && usage_limit > 0 && adjusted_credits_count(order) >= usage_limit
end
def adjusted_credits_count(order)
return credits_count if order.nil?
credits_count - (order.promotion_credit_exists?(self) ? 1 : 0)
end
def credits
Adjustment.promotion.where(:originator_id => actions.map(&:id))
end
def credits_count
credits.count
end
end
end