pay 0.0.2 → 1.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pay might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +256 -29
- data/Rakefile +1 -6
- data/app/controllers/pay/webhooks/braintree_controller.rb +56 -0
- data/app/jobs/pay/email_sync_job.rb +12 -0
- data/app/mailers/pay/user_mailer.rb +42 -0
- data/app/models/pay/charge.rb +31 -0
- data/app/models/pay/subscription.rb +77 -0
- data/app/views/pay/user_mailer/receipt.html.erb +20 -0
- data/app/views/pay/user_mailer/refund.html.erb +21 -0
- data/app/views/pay/user_mailer/subscription_renewing.html.erb +6 -0
- data/config/routes.rb +3 -1
- data/db/migrate/20170205020145_create_subscriptions.rb +1 -1
- data/db/migrate/20170503131610_add_fields_to_users.rb +3 -2
- data/db/migrate/20170727235816_create_charges.rb +17 -0
- data/lib/generators/pay/email_views_generator.rb +13 -0
- data/lib/pay.rb +65 -1
- data/lib/pay/billable.rb +54 -24
- data/lib/pay/billable/sync_email.rb +41 -0
- data/lib/pay/braintree.rb +16 -0
- data/lib/pay/braintree/api.rb +30 -0
- data/lib/pay/braintree/billable.rb +219 -0
- data/lib/pay/braintree/charge.rb +27 -0
- data/lib/pay/braintree/subscription.rb +173 -0
- data/lib/pay/engine.rb +14 -1
- data/lib/pay/receipts.rb +37 -0
- data/lib/pay/stripe.rb +17 -0
- data/lib/pay/stripe/api.rb +13 -0
- data/lib/pay/stripe/billable.rb +143 -0
- data/lib/pay/stripe/charge.rb +30 -0
- data/lib/pay/stripe/subscription.rb +48 -0
- data/lib/pay/stripe/webhooks.rb +39 -0
- data/lib/pay/stripe/webhooks/charge_refunded.rb +25 -0
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +47 -0
- data/lib/pay/stripe/webhooks/customer_deleted.rb +31 -0
- data/lib/pay/stripe/webhooks/customer_updated.rb +19 -0
- data/lib/pay/stripe/webhooks/source_deleted.rb +19 -0
- data/lib/pay/stripe/webhooks/subscription_created.rb +46 -0
- data/lib/pay/stripe/webhooks/subscription_deleted.rb +21 -0
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +25 -0
- data/lib/pay/stripe/webhooks/subscription_updated.rb +35 -0
- data/lib/pay/version.rb +1 -1
- metadata +124 -30
- data/app/models/subscription.rb +0 -59
- data/config/initializers/pay.rb +0 -3
- data/config/initializers/stripe.rb +0 -1
- data/db/development.sqlite3 +0 -0
- data/lib/pay/billable/braintree.rb +0 -57
- data/lib/pay/billable/stripe.rb +0 -47
- data/lib/tasks/pay_tasks.rake +0 -4
@@ -0,0 +1,19 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
module Webhooks
|
4
|
+
|
5
|
+
class CustomerUpdated
|
6
|
+
def call(event)
|
7
|
+
object = event.data.object
|
8
|
+
user = Pay.user_model.find_by(processor: :stripe, processor_id: object.id)
|
9
|
+
|
10
|
+
# Couldn't find user, we can skip
|
11
|
+
return unless user.present?
|
12
|
+
|
13
|
+
user.sync_card_from_stripe
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
module Webhooks
|
4
|
+
|
5
|
+
class SourceDeleted
|
6
|
+
def call(event)
|
7
|
+
object = event.data.object
|
8
|
+
user = Pay.user_model.find_by(processor: :stripe, processor_id: object.customer)
|
9
|
+
|
10
|
+
# Couldn't find user, we can skip
|
11
|
+
return unless user.present?
|
12
|
+
|
13
|
+
user.sync_card_from_stripe
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
module Webhooks
|
4
|
+
|
5
|
+
class SubscriptionCreated
|
6
|
+
def call(event)
|
7
|
+
object = event.data.object
|
8
|
+
|
9
|
+
# We may already have the subscription in the database, so we can update that record
|
10
|
+
subscription = Pay.subscription_model.find_by(processor: :stripe, processor_id: object.id)
|
11
|
+
|
12
|
+
if subscription.nil?
|
13
|
+
# The customer should already be in the database
|
14
|
+
owner = Pay.user_model.find_by(processor: :stripe, processor_id: object.customer)
|
15
|
+
|
16
|
+
Rails.logger.error("[Pay] Unable to find #{Pay.user_model} with processor: :stripe and processor_id: '#{object.customer}'")
|
17
|
+
return if owner.nil?
|
18
|
+
|
19
|
+
subscription = Pay.subscription_model.new(owner: owner)
|
20
|
+
end
|
21
|
+
|
22
|
+
subscription.quantity = object.quantity
|
23
|
+
subscription.processor_plan = object.plan.id
|
24
|
+
subscription.trial_ends_at = Time.at(object.trial_end) if object.trial_end.present?
|
25
|
+
|
26
|
+
# If user was on trial, their subscription ends at the end of the trial
|
27
|
+
if object.cancel_at_period_end && subscription.on_trial?
|
28
|
+
subscription.ends_at = subscription.trial_ends_at
|
29
|
+
|
30
|
+
# User wasn't on trial, so subscription ends at period end
|
31
|
+
elsif object.cancel_at_period_end
|
32
|
+
subscription.ends_at = Time.at(object.current_period_end)
|
33
|
+
|
34
|
+
# Subscription isn't marked to cancel at period end
|
35
|
+
else
|
36
|
+
subscription.ends_at = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
subscription.save!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
module Webhooks
|
4
|
+
|
5
|
+
class SubscriptionDeleted
|
6
|
+
def call(event)
|
7
|
+
object = event.data.object
|
8
|
+
subscription = Pay.subscription_model.find_by(processor: :stripe, processor_id: object.id)
|
9
|
+
|
10
|
+
# We couldn't find the subscription for some reason, maybe it's from another service
|
11
|
+
return if subscription.nil?
|
12
|
+
|
13
|
+
# User canceled subscriptions have an ends_at
|
14
|
+
# Automatically canceled subscriptions need this value set
|
15
|
+
subscription.update!(ends_at: Time.at(object.ended_at)) if subscription.ends_at.blank? && object.ended_at.present?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
module Webhooks
|
4
|
+
|
5
|
+
class SubscriptionRenewing
|
6
|
+
def call(event)
|
7
|
+
# Event is of type "invoice" see:
|
8
|
+
# https://stripe.com/docs/api/invoices/object
|
9
|
+
subscription = Pay.subscription_model.find_by(
|
10
|
+
processor: :stripe,
|
11
|
+
processor_id: event.data.object.subscription
|
12
|
+
)
|
13
|
+
notify_user(subscription.owner, subscription) if subscription.present?
|
14
|
+
end
|
15
|
+
|
16
|
+
def notify_user(user, subscription)
|
17
|
+
if Pay.send_emails
|
18
|
+
Pay::UserMailer.subscription_renewing(user, subscription).deliver_later
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Pay
|
2
|
+
module Stripe
|
3
|
+
module Webhooks
|
4
|
+
|
5
|
+
class SubscriptionUpdated
|
6
|
+
def call(event)
|
7
|
+
object = event.data.object
|
8
|
+
subscription = Pay.subscription_model.find_by(processor: :stripe, processor_id: object.id)
|
9
|
+
|
10
|
+
return if subscription.nil?
|
11
|
+
|
12
|
+
subscription.quantity = object.quantity
|
13
|
+
subscription.processor_plan = object.plan.id
|
14
|
+
subscription.trial_ends_at = Time.at(object.trial_end) if object.trial_end.present?
|
15
|
+
|
16
|
+
# If user was on trial, their subscription ends at the end of the trial
|
17
|
+
if object.cancel_at_period_end && subscription.on_trial?
|
18
|
+
subscription.ends_at = subscription.trial_ends_at
|
19
|
+
|
20
|
+
# User wasn't on trial, so subscription ends at period end
|
21
|
+
elsif object.cancel_at_period_end
|
22
|
+
subscription.ends_at = Time.at(object.current_period_end)
|
23
|
+
|
24
|
+
# Subscription isn't marked to cancel at period end
|
25
|
+
else
|
26
|
+
subscription.ends_at = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
subscription.save!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/pay/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 1.0.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Charnes
|
8
|
+
- Chris Oliver
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2019-03-11 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rails
|
@@ -25,33 +26,87 @@ dependencies:
|
|
25
26
|
- !ruby/object:Gem::Version
|
26
27
|
version: '4.2'
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
29
|
+
name: rails-html-sanitizer
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
32
|
- - "~>"
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
+
version: 1.0.4
|
34
35
|
type: :runtime
|
35
36
|
prerelease: false
|
36
37
|
version_requirements: !ruby/object:Gem::Requirement
|
37
38
|
requirements:
|
38
39
|
- - "~>"
|
39
40
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
41
|
+
version: 1.0.4
|
41
42
|
- !ruby/object:Gem::Dependency
|
42
43
|
name: braintree
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 2.92.0
|
49
|
+
- - "<"
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '3.0'
|
52
|
+
type: :development
|
53
|
+
prerelease: false
|
54
|
+
version_requirements: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: 2.92.0
|
59
|
+
- - "<"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: stripe
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.8'
|
69
|
+
- - "<"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '5.0'
|
72
|
+
type: :development
|
73
|
+
prerelease: false
|
74
|
+
version_requirements: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '2.8'
|
79
|
+
- - "<"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '5.0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: stripe_event
|
43
84
|
requirement: !ruby/object:Gem::Requirement
|
44
85
|
requirements:
|
45
86
|
- - "~>"
|
46
87
|
- !ruby/object:Gem::Version
|
47
|
-
version: '2.
|
48
|
-
type: :
|
88
|
+
version: '2.2'
|
89
|
+
type: :development
|
49
90
|
prerelease: false
|
50
91
|
version_requirements: !ruby/object:Gem::Requirement
|
51
92
|
requirements:
|
52
93
|
- - "~>"
|
53
94
|
- !ruby/object:Gem::Version
|
54
|
-
version: '2.
|
95
|
+
version: '2.2'
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: bundler
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "<"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '2'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "<"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '2'
|
55
110
|
- !ruby/object:Gem::Dependency
|
56
111
|
name: byebug
|
57
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,21 +150,35 @@ dependencies:
|
|
95
150
|
- !ruby/object:Gem::Version
|
96
151
|
version: '0'
|
97
152
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
153
|
+
name: sqlite3
|
99
154
|
requirement: !ruby/object:Gem::Requirement
|
100
155
|
requirements:
|
101
|
-
- - "
|
156
|
+
- - "~>"
|
102
157
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
158
|
+
version: 1.3.6
|
104
159
|
type: :development
|
105
160
|
prerelease: false
|
106
161
|
version_requirements: !ruby/object:Gem::Requirement
|
107
162
|
requirements:
|
108
|
-
- - "
|
163
|
+
- - "~>"
|
109
164
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
165
|
+
version: 1.3.6
|
111
166
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
167
|
+
name: stripe-ruby-mock
|
168
|
+
requirement: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '2.5'
|
173
|
+
type: :development
|
174
|
+
prerelease: false
|
175
|
+
version_requirements: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - "~>"
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '2.5'
|
180
|
+
- !ruby/object:Gem::Dependency
|
181
|
+
name: vcr
|
113
182
|
requirement: !ruby/object:Gem::Requirement
|
114
183
|
requirements:
|
115
184
|
- - ">="
|
@@ -123,22 +192,23 @@ dependencies:
|
|
123
192
|
- !ruby/object:Gem::Version
|
124
193
|
version: '0'
|
125
194
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
195
|
+
name: webmock
|
127
196
|
requirement: !ruby/object:Gem::Requirement
|
128
197
|
requirements:
|
129
|
-
- - "
|
198
|
+
- - ">="
|
130
199
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
200
|
+
version: '0'
|
132
201
|
type: :development
|
133
202
|
prerelease: false
|
134
203
|
version_requirements: !ruby/object:Gem::Requirement
|
135
204
|
requirements:
|
136
|
-
- - "
|
205
|
+
- - ">="
|
137
206
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
207
|
+
version: '0'
|
139
208
|
description: A Ruby on Rails subscription engine.
|
140
209
|
email:
|
141
210
|
- jason@thecharnes.com
|
211
|
+
- excid3@gmail.com
|
142
212
|
executables: []
|
143
213
|
extensions: []
|
144
214
|
extra_rdoc_files: []
|
@@ -150,25 +220,50 @@ files:
|
|
150
220
|
- app/assets/javascripts/pay/application.js
|
151
221
|
- app/assets/stylesheets/pay/application.css
|
152
222
|
- app/controllers/pay/application_controller.rb
|
223
|
+
- app/controllers/pay/webhooks/braintree_controller.rb
|
153
224
|
- app/helpers/pay/application_helper.rb
|
154
225
|
- app/jobs/pay/application_job.rb
|
226
|
+
- app/jobs/pay/email_sync_job.rb
|
155
227
|
- app/mailers/pay/application_mailer.rb
|
228
|
+
- app/mailers/pay/user_mailer.rb
|
156
229
|
- app/models/pay/application_record.rb
|
157
|
-
- app/models/
|
230
|
+
- app/models/pay/charge.rb
|
231
|
+
- app/models/pay/subscription.rb
|
158
232
|
- app/views/layouts/pay/application.html.erb
|
159
|
-
-
|
160
|
-
-
|
233
|
+
- app/views/pay/user_mailer/receipt.html.erb
|
234
|
+
- app/views/pay/user_mailer/refund.html.erb
|
235
|
+
- app/views/pay/user_mailer/subscription_renewing.html.erb
|
161
236
|
- config/routes.rb
|
162
|
-
- db/development.sqlite3
|
163
237
|
- db/migrate/20170205020145_create_subscriptions.rb
|
164
238
|
- db/migrate/20170503131610_add_fields_to_users.rb
|
239
|
+
- db/migrate/20170727235816_create_charges.rb
|
240
|
+
- lib/generators/pay/email_views_generator.rb
|
165
241
|
- lib/pay.rb
|
166
242
|
- lib/pay/billable.rb
|
167
|
-
- lib/pay/billable/
|
168
|
-
- lib/pay/
|
243
|
+
- lib/pay/billable/sync_email.rb
|
244
|
+
- lib/pay/braintree.rb
|
245
|
+
- lib/pay/braintree/api.rb
|
246
|
+
- lib/pay/braintree/billable.rb
|
247
|
+
- lib/pay/braintree/charge.rb
|
248
|
+
- lib/pay/braintree/subscription.rb
|
169
249
|
- lib/pay/engine.rb
|
250
|
+
- lib/pay/receipts.rb
|
251
|
+
- lib/pay/stripe.rb
|
252
|
+
- lib/pay/stripe/api.rb
|
253
|
+
- lib/pay/stripe/billable.rb
|
254
|
+
- lib/pay/stripe/charge.rb
|
255
|
+
- lib/pay/stripe/subscription.rb
|
256
|
+
- lib/pay/stripe/webhooks.rb
|
257
|
+
- lib/pay/stripe/webhooks/charge_refunded.rb
|
258
|
+
- lib/pay/stripe/webhooks/charge_succeeded.rb
|
259
|
+
- lib/pay/stripe/webhooks/customer_deleted.rb
|
260
|
+
- lib/pay/stripe/webhooks/customer_updated.rb
|
261
|
+
- lib/pay/stripe/webhooks/source_deleted.rb
|
262
|
+
- lib/pay/stripe/webhooks/subscription_created.rb
|
263
|
+
- lib/pay/stripe/webhooks/subscription_deleted.rb
|
264
|
+
- lib/pay/stripe/webhooks/subscription_renewing.rb
|
265
|
+
- lib/pay/stripe/webhooks/subscription_updated.rb
|
170
266
|
- lib/pay/version.rb
|
171
|
-
- lib/tasks/pay_tasks.rake
|
172
267
|
homepage: https://github.com/jasoncharnes/pay
|
173
268
|
licenses:
|
174
269
|
- MIT
|
@@ -184,12 +279,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
279
|
version: '0'
|
185
280
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
281
|
requirements:
|
187
|
-
- - "
|
282
|
+
- - ">"
|
188
283
|
- !ruby/object:Gem::Version
|
189
|
-
version:
|
284
|
+
version: 1.3.1
|
190
285
|
requirements: []
|
191
|
-
|
192
|
-
rubygems_version: 2.6.12
|
286
|
+
rubygems_version: 3.0.1
|
193
287
|
signing_key:
|
194
288
|
specification_version: 4
|
195
289
|
summary: A Ruby on Rails subscription engine.
|
data/app/models/subscription.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
class Subscription < ApplicationRecord
|
2
|
-
# Associations
|
3
|
-
belongs_to :owner, class_name: Pay.billable_class, foreign_key: :owner_id
|
4
|
-
|
5
|
-
# Validations
|
6
|
-
validates :name, presence: true
|
7
|
-
validates :processor, presence: true
|
8
|
-
validates :processor_id, presence: true
|
9
|
-
validates :processor_plan, presence: true
|
10
|
-
validates :quantity, presence: true
|
11
|
-
|
12
|
-
# Scopes
|
13
|
-
scope :for_name, ->(name) { where(name: name) }
|
14
|
-
|
15
|
-
def on_trial?
|
16
|
-
trial_ends_at? && Time.zone.now < trial_ends_at
|
17
|
-
end
|
18
|
-
|
19
|
-
def cancelled?
|
20
|
-
ends_at?
|
21
|
-
end
|
22
|
-
|
23
|
-
def on_grace_period?
|
24
|
-
cancelled? && Time.zone.now < ends_at
|
25
|
-
end
|
26
|
-
|
27
|
-
def active?
|
28
|
-
ends_at.nil? || on_grace_period? || on_trial?
|
29
|
-
end
|
30
|
-
|
31
|
-
def cancel
|
32
|
-
subscription = processor_subscription.delete(at_period_end: true)
|
33
|
-
update(ends_at: Time.at(subscription.current_period_end))
|
34
|
-
end
|
35
|
-
|
36
|
-
def cancel_now!
|
37
|
-
subscription = processor_subscription.delete
|
38
|
-
update(ends_at: Time.at(subscription.current_period_end))
|
39
|
-
end
|
40
|
-
|
41
|
-
def resume
|
42
|
-
unless on_grace_period?
|
43
|
-
raise StandardError,
|
44
|
-
'You can only resume subscriptions within their grace period.'
|
45
|
-
end
|
46
|
-
|
47
|
-
subscription = processor_subscription
|
48
|
-
subscription.plan = processor_plan
|
49
|
-
subscription.trial_end = on_trial? ? trial_ends_at.to_i : 'now'
|
50
|
-
subscription.save
|
51
|
-
|
52
|
-
update(ends_at: nil)
|
53
|
-
self
|
54
|
-
end
|
55
|
-
|
56
|
-
def processor_subscription
|
57
|
-
owner.processor_subscription(processor_id)
|
58
|
-
end
|
59
|
-
end
|