/
subscription.rb
196 lines (147 loc) · 5.55 KB
/
subscription.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
class Spree::Subscription < ActiveRecord::Base
def self.create_from_order(order,line_item)
# get subscription info TODO: load from product configuration.
interval = "month"
duration = 1
s = Spree::Subscription.create(:interval => interval,
:duration => duration,
:user => order.user,
:variant => line_item.variant,
:price => line_item.price,
:next_payment_at => Time.now + eval(duration.to_s + "." + interval.to_s),
:creditcard => order.creditcards[0],
:created_by_order_id => order.id,
:gateway => order.payment_method)
return s
end
def get_gateway
return self.gateway if not self.gateway.nil?
return self.parent_order.payment_method if not self.parent_order.nil?
end
attr_accessible :user,:variant,:creditcard,:parent_order,:ship_address,:bill_address,:expiry_notifications,:price,:state
attr_accessible :interval, :duration, :next_payment_at, :created_by_order_id,:gateway
belongs_to :user
belongs_to :variant
belongs_to :creditcard
belongs_to :gateway
belongs_to :parent_order, :class_name => "Spree::Order", :foreign_key => :created_by_order_id
belongs_to :ship_address, :foreign_key => :shipping_address_id
belongs_to :bill_address, :foreign_key => :billing_address_id
has_many :expiry_notifications
has_many :subsequent_orders, :class_name => "Spree::Order", :foreign_key => :created_by_subscription_id
accepts_nested_attributes_for :creditcard
validates :price, :presence => true, :numericality => true
validate :check_whole_dollar_amount
state_machine :state, :initial => :created do
event :cancel do
transition :to => :canceled, :if => :allow_cancel?
end
event :expire do
transition :to => :expired
end
event :reactivate do
transition :to => :active, :from => [:expired, :error, :declined]
end
event :activate do
transition :to => :active, :from => [:created]
end
event :renew do
transition :active => same
end
event :declined do
transition :active => :error, :if => :third_decline?
transition :active => same
end
after_transition :on => :renew, :do => [:on_renew,:reset_declined_count]
before_transition :on => :reactivate, :do => :reset_declined_count
before_transition :on => :declined, :do => :bump_up_declined_count
after_transition :on => :renew, :do => :renew_subscription
end
scope :backlog, lambda{{:conditions => ["next_payment_at <= ? ", Time.now] }}
scope :active, lambda{{:conditions => {:state => "active"}}}
scope :created, lambda{{:conditions => {:state => "created"}}}
def allow_cancel?
self.state != 'canceled'
end
def inactive?
self.state != 'active'
end
def check_whole_dollar_amount
# why does this need to be true?
errors.add(:price,"should be a whole dollar amount") if self.price.to_i != self.price
end
def due_on
next_payment_at
end
def due_soon?
next_payment_at < Time.now + 1.week
end
def on_renew
self.update_attribute(:next_payment_at, next_payment_at + eval(self.duration.to_s + "." + self.interval.to_s))
end
def backlogged?
self.next_payment_at <= Time.now ? true : false
end
def reset_declined_count
self.update_attribute(:declined_count , 0)
end
def third_decline?
self.declined_count >= 2
end
def subscription_bill_address
self.billing_address || self.parent_order.bill_address
end
def subscription_ship_address
self.ship_address || self.parent_order.ship_address
end
def latest_subsequent_order
self.subsequent_orders.order('created_at DESC').first
end
def bump_up_declined_count
self.declined_count += 1
end
def available_payment_methods
@available_payment_methods ||= Spree::PaymentMethod.available(:front_end)
end
def payment_method
# if payment and payment.payment_method
# payment.payment_method
# else
available_payment_methods.first
# end
end
def renew_subscription
new_order = self.subsequent_orders.build
new_order.save!
new_order.user = self.user
new_order.bill_address = self.bill_address
new_order.ship_address = self.ship_address
new_order.email = self.user.email
#Add a line item from the variant on this sub and set the price
new_order.add_variant( self.variant )
#NOTE settting quantity as opposed to price becuase during processing payments the order and price will get flipped
new_order.line_items.first.quantity = self.price.to_i #doing this will clip a price like 8.8 to 8)
new_order.line_items.first.price = 1
new_order.save!
#Process payment for the order
new_payment = Spree::Payment.new
new_payment.amount = new_order.total
new_payment.source = self.creditcard
new_payment.payment_method = self.gateway
new_order.payments << new_payment
new_order.update! #updating totals
#By setting to confirm we can do new_order.next and we get all the same
#callbacks as if you were on the order form itself
new_order.state = 'confirm'
new_order.next
new_order.save!
if new_order.payments.last.state == 'completed'
self.reset_declined_count
puts "Subscription renewed"
else
self.declined
# SubscriptionsMailer.declined_creditcard_message(sub).deliver
puts "There was an error proccesing the subscription. Subscription state set to 'error'. Subscription not renewed"
end
end
end