pay 2.2.0 → 2.4.0
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 +4 -4
- data/README.md +161 -11
- data/Rakefile +2 -4
- data/app/controllers/pay/payments_controller.rb +3 -0
- data/app/controllers/pay/webhooks/braintree_controller.rb +1 -1
- data/app/controllers/pay/webhooks/paddle_controller.rb +36 -0
- data/app/mailers/pay/user_mailer.rb +14 -35
- data/app/models/pay/application_record.rb +6 -1
- data/app/models/pay/charge.rb +7 -0
- data/app/models/pay/subscription.rb +27 -4
- data/app/views/pay/payments/show.html.erb +1 -1
- data/app/views/pay/user_mailer/payment_action_required.html.erb +1 -1
- data/app/views/pay/user_mailer/receipt.html.erb +6 -6
- data/app/views/pay/user_mailer/refund.html.erb +6 -6
- data/app/views/pay/user_mailer/subscription_renewing.html.erb +1 -1
- data/config/locales/en.yml +137 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20200603134434_add_data_to_pay_models.rb +17 -0
- data/lib/generators/active_record/pay_generator.rb +1 -1
- data/lib/generators/pay/orm_helpers.rb +1 -2
- data/lib/pay.rb +9 -41
- data/lib/pay/billable.rb +16 -11
- data/lib/pay/braintree/billable.rb +25 -19
- data/lib/pay/braintree/charge.rb +7 -3
- data/lib/pay/braintree/subscription.rb +15 -5
- data/lib/pay/engine.rb +7 -0
- data/lib/pay/errors.rb +73 -0
- data/lib/pay/paddle.rb +38 -0
- data/lib/pay/paddle/billable.rb +95 -0
- data/lib/pay/paddle/charge.rb +39 -0
- data/lib/pay/paddle/subscription.rb +70 -0
- data/lib/pay/paddle/webhooks.rb +1 -0
- data/lib/pay/paddle/webhooks/signature_verifier.rb +115 -0
- data/lib/pay/paddle/webhooks/subscription_cancelled.rb +18 -0
- data/lib/pay/paddle/webhooks/subscription_created.rb +59 -0
- data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +21 -0
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +43 -0
- data/lib/pay/paddle/webhooks/subscription_updated.rb +37 -0
- data/lib/pay/receipts.rb +6 -6
- data/lib/pay/stripe.rb +1 -1
- data/lib/pay/stripe/billable.rb +12 -6
- data/lib/pay/stripe/charge.rb +6 -2
- data/lib/pay/stripe/subscription.rb +15 -5
- data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -2
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +7 -7
- data/lib/pay/stripe/webhooks/payment_action_required.rb +7 -8
- data/lib/pay/stripe/webhooks/subscription_created.rb +1 -1
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +4 -3
- data/lib/pay/version.rb +1 -1
- metadata +35 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2166bd09d0f1dcafea1425635ec9346d4f7731c212fc695f46b0f2fedfa08d2e
|
4
|
+
data.tar.gz: b9a035ee4abda206db7e132e4ced798c5917829a5ecf94b1e89c587675a09cc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5689e3cc0f8eaa890a8a8483910a2ee96c2e893e7484195de2554f9931f650f23f5bb9c37e5ceeb8cbf2c07048d1b4e3b398dd7c3ce52eb2901bc08bbececb9
|
7
|
+
data.tar.gz: dc10f025e73b6e4e053f11ecdabfb954fc6178090a9e3e82533b9bc2a7d3fc867d7f4a94871427541997e551589f82a0943efb091d199a86e53c2b6ccbf48d2c
|
data/README.md
CHANGED
@@ -8,8 +8,9 @@ Pay is a payments engine for Ruby on Rails 4.2 and higher.
|
|
8
8
|
|
9
9
|
**Current Payment Providers**
|
10
10
|
|
11
|
-
- Stripe ([supports SCA](https://stripe.com/docs/strong-customer-authentication)
|
11
|
+
- Stripe ([supports SCA](https://stripe.com/docs/strong-customer-authentication) using API version `2020-08-27`)
|
12
12
|
- Braintree
|
13
|
+
- Paddle
|
13
14
|
|
14
15
|
Want to add a new payment provider? Contributions are welcome and the instructions [are here](https://github.com/jasoncharnes/pay/wiki/New-Payment-Provider).
|
15
16
|
|
@@ -35,6 +36,9 @@ gem 'stripe_event', '~> 2.3'
|
|
35
36
|
# To use Braintree + PayPal, also include:
|
36
37
|
gem 'braintree', '< 3.0', '>= 2.92.0'
|
37
38
|
|
39
|
+
# To use Paddle, also include:
|
40
|
+
gem 'paddle_pay', '~> 0.0.1'
|
41
|
+
|
38
42
|
# To use Receipts
|
39
43
|
gem 'receipts', '~> 1.0.0'
|
40
44
|
```
|
@@ -99,6 +103,9 @@ Pay.setup do |config|
|
|
99
103
|
|
100
104
|
config.send_emails = true
|
101
105
|
|
106
|
+
config.default_product_name = "default"
|
107
|
+
config.default_plan_name = "default"
|
108
|
+
|
102
109
|
config.automount_routes = true
|
103
110
|
config.routes_path = "/pay" # Only when automount_routes is true
|
104
111
|
end
|
@@ -133,10 +140,15 @@ development:
|
|
133
140
|
public_key: yyyy
|
134
141
|
merchant_id: aaaa
|
135
142
|
environment: sandbox
|
143
|
+
paddle:
|
144
|
+
vendor_id: xxxx
|
145
|
+
vendor_auth_code: yyyy
|
146
|
+
public_key_base64: MII...==
|
136
147
|
```
|
137
148
|
|
138
149
|
For Stripe, you can also use the `STRIPE_PUBLIC_KEY`, `STRIPE_PRIVATE_KEY` and `STRIPE_SIGNING_SECRET` environment variables.
|
139
150
|
For Braintree, you can also use `BRAINTREE_MERCHANT_ID`, `BRAINTREE_PUBLIC_KEY`, `BRAINTREE_PRIVATE_KEY`, and `BRAINTREE_ENVIRONMENT` environment variables.
|
151
|
+
For Paddle, you can also use `PADDLE_VENDOR_ID`, `PADDLE_VENDOR_AUTH_CODE` and `PADDLE_PUBLIC_KEY_BASE64` environment variables.
|
140
152
|
|
141
153
|
### Generators
|
142
154
|
|
@@ -196,6 +208,8 @@ user.on_generic_trial? #=> true
|
|
196
208
|
|
197
209
|
#### Creating a Charge
|
198
210
|
|
211
|
+
##### Stripe and Braintree
|
212
|
+
|
199
213
|
```ruby
|
200
214
|
user = User.find_by(email: 'michael@bluthcompany.co')
|
201
215
|
|
@@ -219,8 +233,23 @@ different currencies, etc.
|
|
219
233
|
On failure, a `Pay::Error` will be raised with details about the payment
|
220
234
|
failure.
|
221
235
|
|
236
|
+
##### Paddle
|
237
|
+
It is only possible to create immediate one-time charges on top of an existing subscription.
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
user = User.find_by(email: 'michael@bluthcompany.co')
|
241
|
+
|
242
|
+
user.processor = 'paddle'
|
243
|
+
user.charge(1500, {charge_name: "Test"}) # $15.00 USD
|
244
|
+
|
245
|
+
```
|
246
|
+
|
247
|
+
An existing subscription and a charge name are required.
|
248
|
+
|
222
249
|
#### Creating a Subscription
|
223
250
|
|
251
|
+
##### Stripe and Braintree
|
252
|
+
|
224
253
|
```ruby
|
225
254
|
user = User.find_by(email: 'michael@bluthcompany.co')
|
226
255
|
|
@@ -234,7 +263,7 @@ A `card_token` must be provided as an attribute.
|
|
234
263
|
The subscribe method has three optional arguments with default values.
|
235
264
|
|
236
265
|
```ruby
|
237
|
-
def subscribe(name:
|
266
|
+
def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
|
238
267
|
...
|
239
268
|
end
|
240
269
|
```
|
@@ -243,23 +272,56 @@ For example, you can pass the `quantity` option to subscribe to a plan with for
|
|
243
272
|
|
244
273
|
```ruby
|
245
274
|
|
246
|
-
user.subscribe(name:
|
275
|
+
user.subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, quantity: 3)
|
247
276
|
```
|
248
277
|
|
249
|
-
|
278
|
+
###### Name
|
250
279
|
|
251
280
|
Name is an internally used name for the subscription.
|
252
281
|
|
253
|
-
|
282
|
+
###### Plan
|
254
283
|
|
255
284
|
Plan is the plan ID or price ID from the payment processor. For example: `plan_xxxxx` or `price_xxxxx`
|
256
285
|
|
257
|
-
|
286
|
+
###### Options
|
258
287
|
|
259
288
|
By default, the trial specified on the subscription will be used.
|
260
289
|
|
261
290
|
`trial_period_days: 30` can be set to override and a trial to the subscription. This works the same for Braintree and Stripe.
|
262
291
|
|
292
|
+
##### Paddle
|
293
|
+
It is currently not possible to create a subscription through the API. Instead the subscription in Pay is created by the Paddle Subscription Webhook. In order to be able to assign the subcription to the correct owner, the Paddle [passthrough parameter](https://developer.paddle.com/guides/how-tos/checkout/pass-parameters) has to be used for checkout.
|
294
|
+
|
295
|
+
To ensure that the owner cannot be tampered with, Pay uses a Signed Global ID with a purpose. The purpose string consists of "paddle_" and the subscription plan id (or product id respectively).
|
296
|
+
|
297
|
+
Javascript Checkout:
|
298
|
+
```javascript
|
299
|
+
Paddle.Checkout.open({
|
300
|
+
product: 12345,
|
301
|
+
passthrough: "<%= Pay::Paddle.passthrough(owner: current_user) %>"
|
302
|
+
});
|
303
|
+
```
|
304
|
+
|
305
|
+
Paddle Button Checkout:
|
306
|
+
```html
|
307
|
+
<a href="#!" class="paddle_button" data-product="12345" data-email="<%= current_user.email %>" data-passthrough="<%= Pay::Paddle.passthrough(owner: current_user) %>"
|
308
|
+
```
|
309
|
+
|
310
|
+
###### Passthrough
|
311
|
+
|
312
|
+
Pay providers a helper method for generating the passthrough JSON object to associate the purchase with the correct Rails model.
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
Pay::Paddle.passthrough(owner: current_user, foo: :bar)
|
316
|
+
#=> { owner_sgid: "xxxxxxxx", foo: "bar" }
|
317
|
+
|
318
|
+
# To generate manually without the helper
|
319
|
+
#=> { owner_sgid: current_user.to_sgid.to_s, foo: "bar" }.to_json
|
320
|
+
```
|
321
|
+
|
322
|
+
Pay parses the passthrough JSON string and verifies the `owner_sgid` hash to match the webhook with the correct billable record.
|
323
|
+
The passthrough parameter `owner_sgid` is only required for creating a subscription.
|
324
|
+
|
263
325
|
#### Retrieving a Subscription from the Database
|
264
326
|
|
265
327
|
```ruby
|
@@ -316,26 +378,45 @@ Plan is the plan ID from the payment processor.
|
|
316
378
|
|
317
379
|
#### Retrieving a Payment Processor Account
|
318
380
|
|
381
|
+
##### Stripe and Braintree
|
382
|
+
|
319
383
|
```ruby
|
320
384
|
user = User.find_by(email: 'george.michael@bluthcompany.co')
|
321
385
|
|
322
386
|
user.customer #> Stripe or Braintree customer account
|
323
387
|
```
|
324
388
|
|
389
|
+
##### Paddle
|
390
|
+
|
391
|
+
It is currently not possible to retrieve a payment processor account through the API.
|
392
|
+
|
325
393
|
#### Updating a Customer's Credit Card
|
326
394
|
|
395
|
+
##### Stripe and Braintree
|
396
|
+
|
327
397
|
```ruby
|
328
398
|
user = User.find_by(email: 'tobias@bluthcompany.co')
|
329
399
|
|
330
400
|
user.update_card('payment_method_id')
|
331
401
|
```
|
332
402
|
|
403
|
+
##### Paddle
|
404
|
+
|
405
|
+
Paddle provides a unique [Update URL](https://developer.paddle.com/guides/how-tos/subscriptions/update-payment-details) for each user, which allows them to update the payment method.
|
406
|
+
```ruby
|
407
|
+
user = User.find_by(email: 'tobias@bluthcompany.co')
|
408
|
+
|
409
|
+
user.subscription.paddle_update_url
|
410
|
+
```
|
411
|
+
|
412
|
+
|
413
|
+
|
333
414
|
#### Retrieving a Customer's Subscription from the Processor
|
334
415
|
|
335
416
|
```ruby
|
336
417
|
user = User.find_by(email: 'lucille@bluthcompany.co')
|
337
418
|
|
338
|
-
user.processor_subscription(subscription_id) #=> Stripe or
|
419
|
+
user.processor_subscription(subscription_id) #=> Stripe, Braintree or Paddle Subscription
|
339
420
|
```
|
340
421
|
|
341
422
|
## Subscription API
|
@@ -372,14 +453,31 @@ user = User.find_by(email: 'carl.weathers@bluthcompany.co')
|
|
372
453
|
user.subscription.active? #=> true or false
|
373
454
|
```
|
374
455
|
|
456
|
+
#### Checking to See If a Subscription Is Paused
|
457
|
+
|
458
|
+
```ruby
|
459
|
+
user = User.find_by(email: 'carl.weathers@bluthcompany.co')
|
460
|
+
|
461
|
+
user.subscription.paused? #=> true or false
|
462
|
+
```
|
463
|
+
|
375
464
|
#### Cancel a Subscription (At End of Billing Cycle)
|
376
465
|
|
466
|
+
##### Stripe, Braintree and Paddle
|
467
|
+
|
377
468
|
```ruby
|
378
469
|
user = User.find_by(email: 'oscar@bluthcompany.co')
|
379
470
|
|
380
471
|
user.subscription.cancel
|
381
472
|
```
|
382
473
|
|
474
|
+
##### Paddle
|
475
|
+
In addition to the API, Paddle provides a subscription [Cancel URL](https://developer.paddle.com/guides/how-tos/subscriptions/cancel-and-pause) that you can redirect customers to cancel their subscription.
|
476
|
+
|
477
|
+
```ruby
|
478
|
+
user.subscription.paddle_cancel_url
|
479
|
+
```
|
480
|
+
|
383
481
|
#### Cancel a Subscription Immediately
|
384
482
|
|
385
483
|
```ruby
|
@@ -388,6 +486,16 @@ user = User.find_by(email: 'annyong@bluthcompany.co')
|
|
388
486
|
user.subscription.cancel_now!
|
389
487
|
```
|
390
488
|
|
489
|
+
#### Pause a Subscription
|
490
|
+
|
491
|
+
##### Paddle
|
492
|
+
|
493
|
+
```ruby
|
494
|
+
user = User.find_by(email: 'oscar@bluthcompany.co')
|
495
|
+
|
496
|
+
user.subscription.pause
|
497
|
+
```
|
498
|
+
|
391
499
|
#### Swap a Subscription to another Plan
|
392
500
|
|
393
501
|
```ruby
|
@@ -396,7 +504,17 @@ user = User.find_by(email: 'steve.holt@bluthcompany.co')
|
|
396
504
|
user.subscription.swap("yearly")
|
397
505
|
```
|
398
506
|
|
399
|
-
#### Resume a Subscription
|
507
|
+
#### Resume a Subscription
|
508
|
+
|
509
|
+
##### Stripe or Braintree Subscription (on Grace Period)
|
510
|
+
|
511
|
+
```ruby
|
512
|
+
user = User.find_by(email: 'steve.holt@bluthcompany.co')
|
513
|
+
|
514
|
+
user.subscription.resume
|
515
|
+
```
|
516
|
+
|
517
|
+
##### Paddle (Paused)
|
400
518
|
|
401
519
|
```ruby
|
402
520
|
user = User.find_by(email: 'steve.holt@bluthcompany.co')
|
@@ -473,8 +591,8 @@ config.routes_path = '/secret-webhook-path'
|
|
473
591
|
|
474
592
|
## Payment Providers
|
475
593
|
|
476
|
-
We support
|
477
|
-
standardize the
|
594
|
+
We support Stripe, Braintree and Paddle and make our best attempt to
|
595
|
+
standardize the three. They function differently so keep that in mind if
|
478
596
|
you plan on doing more complex payments. It would be best to stick with
|
479
597
|
a single payment provider in that case so you don't run into
|
480
598
|
discrepancies.
|
@@ -489,7 +607,22 @@ development:
|
|
489
607
|
merchant_id: zzzz
|
490
608
|
environment: sandbox
|
491
609
|
```
|
610
|
+
#### Paddle
|
492
611
|
|
612
|
+
```yaml
|
613
|
+
paddle:
|
614
|
+
vendor_id: xxxx
|
615
|
+
vendor_auth_code: yyyy
|
616
|
+
public_key_base64: MII...==
|
617
|
+
```
|
618
|
+
|
619
|
+
Paddle receipts can be retrieved by a charge receipt URL.
|
620
|
+
```ruby
|
621
|
+
user = User.find_by(email: 'annyong@bluthcompany.co')
|
622
|
+
|
623
|
+
charge = user.charges.first
|
624
|
+
charge.paddle_receipt_url
|
625
|
+
```
|
493
626
|
#### Stripe
|
494
627
|
|
495
628
|
You'll need to add your private Stripe API key to your Rails secrets `config/secrets.yml`, credentials `rails credentials:edit`
|
@@ -506,6 +639,20 @@ You can also use the `STRIPE_PRIVATE_KEY` and `STRIPE_SIGNING_SECRET` environmen
|
|
506
639
|
|
507
640
|
**To see how to use Stripe Elements JS & Devise, [click here](https://github.com/jasoncharnes/pay/wiki/Using-Stripe-Elements-and-Devise).**
|
508
641
|
|
642
|
+
You need the following event types to trigger the webhook:
|
643
|
+
|
644
|
+
```
|
645
|
+
customer.subscription.updated
|
646
|
+
customer.subscription.deleted
|
647
|
+
customer.subscription.created
|
648
|
+
payment_method.updated
|
649
|
+
invoice.payment_action_required
|
650
|
+
customer.updated
|
651
|
+
customer.deleted
|
652
|
+
charge.succeeded
|
653
|
+
charge.refunded
|
654
|
+
```
|
655
|
+
|
509
656
|
##### Strong Customer Authentication (SCA)
|
510
657
|
|
511
658
|
Our Stripe integration **requires** the use of Payment Method objects to correctly support Strong Customer Authentication with Stripe. If you've previously been using card tokens, you'll need to upgrade your Javascript integration.
|
@@ -552,7 +699,10 @@ If you have an issue you'd like to submit, please do so using the issue tracker
|
|
552
699
|
|
553
700
|
If you'd like to open a PR please make sure the following things pass:
|
554
701
|
|
555
|
-
|
702
|
+
```ruby
|
703
|
+
bin/rails db:test:prepare
|
704
|
+
bin/rails test
|
705
|
+
```
|
556
706
|
|
557
707
|
## License
|
558
708
|
|
data/Rakefile
CHANGED
@@ -4,6 +4,8 @@ rescue LoadError
|
|
4
4
|
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
5
5
|
end
|
6
6
|
|
7
|
+
require "bundler/gem_tasks"
|
8
|
+
|
7
9
|
require "rdoc/task"
|
8
10
|
|
9
11
|
RDoc::Task.new(:rdoc) do |rdoc|
|
@@ -19,10 +21,6 @@ load "rails/tasks/engine.rake"
|
|
19
21
|
|
20
22
|
load "rails/tasks/statistics.rake"
|
21
23
|
|
22
|
-
unless Rails.env.test?
|
23
|
-
require "bundler/gem_tasks"
|
24
|
-
end
|
25
|
-
|
26
24
|
require "rake/testtask"
|
27
25
|
|
28
26
|
Rake::TestTask.new(:test) do |t|
|
@@ -33,7 +33,7 @@ module Pay
|
|
33
33
|
charge = billable.save_braintree_transaction(subscription.transactions.first)
|
34
34
|
|
35
35
|
if Pay.send_emails
|
36
|
-
Pay::UserMailer.
|
36
|
+
Pay::UserMailer.with(billable: billable, charge: charge).receipt.deliver_later
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Pay
|
2
|
+
module Webhooks
|
3
|
+
class PaddleController < Pay::ApplicationController
|
4
|
+
if Rails.application.config.action_controller.default_protect_from_forgery
|
5
|
+
skip_before_action :verify_authenticity_token
|
6
|
+
end
|
7
|
+
|
8
|
+
def create
|
9
|
+
verifier = Pay::Paddle::Webhooks::SignatureVerifier.new(check_params.as_json)
|
10
|
+
if verifier.verify
|
11
|
+
case params["alert_name"]
|
12
|
+
when "subscription_created"
|
13
|
+
Pay::Paddle::Webhooks::SubscriptionCreated.new(check_params.as_json)
|
14
|
+
when "subscription_updated"
|
15
|
+
Pay::Paddle::Webhooks::SubscriptionUpdated.new(check_params.as_json)
|
16
|
+
when "subscription_cancelled"
|
17
|
+
Pay::Paddle::Webhooks::SubscriptionCancelled.new(check_params.as_json)
|
18
|
+
when "subscription_payment_succeeded"
|
19
|
+
Pay::Paddle::Webhooks::SubscriptionPaymentSucceeded.new(check_params.as_json)
|
20
|
+
when "subscription_payment_refunded"
|
21
|
+
Pay::Paddle::Webhooks::SubscriptionPaymentRefunded.new(check_params.as_json)
|
22
|
+
end
|
23
|
+
render json: {success: true}, status: :ok
|
24
|
+
else
|
25
|
+
head :ok
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def check_params
|
32
|
+
params.except(:action, :controller).permit!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,53 +1,32 @@
|
|
1
1
|
module Pay
|
2
2
|
class UserMailer < ApplicationMailer
|
3
|
-
def receipt
|
4
|
-
|
5
|
-
|
6
|
-
if charge.respond_to? :receipt
|
7
|
-
attachments[charge.filename] = charge.receipt
|
3
|
+
def receipt
|
4
|
+
if params[:charge].respond_to? :receipt
|
5
|
+
attachments[params[:charge].filename] = params[:charge].receipt
|
8
6
|
end
|
9
7
|
|
10
|
-
mail
|
11
|
-
to: to(user),
|
12
|
-
subject: Pay.email_receipt_subject
|
13
|
-
)
|
8
|
+
mail to: to
|
14
9
|
end
|
15
10
|
|
16
|
-
def refund
|
17
|
-
|
18
|
-
|
19
|
-
mail(
|
20
|
-
to: to(user),
|
21
|
-
subject: Pay.email_refund_subject
|
22
|
-
)
|
11
|
+
def refund
|
12
|
+
mail to: to
|
23
13
|
end
|
24
14
|
|
25
|
-
def subscription_renewing
|
26
|
-
|
27
|
-
|
28
|
-
mail(
|
29
|
-
to: to(user),
|
30
|
-
subject: Pay.email_renewing_subject
|
31
|
-
)
|
15
|
+
def subscription_renewing
|
16
|
+
mail to: to
|
32
17
|
end
|
33
18
|
|
34
|
-
def payment_action_required
|
35
|
-
|
36
|
-
@user, @payment, @subscription = user, payment, subscription
|
37
|
-
|
38
|
-
mail(
|
39
|
-
to: to(user),
|
40
|
-
subject: Pay.payment_action_required_subject
|
41
|
-
)
|
19
|
+
def payment_action_required
|
20
|
+
mail to: to
|
42
21
|
end
|
43
22
|
|
44
23
|
private
|
45
24
|
|
46
|
-
def to
|
47
|
-
if
|
48
|
-
"#{
|
25
|
+
def to
|
26
|
+
if params[:billable].respond_to?(:customer_name)
|
27
|
+
"#{params[:billable].customer_name} <#{params[:billable].email}>"
|
49
28
|
else
|
50
|
-
|
29
|
+
params[:billable].email
|
51
30
|
end
|
52
31
|
end
|
53
32
|
end
|