Class: Pay::Braintree::Subscription
Constant Summary
Constants inherited
from Subscription
Subscription::STATUSES
Class Method Summary
collapse
Instance Method Summary
collapse
#active?, #canceled?, #cancelled?, #ended?, find_by_processor_and_id, #generic_trial?, #has_incomplete_payment?, #has_trial?, #incomplete?, #no_prorate, #on_grace_period?, #on_trial?, #past_due?, #skip_trial, #swap_and_invoice, #sync!, #trial_ended?, #unpaid?
Class Method Details
.sync(subscription_id, object: nil, name: nil, try: 0, retries: 1) ⇒ Object
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
|
# File 'app/models/pay/braintree/subscription.rb', line 4
def self.sync(subscription_id, object: nil, name: nil, try: 0, retries: 1)
object ||= Pay.braintree_gateway.subscription.find(subscription_id)
payment_method = Pay.braintree_gateway.payment_method.find(object.payment_method_token)
pay_customer = Pay::Customer.find_by(processor: :braintree, processor_id: payment_method.customer_id)
return unless pay_customer
pay_customer.save_payment_method(payment_method, default: payment_method.default?)
attributes = {
created_at: object.created_at,
current_period_end: object.billing_period_end_date,
current_period_start: object.billing_period_start_date,
payment_method_id: object.payment_method_token,
processor_plan: object.plan_id,
status: object.status.parameterize(separator: "_"),
trial_ends_at: (object.created_at + object.trial_duration.send(object.trial_duration_unit) if object.trial_period)
}
if object.status == "Canceled"
attributes[:ends_at] = object.updated_at
elsif object.status == "Active" && object.number_of_billing_cycles
attributes[:ends_at] = object.paid_through_date.end_of_day
end
pay_subscription = pay_customer.subscriptions.find_by(processor_id: object.id)
if pay_subscription
pay_subscription.with_lock { pay_subscription.update!(attributes) }
else
name ||= Pay.default_product_name
pay_subscription = pay_customer.subscriptions.create!(attributes.merge(name: name, processor_id: object.id))
end
pay_subscription
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
try += 1
if try <= retries
sleep 0.1
retry
else
raise
end
end
|
Instance Method Details
#api_record(**options) ⇒ Object
53
54
55
|
# File 'app/models/pay/braintree/subscription.rb', line 53
def api_record(**options)
gateway.subscription.find(processor_id)
end
|
#cancel(**options) ⇒ Object
57
58
59
60
61
62
63
64
65
66
67
68
69
|
# File 'app/models/pay/braintree/subscription.rb', line 57
def cancel(**options)
return if canceled?
result = if on_trial?
gateway.subscription.cancel(processor_id)
else
gateway.subscription.update(processor_id, {number_of_billing_cycles: api_record.current_billing_cycle})
end
sync!(object: result.subscription)
rescue ::Braintree::BraintreeError => e
raise Pay::Braintree::Error, e
end
|
#cancel_now!(**options) ⇒ Object
71
72
73
74
75
76
77
78
|
# File 'app/models/pay/braintree/subscription.rb', line 71
def cancel_now!(**options)
return if canceled?
result = gateway.subscription.cancel(processor_id)
sync!(object: result.subscription)
rescue ::Braintree::BraintreeError => e
raise Pay::Braintree::Error, e
end
|
#change_quantity(quantity, **options) ⇒ Object
80
81
82
|
# File 'app/models/pay/braintree/subscription.rb', line 80
def change_quantity(quantity, **options)
raise NotImplementedError, "Braintree does not support setting quantity on subscriptions"
end
|
#pause ⇒ Object
88
89
90
|
# File 'app/models/pay/braintree/subscription.rb', line 88
def pause
raise NotImplementedError, "Braintree does not support pausing subscriptions"
end
|
#paused? ⇒ Boolean
84
85
86
|
# File 'app/models/pay/braintree/subscription.rb', line 84
def paused?
false
end
|
#resumable? ⇒ Boolean
92
93
94
|
# File 'app/models/pay/braintree/subscription.rb', line 92
def resumable?
on_grace_period?
end
|
#resume ⇒ Object
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
|
# File 'app/models/pay/braintree/subscription.rb', line 96
def resume
unless resumable?
raise StandardError, "You can only resume subscriptions within their grace period."
end
if canceled? && on_trial?
duration = trial_ends_at.to_date - Date.today
customer.subscribe(
name: name,
plan: processor_plan,
trial_period: true,
trial_duration: duration.to_i,
trial_duration_unit: :day
)
else
gateway.subscription.update(processor_id, {
never_expires: true,
number_of_billing_cycles: nil
})
end
update(ends_at: nil, status: :active)
rescue ::Braintree::BraintreeError => e
raise Pay::Braintree::Error, e
end
|
#retry_failed_payment ⇒ Object
Retries the latest invoice for a Past Due subscription
160
161
162
163
164
165
166
167
168
169
170
|
# File 'app/models/pay/braintree/subscription.rb', line 160
def retry_failed_payment
result = gateway.subscription.retry_charge(
processor_id,
nil, true )
if result.success?
update(status: :active)
end
end
|
#swap(plan, **options) ⇒ Object
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
|
# File 'app/models/pay/braintree/subscription.rb', line 123
def swap(plan, **options)
raise ArgumentError, "plan must be a string" unless plan.is_a?(String)
if on_grace_period? && processor_plan == plan
resume
return
end
unless active?
customer.subscribe(name: name, plan: plan, trial_period: false)
return
end
braintree_plan = find_braintree_plan(plan)
if would_change_billing_frequency?(braintree_plan) && prorate?
swap_across_frequencies(braintree_plan)
return
end
result = gateway.subscription.update(processor_id, {
plan_id: braintree_plan.id,
price: braintree_plan.price,
never_expires: true,
number_of_billing_cycles: nil,
options: {
prorate_charges: prorate?
}
})
raise Error, "Braintree failed to swap plans: #{result.message}" unless result.success?
update(processor_plan: plan, ends_at: nil, status: :active)
rescue ::Braintree::BraintreeError => e
raise Pay::Braintree::Error, e
end
|