spree_stripe 1.2.4 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/stripe_event/webhook_controller_decorator.rb +4 -0
- data/app/javascript/spree_stripe/controllers/stripe_button_controller.js +15 -6
- data/app/javascript/spree_stripe/controllers/stripe_controller.js +6 -7
- data/app/jobs/spree_stripe/update_customer_job.rb +10 -0
- data/app/models/spree_stripe/address_decorator.rb +19 -0
- data/app/models/spree_stripe/gateway.rb +33 -13
- data/app/models/spree_stripe/gateway_customer_decorator.rb +9 -0
- data/app/models/spree_stripe/order_decorator.rb +11 -0
- data/app/models/spree_stripe/user_decorator.rb +21 -0
- data/app/presenters/spree_stripe/customer_presenter.rb +1 -1
- data/app/services/spree_stripe/create_gateway_webhooks.rb +6 -6
- data/app/services/spree_stripe/update_customer.rb +13 -0
- data/app/views/spree_stripe/_quick_checkout.html.erb +1 -1
- data/lib/spree_stripe/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aba1375f50b74ab3e4fa3887f9b40c314f56f3e96898e21a02ab43efddc2dd07
|
4
|
+
data.tar.gz: a812910d9968f97b3f4ba54fa4026e5ca824e13b8ed4e86bc4a11377904e0285
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 265ada6aa1bbbc80df01e8bdf347e1d9f24e6cec65e71c1480946dcfa0c9682df1d691c0fb80959807c5164027a0fec6e58dfa700d8dc5eeb5e1511327e67693
|
7
|
+
data.tar.gz: ef1a978a396ad0b67758811b48cd475c6ffbfdedb6b5292e138c89439711030c164dccd48f0c377094e5cac92c9376ee40888afc00932e74de4bf4b849cfe4b9
|
@@ -1,5 +1,9 @@
|
|
1
1
|
module StripeEvent
|
2
2
|
module WebhookControllerDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.include Spree::Core::ControllerHelpers::Store
|
5
|
+
end
|
6
|
+
|
3
7
|
def secrets(payload, signature)
|
4
8
|
all_signing_keys = SpreeStripe::WebhookKey.pluck(:signing_secret).uniq.compact
|
5
9
|
all_signing_keys << ENV['STRIPE_SIGNING_SECRET'] if ENV['STRIPE_SIGNING_SECRET'].present?
|
@@ -160,14 +160,19 @@ export default class extends Controller {
|
|
160
160
|
// In case of any error here we have to allow user try again
|
161
161
|
try {
|
162
162
|
const response = await fetch(
|
163
|
-
|
163
|
+
this.checkoutAdvancePathValue,
|
164
164
|
{
|
165
165
|
method: 'PATCH',
|
166
166
|
headers: {
|
167
167
|
'X-Spree-Order-Token': this.orderTokenValue,
|
168
168
|
'Content-Type': 'application/json'
|
169
169
|
},
|
170
|
-
body: JSON.stringify({
|
170
|
+
body: JSON.stringify({
|
171
|
+
state: 'delivery',
|
172
|
+
include: 'shipments.shipping_rates',
|
173
|
+
quick_checkout: true,
|
174
|
+
shipping_method_id: this.currentShippingOptionId
|
175
|
+
})
|
171
176
|
}
|
172
177
|
)
|
173
178
|
const newOrderResponse = await response.json()
|
@@ -259,13 +264,14 @@ export default class extends Controller {
|
|
259
264
|
}
|
260
265
|
|
261
266
|
const validationResponse = await fetch(
|
262
|
-
|
267
|
+
this.checkoutValidateOrderForPaymentPathValue,
|
263
268
|
{
|
264
269
|
method: 'POST',
|
265
270
|
headers: {
|
266
271
|
'X-Spree-Order-Token': this.orderTokenValue,
|
267
272
|
'Content-Type': 'application/json'
|
268
|
-
}
|
273
|
+
},
|
274
|
+
body: JSON.stringify({ skip_state: true })
|
269
275
|
}
|
270
276
|
)
|
271
277
|
|
@@ -307,13 +313,16 @@ export default class extends Controller {
|
|
307
313
|
return
|
308
314
|
}
|
309
315
|
|
310
|
-
const advanceResponse = await fetch(
|
316
|
+
const advanceResponse = await fetch(this.checkoutAdvancePathValue, {
|
311
317
|
method: 'PATCH',
|
312
318
|
headers: {
|
313
319
|
'X-Spree-Order-Token': this.orderTokenValue,
|
314
320
|
'Content-Type': 'application/json'
|
315
321
|
},
|
316
|
-
body: JSON.stringify({
|
322
|
+
body: JSON.stringify({
|
323
|
+
state: 'payment',
|
324
|
+
shipping_method_id: shippingRateId
|
325
|
+
})
|
317
326
|
})
|
318
327
|
|
319
328
|
if (advanceResponse.status !== 200) {
|
@@ -206,10 +206,11 @@ export default class extends Controller {
|
|
206
206
|
async updateBillingAddress() {
|
207
207
|
// billing address same as shipping address
|
208
208
|
if (this.billingAddressCheckbox?.checked) {
|
209
|
-
const response = await fetch(
|
209
|
+
const response = await fetch(this.checkoutPathValue, {
|
210
210
|
method: 'PATCH',
|
211
211
|
headers: this.spreeApiHeaders,
|
212
212
|
body: JSON.stringify({
|
213
|
+
include: 'billing_address',
|
213
214
|
order: {
|
214
215
|
use_shipping: true
|
215
216
|
}
|
@@ -221,6 +222,8 @@ export default class extends Controller {
|
|
221
222
|
if (response.ok) {
|
222
223
|
return responseJson.included.find(item => item.type === 'address').attributes;
|
223
224
|
} else {
|
225
|
+
const errors = Array.isArray(responseJson.error) ? responseJson.error.join('. ') : responseJson.error || 'Billing address is invalid';
|
226
|
+
showFlashMessage(errors, 'error');
|
224
227
|
this.submitTarget.disabled = false;
|
225
228
|
return false;
|
226
229
|
}
|
@@ -230,10 +233,11 @@ export default class extends Controller {
|
|
230
233
|
if (this.billingAddressForm.checkValidity()) {
|
231
234
|
const formData = new FormData(this.billingAddressForm);
|
232
235
|
|
233
|
-
const response = await fetch(
|
236
|
+
const response = await fetch(this.checkoutPathValue, {
|
234
237
|
method: 'PATCH',
|
235
238
|
headers: this.spreeApiHeaders,
|
236
239
|
body: JSON.stringify({
|
240
|
+
include: 'billing_address',
|
237
241
|
order: {
|
238
242
|
bill_address_attributes: {
|
239
243
|
firstname: formData.get("order[bill_address_attributes][firstname]"),
|
@@ -259,11 +263,6 @@ export default class extends Controller {
|
|
259
263
|
const errors = Array.isArray(responseJson.error) ? responseJson.error.join('. ') : responseJson.error || 'Billing address is invalid';
|
260
264
|
showFlashMessage(errors, 'error');
|
261
265
|
|
262
|
-
const flashMessage = document.getElementsByClassName('flash-message')[0];
|
263
|
-
if (flashMessage) {
|
264
|
-
flashMessage.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'nearest' });
|
265
|
-
}
|
266
|
-
|
267
266
|
this.submitTarget.disabled = false;
|
268
267
|
return false;
|
269
268
|
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
module AddressDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.after_update :update_stripe_customer, if: :should_update_stripe_customer?
|
5
|
+
end
|
6
|
+
|
7
|
+
delegate :update_stripe_customer, to: :user, allow_nil: true
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def should_update_stripe_customer?
|
12
|
+
user_default_billing? && previous_changes.any?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if ActiveRecord::Base.connection.database_exists? && ActiveRecord::Base.connection.table_exists?('spree_addresses')
|
18
|
+
Spree::Address.prepend(SpreeStripe::AddressDecorator)
|
19
|
+
end
|
@@ -15,8 +15,8 @@ module SpreeStripe
|
|
15
15
|
|
16
16
|
has_many :payment_intents, class_name: 'SpreeStripe::PaymentIntent', foreign_key: 'payment_method_id', dependent: :delete_all
|
17
17
|
|
18
|
-
def
|
19
|
-
|
18
|
+
def webhook_url
|
19
|
+
StripeEvent::Engine.routes.url_helpers.root_url(host: stores.first.url, protocol: 'https')
|
20
20
|
end
|
21
21
|
|
22
22
|
def provider_class
|
@@ -128,18 +128,13 @@ module SpreeStripe
|
|
128
128
|
gateway_customers.find_by(user: user) || create_customer(order: order, user: user)
|
129
129
|
end
|
130
130
|
|
131
|
+
# Creates a Stripe customer based on the order or user
|
132
|
+
#
|
133
|
+
# @param order [Spree::Order] the order to use for creating the Stripe customer
|
134
|
+
# @param user [Spree::User] the user to use for creating the Stripe customer
|
135
|
+
# @return [Stripe::Customer] the created Stripe customer
|
131
136
|
def create_customer(order: nil, user: nil)
|
132
|
-
|
133
|
-
address = order&.bill_address || user&.bill_address
|
134
|
-
name = order&.name || user&.name
|
135
|
-
email = order&.email || user&.email
|
136
|
-
|
137
|
-
payload = SpreeStripe::CustomerPresenter.new(
|
138
|
-
name: name,
|
139
|
-
email: email,
|
140
|
-
address: address
|
141
|
-
).call
|
142
|
-
|
137
|
+
payload = build_customer_payload(order: order, user: user)
|
143
138
|
response = send_request { Stripe::Customer.create(payload) }
|
144
139
|
|
145
140
|
customer = gateway_customers.build(user: user, profile_id: response.id)
|
@@ -147,6 +142,22 @@ module SpreeStripe
|
|
147
142
|
customer
|
148
143
|
end
|
149
144
|
|
145
|
+
# Updates a Stripe customer based on the order or user
|
146
|
+
#
|
147
|
+
# @param order [Spree::Order] the order to use for updating the Stripe customer
|
148
|
+
# @param user [Spree::User] the user to use for updating the Stripe customer
|
149
|
+
# @return [Stripe::Customer] the updated Stripe customer
|
150
|
+
def update_customer(order: nil, user: nil)
|
151
|
+
user ||= order&.user
|
152
|
+
return if user.blank?
|
153
|
+
|
154
|
+
customer = gateway_customers.find_by(user: user)
|
155
|
+
return if customer.blank?
|
156
|
+
|
157
|
+
payload = build_customer_payload(order: order, user: user)
|
158
|
+
send_request { Stripe::Customer.update(customer.profile_id, payload) }
|
159
|
+
end
|
160
|
+
|
150
161
|
# Creates a Stripe payment intent for the order
|
151
162
|
#
|
152
163
|
# @param amount_in_cents [Integer] the amount in cents
|
@@ -362,5 +373,14 @@ module SpreeStripe
|
|
362
373
|
end
|
363
374
|
end
|
364
375
|
end
|
376
|
+
|
377
|
+
def build_customer_payload(order: nil, user: nil)
|
378
|
+
user ||= order&.user
|
379
|
+
address = order&.bill_address || user&.bill_address
|
380
|
+
name = order&.name || user&.name
|
381
|
+
email = order&.email || user&.email
|
382
|
+
|
383
|
+
SpreeStripe::CustomerPresenter.new(name: name, email: email, address: address).call
|
384
|
+
end
|
365
385
|
end
|
366
386
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
module GatewayCustomerDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.scope :stripe, -> { joins(:payment_method).where("#{Spree::PaymentMethod.table_name}.type" => SpreeStripe::Gateway.to_s) }
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Spree::GatewayCustomer.prepend(SpreeStripe::GatewayCustomerDecorator)
|
@@ -12,6 +12,17 @@ module SpreeStripe
|
|
12
12
|
payment_intent.update!(amount: total_minus_store_credits)
|
13
13
|
end
|
14
14
|
end
|
15
|
+
|
16
|
+
def associate_user!(user, override_email = true)
|
17
|
+
super(user, override_email)
|
18
|
+
|
19
|
+
return if payment_intents.empty?
|
20
|
+
|
21
|
+
responses = payment_intents.map { |payment_intent| payment_intent.update_stripe_payment_intent }
|
22
|
+
customer_id = responses.find { |response| response.params['customer'].present? }&.params['customer']
|
23
|
+
|
24
|
+
payment_intents.update_all(customer_id: customer_id) if customer_id.present?
|
25
|
+
end
|
15
26
|
end
|
16
27
|
end
|
17
28
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
module UserDecorator
|
3
|
+
def self.prepended(base)
|
4
|
+
base.after_update :update_stripe_customer, if: :should_update_stripe_customer?
|
5
|
+
end
|
6
|
+
|
7
|
+
def update_stripe_customer
|
8
|
+
SpreeStripe::UpdateCustomerJob.perform_later(id)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def should_update_stripe_customer?
|
14
|
+
ship_address_previously_changed? || bill_address_previously_changed? ||
|
15
|
+
first_name_previously_changed? || last_name_previously_changed? ||
|
16
|
+
email_previously_changed?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Spree.user_class.prepend(SpreeStripe::UserDecorator) if Spree.user_class.present?
|
@@ -2,15 +2,15 @@ module SpreeStripe
|
|
2
2
|
class CreateGatewayWebhooks
|
3
3
|
def call(payment_method:, events: SpreeStripe::Config[:supported_webhook_events], connect: false)
|
4
4
|
webhook_list = Stripe::WebhookEndpoint.list({}, { api_key: payment_method.preferred_secret_key })
|
5
|
-
webhook = find_webhook(webhook_list[:data], events)
|
5
|
+
webhook = find_webhook(payment_method, webhook_list[:data], events)
|
6
6
|
|
7
7
|
ensure_webhook(payment_method, webhook, connect, events)
|
8
8
|
end
|
9
9
|
|
10
10
|
private
|
11
11
|
|
12
|
-
def find_webhook(webhooks_data, enabled_events)
|
13
|
-
webhook_url =
|
12
|
+
def find_webhook(payment_method, webhooks_data, enabled_events)
|
13
|
+
webhook_url = payment_method.webhook_url
|
14
14
|
|
15
15
|
webhooks_data.find do |webhook|
|
16
16
|
webhook[:url] == webhook_url && webhook[:enabled_events].sort == enabled_events.sort
|
@@ -32,7 +32,7 @@ module SpreeStripe
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def create_webhook_endpoint(payment_method, connect, events)
|
35
|
-
params = build_webhook_params(connect, events)
|
35
|
+
params = build_webhook_params(payment_method, connect, events)
|
36
36
|
stripe_webhook = Stripe::WebhookEndpoint.create(params, { api_key: payment_method.preferred_secret_key })
|
37
37
|
|
38
38
|
SpreeStripe::WebhookKey.create!(
|
@@ -44,9 +44,9 @@ module SpreeStripe
|
|
44
44
|
Rails.cache.delete('stripe_webhook_signing_keys')
|
45
45
|
end
|
46
46
|
|
47
|
-
def build_webhook_params(connect, events)
|
47
|
+
def build_webhook_params(payment_method, connect, events)
|
48
48
|
{
|
49
|
-
url:
|
49
|
+
url: payment_method.webhook_url,
|
50
50
|
enabled_events: events,
|
51
51
|
connect: connect
|
52
52
|
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SpreeStripe
|
2
|
+
class UpdateCustomer
|
3
|
+
def call(user:)
|
4
|
+
gateway_customers = user.gateway_customers.stripe
|
5
|
+
return if gateway_customers.empty?
|
6
|
+
|
7
|
+
gateway_customers.each do |gateway_customer|
|
8
|
+
stripe_gateway = gateway_customer.payment_method
|
9
|
+
stripe_gateway.update_customer(user: user)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -27,7 +27,7 @@
|
|
27
27
|
} do %>
|
28
28
|
<div id="payment-request-button"></div>
|
29
29
|
|
30
|
-
<div class="relative group-[.no-separator]:hidden flex
|
30
|
+
<div class="relative group-[.no-separator]:hidden flex pt-5 items-center ">
|
31
31
|
<div class="flex-grow border-t border-default"></div>
|
32
32
|
<span class="flex-shrink mx-4 text-gray-500 text-sm">
|
33
33
|
<%= Spree.t('storefront.checkout.or_continue_below') %>
|
data/lib/spree_stripe/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spree_stripe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vendo Connect Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
11
|
+
date: 2025-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: spree
|
@@ -204,10 +204,13 @@ files:
|
|
204
204
|
- app/jobs/spree_stripe/complete_order_job.rb
|
205
205
|
- app/jobs/spree_stripe/create_webhook_endpoint_job.rb
|
206
206
|
- app/jobs/spree_stripe/register_domain_job.rb
|
207
|
+
- app/jobs/spree_stripe/update_customer_job.rb
|
208
|
+
- app/models/spree_stripe/address_decorator.rb
|
207
209
|
- app/models/spree_stripe/base.rb
|
208
210
|
- app/models/spree_stripe/credit_card_decorator.rb
|
209
211
|
- app/models/spree_stripe/custom_domain_decorator.rb
|
210
212
|
- app/models/spree_stripe/gateway.rb
|
213
|
+
- app/models/spree_stripe/gateway_customer_decorator.rb
|
211
214
|
- app/models/spree_stripe/order_decorator.rb
|
212
215
|
- app/models/spree_stripe/payment_decorator.rb
|
213
216
|
- app/models/spree_stripe/payment_intent.rb
|
@@ -223,6 +226,7 @@ files:
|
|
223
226
|
- app/models/spree_stripe/payment_sources/przelewy24.rb
|
224
227
|
- app/models/spree_stripe/payment_sources/sepa_debit.rb
|
225
228
|
- app/models/spree_stripe/store_decorator.rb
|
229
|
+
- app/models/spree_stripe/user_decorator.rb
|
226
230
|
- app/models/spree_stripe/webhook_key.rb
|
227
231
|
- app/presenters/spree_stripe/customer_presenter.rb
|
228
232
|
- app/presenters/spree_stripe/payment_intent_presenter.rb
|
@@ -251,6 +255,7 @@ files:
|
|
251
255
|
- app/services/spree_stripe/create_setup_intent.rb
|
252
256
|
- app/services/spree_stripe/create_source.rb
|
253
257
|
- app/services/spree_stripe/register_domain.rb
|
258
|
+
- app/services/spree_stripe/update_customer.rb
|
254
259
|
- app/services/spree_stripe/webhook_handlers/payment_intent_payment_failed.rb
|
255
260
|
- app/services/spree_stripe/webhook_handlers/payment_intent_succeeded.rb
|
256
261
|
- app/services/spree_stripe/webhook_handlers/setup_intent_succeeded.rb
|