pay 2.6.11 → 3.0.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 +35 -693
- data/app/controllers/pay/webhooks/braintree_controller.rb +10 -3
- data/app/controllers/pay/webhooks/paddle_controller.rb +7 -8
- data/app/controllers/pay/webhooks/stripe_controller.rb +6 -3
- data/app/jobs/pay/{email_sync_job.rb → customer_sync_job.rb} +3 -4
- data/app/models/pay/application_record.rb +1 -5
- data/app/models/pay/charge.rb +32 -17
- data/app/models/pay/customer.rb +87 -0
- data/app/models/pay/merchant.rb +19 -0
- data/app/models/pay/payment_method.rb +41 -0
- data/app/models/pay/subscription.rb +34 -30
- data/app/models/pay/webhook.rb +36 -0
- data/app/views/layouts/pay/application.html.erb +2 -3
- data/app/views/pay/payments/show.html.erb +109 -81
- data/app/views/pay/user_mailer/receipt.html.erb +2 -2
- data/app/views/pay/user_mailer/refund.html.erb +2 -2
- data/config/locales/en.yml +1 -1
- data/db/migrate/1_create_pay_tables.rb +72 -0
- data/lib/generators/active_record/billable_generator.rb +44 -0
- data/lib/generators/active_record/merchant_generator.rb +44 -0
- data/lib/generators/active_record/templates/billable_migration.rb +17 -0
- data/lib/generators/active_record/templates/merchant_migration.rb +12 -0
- data/lib/generators/pay/{pay_generator.rb → billable_generator.rb} +2 -3
- data/lib/generators/pay/merchant_generator.rb +17 -0
- data/lib/generators/pay/orm_helpers.rb +10 -6
- data/lib/pay/adapter.rb +22 -0
- data/lib/pay/attributes.rb +74 -0
- data/lib/pay/billable/sync_customer.rb +30 -0
- data/lib/pay/braintree/billable.rb +130 -105
- data/lib/pay/braintree/payment_method.rb +33 -0
- data/lib/pay/braintree/subscription.rb +9 -12
- data/lib/pay/braintree/webhooks/subscription_canceled.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_charged_successfully.rb +4 -4
- data/lib/pay/braintree/webhooks/subscription_charged_unsuccessfully.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_expired.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_trial_ended.rb +2 -2
- data/lib/pay/braintree/webhooks/subscription_went_active.rb +1 -1
- data/lib/pay/braintree/webhooks/subscription_went_past_due.rb +1 -1
- data/lib/pay/braintree.rb +3 -2
- data/lib/pay/engine.rb +6 -1
- data/lib/pay/env.rb +8 -0
- data/lib/pay/fake_processor/billable.rb +45 -21
- data/lib/pay/fake_processor/payment_method.rb +21 -0
- data/lib/pay/fake_processor/subscription.rb +11 -8
- data/lib/pay/fake_processor.rb +2 -1
- data/lib/pay/merchant.rb +37 -0
- data/lib/pay/nano_id.rb +13 -0
- data/lib/pay/paddle/billable.rb +18 -48
- data/lib/pay/paddle/charge.rb +5 -5
- data/lib/pay/paddle/payment_method.rb +58 -0
- data/lib/pay/paddle/response.rb +0 -0
- data/lib/pay/paddle/subscription.rb +49 -8
- data/lib/pay/paddle/webhooks/subscription_cancelled.rb +6 -3
- data/lib/pay/paddle/webhooks/subscription_created.rb +1 -40
- data/lib/pay/paddle/webhooks/subscription_payment_refunded.rb +3 -3
- data/lib/pay/paddle/webhooks/subscription_payment_succeeded.rb +23 -23
- data/lib/pay/paddle/webhooks/subscription_updated.rb +2 -2
- data/lib/pay/paddle.rb +7 -3
- data/lib/pay/payment.rb +1 -1
- data/lib/pay/receipts.rb +35 -7
- data/lib/pay/stripe/billable.rb +82 -93
- data/lib/pay/stripe/charge.rb +65 -4
- data/lib/pay/stripe/merchant.rb +66 -0
- data/lib/pay/stripe/payment_method.rb +61 -0
- data/lib/pay/stripe/subscription.rb +91 -24
- data/lib/pay/stripe/webhooks/account_updated.rb +16 -0
- data/lib/pay/stripe/webhooks/charge_refunded.rb +2 -7
- data/lib/pay/stripe/webhooks/charge_succeeded.rb +2 -8
- data/lib/pay/stripe/webhooks/checkout_session_async_payment_succeeded.rb +15 -0
- data/lib/pay/stripe/webhooks/checkout_session_completed.rb +15 -0
- data/lib/pay/stripe/webhooks/customer_deleted.rb +7 -15
- data/lib/pay/stripe/webhooks/customer_updated.rb +10 -3
- data/lib/pay/stripe/webhooks/payment_action_required.rb +2 -2
- data/lib/pay/stripe/webhooks/payment_intent_succeeded.rb +6 -14
- data/lib/pay/stripe/webhooks/payment_method_attached.rb +15 -0
- data/lib/pay/stripe/webhooks/payment_method_detached.rb +12 -0
- data/lib/pay/stripe/webhooks/payment_method_updated.rb +10 -4
- data/lib/pay/stripe/webhooks/subscription_created.rb +1 -35
- data/lib/pay/stripe/webhooks/subscription_deleted.rb +2 -9
- data/lib/pay/stripe/webhooks/subscription_renewing.rb +14 -6
- data/lib/pay/stripe/webhooks/subscription_updated.rb +1 -28
- data/lib/pay/stripe.rb +17 -3
- data/lib/pay/version.rb +1 -1
- data/lib/pay/webhooks/delegator.rb +4 -0
- data/lib/pay/webhooks/process_job.rb +9 -0
- data/lib/pay/webhooks.rb +1 -0
- data/lib/pay.rb +8 -57
- metadata +34 -36
- data/db/migrate/20170205020145_create_pay_subscriptions.rb +0 -17
- data/db/migrate/20170727235816_create_pay_charges.rb +0 -18
- data/db/migrate/20190816015720_add_status_to_pay_subscriptions.rb +0 -14
- data/db/migrate/20200603134434_add_data_to_pay_models.rb +0 -22
- data/db/migrate/20210423235138_add_currency_to_pay_charges.rb +0 -5
- data/lib/generators/active_record/pay_generator.rb +0 -58
- data/lib/generators/active_record/templates/migration.rb +0 -9
- data/lib/pay/billable/sync_email.rb +0 -40
- data/lib/pay/billable.rb +0 -168
@@ -3,14 +3,14 @@ module Pay
|
|
3
3
|
module Webhooks
|
4
4
|
class SubscriptionUpdated
|
5
5
|
def call(event)
|
6
|
-
subscription = Pay.
|
6
|
+
subscription = Pay::Subscription.find_by_processor_and_id(:paddle, event["subscription_id"])
|
7
7
|
|
8
8
|
return if subscription.nil?
|
9
9
|
|
10
10
|
case event["status"]
|
11
11
|
when "deleted"
|
12
12
|
subscription.status = "canceled"
|
13
|
-
subscription.ends_at = Time.zone.parse(event["next_bill_date"]) || Time.
|
13
|
+
subscription.ends_at = Time.zone.parse(event["next_bill_date"]) || Time.current if subscription.ends_at.blank?
|
14
14
|
when "trialing"
|
15
15
|
subscription.status = "trialing"
|
16
16
|
subscription.trial_ends_at = Time.zone.parse(event["next_bill_date"])
|
data/lib/pay/paddle.rb
CHANGED
@@ -2,8 +2,9 @@ module Pay
|
|
2
2
|
module Paddle
|
3
3
|
autoload :Billable, "pay/paddle/billable"
|
4
4
|
autoload :Charge, "pay/paddle/charge"
|
5
|
-
autoload :Subscription, "pay/paddle/subscription"
|
6
5
|
autoload :Error, "pay/paddle/error"
|
6
|
+
autoload :PaymentMethod, "pay/paddle/payment_method"
|
7
|
+
autoload :Subscription, "pay/paddle/subscription"
|
7
8
|
|
8
9
|
module Webhooks
|
9
10
|
autoload :SignatureVerifier, "pay/paddle/webhooks/signature_verifier"
|
@@ -44,9 +45,12 @@ module Pay
|
|
44
45
|
options.merge(owner_sgid: owner.to_sgid.to_s).to_json
|
45
46
|
end
|
46
47
|
|
48
|
+
def self.parse_passthrough(passthrough)
|
49
|
+
JSON.parse(passthrough)
|
50
|
+
end
|
51
|
+
|
47
52
|
def self.owner_from_passthrough(passthrough)
|
48
|
-
|
49
|
-
GlobalID::Locator.locate_signed(passthrough_json["owner_sgid"])
|
53
|
+
GlobalID::Locator.locate_signed parse_passthrough(passthrough)["owner_sgid"]
|
50
54
|
rescue JSON::ParserError
|
51
55
|
nil
|
52
56
|
end
|
data/lib/pay/payment.rb
CHANGED
@@ -2,7 +2,7 @@ module Pay
|
|
2
2
|
class Payment
|
3
3
|
attr_reader :intent
|
4
4
|
|
5
|
-
delegate :id, :amount, :client_secret, :status, :confirm, to: :intent
|
5
|
+
delegate :id, :amount, :client_secret, :customer, :status, :confirm, to: :intent
|
6
6
|
|
7
7
|
def self.from_id(id)
|
8
8
|
intent = id.start_with?("seti_") ? ::Stripe::SetupIntent.retrieve(id) : ::Stripe::PaymentIntent.retrieve(id)
|
data/lib/pay/receipts.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module Pay
|
2
2
|
module Receipts
|
3
|
-
def filename
|
4
|
-
"receipt-#{created_at.strftime("%Y-%m-%d")}.pdf"
|
5
|
-
end
|
6
|
-
|
7
3
|
def product
|
8
4
|
Pay.application_name
|
9
5
|
end
|
10
6
|
|
11
|
-
|
7
|
+
def receipt_filename
|
8
|
+
"receipt-#{created_at.strftime("%Y-%m-%d")}.pdf"
|
9
|
+
end
|
10
|
+
alias_method :filename, :receipt_filename
|
11
|
+
|
12
12
|
def receipt
|
13
13
|
receipt_pdf.render
|
14
14
|
end
|
@@ -26,15 +26,43 @@ module Pay
|
|
26
26
|
)
|
27
27
|
end
|
28
28
|
|
29
|
+
def invoice_filename
|
30
|
+
"invoice-#{created_at.strftime("%Y-%m-%d")}.pdf"
|
31
|
+
end
|
32
|
+
|
33
|
+
def invoice
|
34
|
+
invoice_pdf.render
|
35
|
+
end
|
36
|
+
|
37
|
+
def invoice_pdf
|
38
|
+
::Receipts::Invoice.new(
|
39
|
+
id: id,
|
40
|
+
issue_date: created_at,
|
41
|
+
due_date: created_at,
|
42
|
+
status: "<b><color rgb='#5eba7d'>PAID</color></b>",
|
43
|
+
bill_to: [
|
44
|
+
customer.customer_name,
|
45
|
+
customer.email
|
46
|
+
].compact,
|
47
|
+
product: product,
|
48
|
+
company: {
|
49
|
+
name: Pay.business_name,
|
50
|
+
address: Pay.business_address,
|
51
|
+
email: Pay.support_email
|
52
|
+
},
|
53
|
+
line_items: line_items
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
29
57
|
def line_items
|
30
58
|
line_items = [
|
31
59
|
[I18n.t("receipt.date"), created_at.to_s],
|
32
|
-
[I18n.t("receipt.account_billed"), "#{
|
60
|
+
[I18n.t("receipt.account_billed"), "#{customer.customer_name} (#{customer.email})"],
|
33
61
|
[I18n.t("receipt.product"), product],
|
34
62
|
[I18n.t("receipt.amount"), ActionController::Base.helpers.number_to_currency(amount / 100.0)],
|
35
63
|
[I18n.t("receipt.charged_to"), charged_to]
|
36
64
|
]
|
37
|
-
line_items << [I18n.t("receipt.additional_info"), owner.extra_billing_info] if owner.extra_billing_info?
|
65
|
+
line_items << [I18n.t("receipt.additional_info"), customer.owner.extra_billing_info] if customer.owner.extra_billing_info?
|
38
66
|
line_items
|
39
67
|
end
|
40
68
|
end
|
data/lib/pay/stripe/billable.rb
CHANGED
@@ -3,42 +3,40 @@ module Pay
|
|
3
3
|
class Billable
|
4
4
|
include Rails.application.routes.url_helpers
|
5
5
|
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :pay_customer
|
7
7
|
|
8
8
|
delegate :processor_id,
|
9
9
|
:processor_id?,
|
10
10
|
:email,
|
11
11
|
:customer_name,
|
12
|
-
:
|
13
|
-
|
12
|
+
:payment_method_token,
|
13
|
+
:payment_method_token?,
|
14
|
+
:stripe_account,
|
15
|
+
to: :pay_customer
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
Rails.application.config.action_mailer.default_url_options || {}
|
18
|
-
end
|
17
|
+
def self.default_url_options
|
18
|
+
Rails.application.config.action_mailer.default_url_options || {}
|
19
19
|
end
|
20
20
|
|
21
|
-
def initialize(
|
22
|
-
@
|
21
|
+
def initialize(pay_customer)
|
22
|
+
@pay_customer = pay_customer
|
23
23
|
end
|
24
24
|
|
25
|
-
# Handles Billable#customer
|
26
|
-
#
|
27
|
-
# Returns Stripe::Customer
|
28
25
|
def customer
|
29
26
|
stripe_customer = if processor_id?
|
30
|
-
::Stripe::Customer.retrieve(processor_id)
|
27
|
+
::Stripe::Customer.retrieve({id: processor_id}, stripe_options)
|
31
28
|
else
|
32
|
-
sc = ::Stripe::Customer.create(email: email, name: customer_name)
|
33
|
-
|
29
|
+
sc = ::Stripe::Customer.create({email: email, name: customer_name}, stripe_options)
|
30
|
+
pay_customer.update!(processor_id: sc.id, stripe_account: stripe_account)
|
34
31
|
sc
|
35
32
|
end
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
34
|
+
if payment_method_token?
|
35
|
+
payment_method = ::Stripe::PaymentMethod.attach(payment_method_token, {customer: stripe_customer.id}, stripe_options)
|
36
|
+
pay_payment_method = save_payment_method(payment_method, default: false)
|
37
|
+
pay_payment_method.make_default!
|
38
|
+
|
39
|
+
pay_customer.payment_method_token = nil
|
42
40
|
end
|
43
41
|
|
44
42
|
stripe_customer
|
@@ -46,36 +44,32 @@ module Pay
|
|
46
44
|
raise Pay::Stripe::Error, e
|
47
45
|
end
|
48
46
|
|
49
|
-
# Handles Billable#charge
|
50
|
-
#
|
51
|
-
# Returns Pay::Charge
|
52
47
|
def charge(amount, options = {})
|
53
|
-
|
48
|
+
add_payment_method(payment_method_token, default: true) if payment_method_token?
|
49
|
+
|
50
|
+
payment_method = pay_customer.default_payment_method
|
54
51
|
args = {
|
55
52
|
amount: amount,
|
56
53
|
confirm: true,
|
57
54
|
confirmation_method: :automatic,
|
58
55
|
currency: "usd",
|
59
|
-
customer:
|
60
|
-
payment_method:
|
56
|
+
customer: processor_id,
|
57
|
+
payment_method: payment_method&.processor_id
|
61
58
|
}.merge(options)
|
62
59
|
|
63
|
-
payment_intent = ::Stripe::PaymentIntent.create(args)
|
60
|
+
payment_intent = ::Stripe::PaymentIntent.create(args, stripe_options)
|
64
61
|
Pay::Payment.new(payment_intent).validate
|
65
62
|
|
66
|
-
|
67
|
-
|
63
|
+
charge = payment_intent.charges.first
|
64
|
+
Pay::Stripe::Charge.sync(charge.id, object: charge)
|
68
65
|
rescue ::Stripe::StripeError => e
|
69
66
|
raise Pay::Stripe::Error, e
|
70
67
|
end
|
71
68
|
|
72
|
-
# Handles Billable#subscribe
|
73
|
-
#
|
74
|
-
# Returns Pay::Subscription
|
75
69
|
def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
|
76
70
|
quantity = options.delete(:quantity) || 1
|
77
71
|
opts = {
|
78
|
-
expand: ["pending_setup_intent", "latest_invoice.payment_intent"],
|
72
|
+
expand: ["pending_setup_intent", "latest_invoice.payment_intent", "latest_invoice.charge.invoice"],
|
79
73
|
items: [plan: plan, quantity: quantity],
|
80
74
|
off_session: true
|
81
75
|
}.merge(options)
|
@@ -83,19 +77,18 @@ module Pay
|
|
83
77
|
# Inherit trial from plan unless trial override was specified
|
84
78
|
opts[:trial_from_plan] = true unless opts[:trial_period_days]
|
85
79
|
|
86
|
-
# Load the Stripe customer to verify it exists and update
|
80
|
+
# Load the Stripe customer to verify it exists and update payment method if needed
|
87
81
|
opts[:customer] = customer.id
|
88
82
|
|
89
|
-
|
90
|
-
|
83
|
+
# Create subscription on Stripe
|
84
|
+
stripe_sub = ::Stripe::Subscription.create(opts, stripe_options)
|
91
85
|
|
92
|
-
#
|
86
|
+
# Save Pay::Subscription
|
87
|
+
subscription = Pay::Stripe::Subscription.sync(stripe_sub.id, object: stripe_sub, name: name)
|
88
|
+
|
89
|
+
# No trial, payment method requires SCA
|
93
90
|
if subscription.incomplete?
|
94
91
|
Pay::Payment.new(stripe_sub.latest_invoice.payment_intent).validate
|
95
|
-
|
96
|
-
# Trial, card requires SCA
|
97
|
-
elsif subscription.on_trial? && stripe_sub.pending_setup_intent
|
98
|
-
Pay::Payment.new(stripe_sub.pending_setup_intent).validate
|
99
92
|
end
|
100
93
|
|
101
94
|
subscription
|
@@ -103,51 +96,57 @@ module Pay
|
|
103
96
|
raise Pay::Stripe::Error, e
|
104
97
|
end
|
105
98
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
def update_card(payment_method_id)
|
110
|
-
stripe_customer = customer
|
111
|
-
|
112
|
-
return true if payment_method_id == stripe_customer.invoice_settings.default_payment_method
|
99
|
+
def add_payment_method(payment_method_id, default: false)
|
100
|
+
customer unless processor_id?
|
101
|
+
payment_method = ::Stripe::PaymentMethod.attach(payment_method_id, {customer: processor_id}, stripe_options)
|
113
102
|
|
114
|
-
|
115
|
-
|
103
|
+
if default
|
104
|
+
::Stripe::Customer.update(processor_id, {
|
105
|
+
invoice_settings: {
|
106
|
+
default_payment_method: payment_method.id
|
107
|
+
}
|
108
|
+
}, stripe_options)
|
109
|
+
end
|
116
110
|
|
117
|
-
|
118
|
-
true
|
111
|
+
save_payment_method(payment_method, default: default)
|
119
112
|
rescue ::Stripe::StripeError => e
|
120
113
|
raise Pay::Stripe::Error, e
|
121
114
|
end
|
122
115
|
|
116
|
+
# Save the Stripe::PaymentMethod to the database
|
117
|
+
def save_payment_method(payment_method, default:)
|
118
|
+
pay_payment_method = pay_customer.payment_methods.where(processor_id: payment_method.id).first_or_initialize
|
119
|
+
|
120
|
+
attributes = Pay::Stripe::PaymentMethod.extract_attributes(payment_method).merge(default: default)
|
121
|
+
|
122
|
+
pay_customer.payment_methods.update_all(default: false) if default
|
123
|
+
pay_payment_method.update!(attributes)
|
124
|
+
|
125
|
+
# Reload the Rails association
|
126
|
+
pay_customer.reload_default_payment_method if default
|
127
|
+
|
128
|
+
pay_payment_method
|
129
|
+
end
|
130
|
+
|
123
131
|
def update_email!
|
124
|
-
::Stripe::Customer.update(processor_id, {email: email, name: customer_name})
|
132
|
+
::Stripe::Customer.update(processor_id, {email: email, name: customer_name}, stripe_options)
|
125
133
|
end
|
126
134
|
|
127
135
|
def processor_subscription(subscription_id, options = {})
|
128
|
-
::Stripe::Subscription.retrieve(options.merge(id: subscription_id))
|
136
|
+
::Stripe::Subscription.retrieve(options.merge(id: subscription_id), stripe_options)
|
129
137
|
end
|
130
138
|
|
131
139
|
def invoice!(options = {})
|
132
140
|
return unless processor_id?
|
133
|
-
::Stripe::Invoice.create(options.merge(customer: processor_id)).pay
|
141
|
+
::Stripe::Invoice.create(options.merge(customer: processor_id), stripe_options).pay
|
134
142
|
end
|
135
143
|
|
136
144
|
def upcoming_invoice
|
137
|
-
::Stripe::Invoice.upcoming(customer: processor_id)
|
138
|
-
end
|
139
|
-
|
140
|
-
# Used by webhooks when the customer or source changes
|
141
|
-
def sync_card_from_stripe
|
142
|
-
if (payment_method_id = customer.invoice_settings.default_payment_method)
|
143
|
-
update_card_on_file ::Stripe::PaymentMethod.retrieve(payment_method_id).card
|
144
|
-
else
|
145
|
-
billable.update(card_type: nil, card_last4: nil)
|
146
|
-
end
|
145
|
+
::Stripe::Invoice.upcoming({customer: processor_id}, stripe_options)
|
147
146
|
end
|
148
147
|
|
149
148
|
def create_setup_intent
|
150
|
-
::Stripe::SetupIntent.create(customer: processor_id, usage: :off_session)
|
149
|
+
::Stripe::SetupIntent.create({customer: processor_id, usage: :off_session}, stripe_options)
|
151
150
|
end
|
152
151
|
|
153
152
|
def trial_end_date(stripe_sub)
|
@@ -155,31 +154,14 @@ module Pay
|
|
155
154
|
stripe_sub.trial_end.present? ? Time.at(stripe_sub.trial_end) : nil
|
156
155
|
end
|
157
156
|
|
158
|
-
#
|
159
|
-
def
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
billable.card_token = nil
|
168
|
-
end
|
169
|
-
|
170
|
-
def save_pay_charge(object)
|
171
|
-
charge = billable.charges.find_or_initialize_by(processor: :stripe, processor_id: object.id)
|
172
|
-
|
173
|
-
charge.update(
|
174
|
-
amount: object.amount,
|
175
|
-
card_last4: object.payment_method_details.card.last4,
|
176
|
-
card_type: object.payment_method_details.card.brand,
|
177
|
-
card_exp_month: object.payment_method_details.card.exp_month,
|
178
|
-
card_exp_year: object.payment_method_details.card.exp_year,
|
179
|
-
created_at: Time.zone.at(object.created)
|
180
|
-
)
|
181
|
-
|
182
|
-
charge
|
157
|
+
# Syncs a customer's subscriptions from Stripe to the database
|
158
|
+
def sync_subscriptions
|
159
|
+
subscriptions = ::Stripe::Subscription.list({customer: customer}, stripe_options)
|
160
|
+
subscriptions.map do |subscription|
|
161
|
+
Pay::Stripe::Subscription.sync(subscription.id)
|
162
|
+
end
|
163
|
+
rescue ::Stripe::StripeError => e
|
164
|
+
raise Pay::Stripe::Error, e
|
183
165
|
end
|
184
166
|
|
185
167
|
# https://stripe.com/docs/api/checkout/sessions/create
|
@@ -213,7 +195,7 @@ module Pay
|
|
213
195
|
}
|
214
196
|
end
|
215
197
|
|
216
|
-
::Stripe::Checkout::Session.create(args.merge(options))
|
198
|
+
::Stripe::Checkout::Session.create(args.merge(options), stripe_options)
|
217
199
|
end
|
218
200
|
|
219
201
|
# https://stripe.com/docs/api/checkout/sessions/create
|
@@ -240,7 +222,14 @@ module Pay
|
|
240
222
|
customer: processor_id,
|
241
223
|
return_url: options.delete(:return_url) || root_url
|
242
224
|
}
|
243
|
-
::Stripe::BillingPortal::Session.create(args.merge(options))
|
225
|
+
::Stripe::BillingPortal::Session.create(args.merge(options), stripe_options)
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
|
230
|
+
# Options for Stripe requests
|
231
|
+
def stripe_options
|
232
|
+
{stripe_account: stripe_account}.compact
|
244
233
|
end
|
245
234
|
end
|
246
235
|
end
|
data/lib/pay/stripe/charge.rb
CHANGED
@@ -3,24 +3,85 @@ module Pay
|
|
3
3
|
class Charge
|
4
4
|
attr_reader :pay_charge
|
5
5
|
|
6
|
-
delegate :processor_id, :
|
6
|
+
delegate :processor_id, :stripe_account, to: :pay_charge
|
7
|
+
|
8
|
+
def self.sync(charge_id, object: nil, stripe_account: nil, try: 0, retries: 1)
|
9
|
+
# Skip loading the latest charge details from the API if we already have it
|
10
|
+
object ||= ::Stripe::Charge.retrieve(charge_id, {stripe_account: stripe_account}.compact)
|
11
|
+
|
12
|
+
pay_customer = Pay::Customer.find_by(processor: :stripe, processor_id: object.customer)
|
13
|
+
return unless pay_customer
|
14
|
+
|
15
|
+
payment_method = object.payment_method_details.send(object.payment_method_details.type)
|
16
|
+
attrs = {
|
17
|
+
amount: object.amount,
|
18
|
+
amount_refunded: object.amount_refunded,
|
19
|
+
application_fee_amount: object.application_fee_amount,
|
20
|
+
created_at: Time.at(object.created),
|
21
|
+
currency: object.currency,
|
22
|
+
stripe_account: pay_customer.stripe_account,
|
23
|
+
metadata: object.metadata,
|
24
|
+
payment_method_type: object.payment_method_details.type,
|
25
|
+
brand: payment_method.try(:brand)&.capitalize,
|
26
|
+
last4: payment_method.try(:last4).to_s,
|
27
|
+
exp_month: payment_method.try(:exp_month).to_s,
|
28
|
+
exp_year: payment_method.try(:exp_year).to_s,
|
29
|
+
bank: payment_method.try(:bank_name) || payment_method.try(:bank) # eps, fpx, ideal, p24, acss_debit, etc
|
30
|
+
}
|
31
|
+
|
32
|
+
# Associate charge with subscription if we can
|
33
|
+
if object.invoice
|
34
|
+
invoice = (object.invoice.is_a?(::Stripe::Invoice) ? object.invoice : ::Stripe::Invoice.retrieve(object.invoice, {stripe_account: stripe_account}.compact))
|
35
|
+
attrs[:subscription] = pay_customer.subscriptions.find_by(processor_id: invoice.subscription)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Update or create the charge
|
39
|
+
if (pay_charge = pay_customer.charges.find_by(processor_id: object.id))
|
40
|
+
pay_charge.with_lock do
|
41
|
+
pay_charge.update!(attrs)
|
42
|
+
end
|
43
|
+
pay_charge
|
44
|
+
else
|
45
|
+
pay_customer.charges.create!(attrs.merge(processor_id: object.id))
|
46
|
+
end
|
47
|
+
rescue ActiveRecord::RecordInvalid
|
48
|
+
try += 1
|
49
|
+
if try <= retries
|
50
|
+
sleep 0.1
|
51
|
+
retry
|
52
|
+
else
|
53
|
+
raise
|
54
|
+
end
|
55
|
+
end
|
7
56
|
|
8
57
|
def initialize(pay_charge)
|
9
58
|
@pay_charge = pay_charge
|
10
59
|
end
|
11
60
|
|
12
61
|
def charge
|
13
|
-
::Stripe::Charge.retrieve(id: processor_id, expand: ["customer", "invoice.subscription"])
|
62
|
+
::Stripe::Charge.retrieve({id: processor_id, expand: ["customer", "invoice.subscription"]}, stripe_options)
|
14
63
|
rescue ::Stripe::StripeError => e
|
15
64
|
raise Pay::Stripe::Error, e
|
16
65
|
end
|
17
66
|
|
18
|
-
|
19
|
-
|
67
|
+
# https://stripe.com/docs/api/refunds/create
|
68
|
+
#
|
69
|
+
# refund!
|
70
|
+
# refund!(5_00)
|
71
|
+
# refund!(5_00, refund_application_fee: true)
|
72
|
+
def refund!(amount_to_refund, **options)
|
73
|
+
::Stripe::Refund.create(options.merge(charge: processor_id, amount: amount_to_refund), stripe_options)
|
20
74
|
pay_charge.update(amount_refunded: amount_to_refund)
|
21
75
|
rescue ::Stripe::StripeError => e
|
22
76
|
raise Pay::Stripe::Error, e
|
23
77
|
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Options for Stripe requests
|
82
|
+
def stripe_options
|
83
|
+
{stripe_account: stripe_account}.compact
|
84
|
+
end
|
24
85
|
end
|
25
86
|
end
|
26
87
|
end
|