spree_stripe 6.0.0.beta4 → 6.0.0.rc2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 761c677448596680810cd6380436150bd4ed2451322f2942e8033511c777176f
4
- data.tar.gz: 7d19dd53fe7b8c742df6d141ff166870f15c093c57081c90cd0d86efd572fb4b
3
+ metadata.gz: 8983341a30de22cd7fa7ad6b6d71aebe323935bfdda5ec4ae7644cd0a268d2e9
4
+ data.tar.gz: b249b9acba1b25c1590c960336ee58130ff94a67eb9daf4b300fd508b354a1d5
5
5
  SHA512:
6
- metadata.gz: 36dc8fdf7281243405d91bf3e466429cba10b146430c93e46f10883391b47163fb5d03159314940f29c285ec380c9bc4d6fe80f89e2b535ef5850bc6873424f3
7
- data.tar.gz: 05ce651862abfee5a54a2716674edfc958016a8ff868ca7a98d31439e11e20207e4885568c2517a3e3ce42449d97d02c9b791742fc3e2b629305f30d960f0ef1
6
+ metadata.gz: b334eb2bcb2d3be7b32688b51b5585616b895c22c6c012b8da7f42dad3595b65e35f506b58b30bccffc324fc5b704ceb80cb59199ef42470092534ab9b27ba8f
7
+ data.tar.gz: 8e4737ce51b74cbd937790c27a8bc2befab609b1d7391fa9c1e792dfc9a0d11be5b48f9ccb5f63dabb0c5f56acec41ba084b6db23a264e072702cdc65a8c205b
@@ -15,6 +15,18 @@ module SpreeStripe
15
15
  MANUAL_CAPTURE_METHOD = 'manual'.freeze
16
16
  SETUP_FUTURE_USAGE = 'off_session'.freeze
17
17
 
18
+ # Not a decision about the intent. A timeout and an outage may not have
19
+ # arrived; a rate limit was turned away before Stripe looked; a bad key
20
+ # or a missing permission never reached the intent. A refusal of the
21
+ # cancel itself is an InvalidRequestError and stays out of this list.
22
+ RETRYABLE_STRIPE_ERRORS = [
23
+ Stripe::APIConnectionError,
24
+ Stripe::RateLimitError,
25
+ Stripe::APIError,
26
+ Stripe::AuthenticationError,
27
+ Stripe::PermissionError
28
+ ].freeze
29
+
18
30
  def session_required?
19
31
  true
20
32
  end
@@ -23,19 +35,31 @@ module SpreeStripe
23
35
  Spree::PaymentSessions::Stripe
24
36
  end
25
37
 
38
+ # Opens a new session on every call. Each earlier session that can still
39
+ # be paid is canceled first: every open intent can be paid on its own,
40
+ # so a reloaded checkout would charge the buyer twice. A session Stripe
41
+ # has already accepted, a card charge still in flight, or one this cart
42
+ # has already completed is left as it is and the request fails, because
43
+ # that money is not dropped to make room for another session.
44
+ #
26
45
  # @param order [Spree::Cart, Spree::Order]
27
46
  # @return [Spree::PaymentSessions::Stripe]
47
+ # @raise [Spree::Core::GatewayError] when a session has already been
48
+ # paid, or an earlier one could not be canceled
28
49
  def create_payment_session(order:, amount: nil, external_data: {})
29
50
  total = amount.presence || order.total_minus_store_credits
30
- amount_in_cents = Spree::Money.new(total, currency: order.currency).cents
51
+ stripe_amount = SpreeStripe::Units.to_stripe(total, order.currency)
31
52
 
32
- raise Spree::Core::GatewayError, Spree.t('stripe.payment_session_errors.zero_amount') if amount_in_cents.zero?
53
+ raise Spree::Core::GatewayError, I18n.t('spree.stripe.payment_session_errors.zero_amount') if stripe_amount.zero?
33
54
 
34
- gateway_customer = fetch_or_create_customer(order: order)
35
55
  stripe_payment_method_id = external_data[:stripe_payment_method_id] || external_data['stripe_payment_method_id']
36
56
 
57
+ replace_open_sessions(order)
58
+
59
+ gateway_customer = fetch_or_create_customer(order: order)
60
+
37
61
  response = create_payment_intent(
38
- amount_in_cents, order,
62
+ stripe_amount, order,
39
63
  payment_method_id: stripe_payment_method_id,
40
64
  customer_profile_id: gateway_customer&.profile_id
41
65
  )
@@ -61,18 +85,18 @@ module SpreeStripe
61
85
 
62
86
  def update_payment_session(payment_session:, amount: nil, external_data: {})
63
87
  attrs = {}
64
- amount_in_cents = nil
88
+ stripe_amount = nil
65
89
 
66
90
  if amount.present?
67
91
  attrs[:amount] = amount
68
- amount_in_cents = Spree::Money.new(amount, currency: payment_session.currency).cents
92
+ stripe_amount = SpreeStripe::Units.to_stripe(amount, payment_session.currency)
69
93
  end
70
94
 
71
95
  stripe_payment_method_id = external_data[:stripe_payment_method_id] || external_data['stripe_payment_method_id']
72
96
 
73
97
  update_payment_intent(
74
98
  payment_session.external_id,
75
- amount_in_cents || payment_session.amount_in_cents,
99
+ stripe_amount || SpreeStripe::Units.to_stripe(payment_session.amount, payment_session.currency),
76
100
  payment_session.owner,
77
101
  stripe_payment_method_id
78
102
  )
@@ -110,6 +134,29 @@ module SpreeStripe
110
134
  payment_session
111
135
  end
112
136
 
137
+ # Stripe refuses once money has moved, and that refusal is raised so the
138
+ # session is never shown as canceled while its money stands. An intent
139
+ # already canceled at Stripe, or unknown to the account the keys now
140
+ # reach, can no longer be paid, so its session is canceled all the same.
141
+ # A timeout, a rate limit, an outage, or rejected credentials is raised
142
+ # as Stripe's own error: wrapped as a refusal, the unused-session job
143
+ # would count the intent handled while the buyer can still pay it.
144
+ #
145
+ # @param payment_session [Spree::PaymentSessions::Stripe]
146
+ # @return [Boolean] whether the session was canceled
147
+ # @raise [Spree::Core::GatewayError] when Stripe refuses
148
+ # @raise [Stripe::StripeError] when Stripe could not be asked
149
+ def cancel_payment_session(payment_session:)
150
+ cancel_payment_intent(payment_session.external_id)
151
+ payment_session.cancel
152
+ rescue *RETRYABLE_STRIPE_ERRORS
153
+ raise
154
+ rescue Stripe::StripeError => error
155
+ raise Spree::Core::GatewayError, error.message unless payment_intent_unpayable?(payment_session.external_id)
156
+
157
+ payment_session.cancel
158
+ end
159
+
113
160
  def retrieve_payment_intent(payment_intent_id)
114
161
  send_request { |opts| Stripe::PaymentIntent.retrieve({ id: payment_intent_id, expand: ['payment_method'] }, opts) }
115
162
  end
@@ -118,8 +165,8 @@ module SpreeStripe
118
165
  send_request { |opts| Stripe::PaymentIntent.confirm(payment_intent_id, {}, opts) }
119
166
  end
120
167
 
121
- def capture_payment_intent(payment_intent_id, amount_in_cents)
122
- send_request { |opts| Stripe::PaymentIntent.capture(payment_intent_id, { amount_to_capture: amount_in_cents }, opts) }
168
+ def capture_payment_intent(payment_intent_id, stripe_amount)
169
+ send_request { |opts| Stripe::PaymentIntent.capture(payment_intent_id, { amount_to_capture: stripe_amount }, opts) }
123
170
  end
124
171
 
125
172
  def cancel_payment_intent(payment_intent_id)
@@ -170,11 +217,65 @@ module SpreeStripe
170
217
 
171
218
  private
172
219
 
220
+ # Nothing is canceled until every still-payable intent has been read. A
221
+ # later one that Stripe has already accepted must not be reached after
222
+ # an earlier one was dropped. A completed session is the same refusal
223
+ # with no provider call: the cart already has its payment.
224
+ def replace_open_sessions(order)
225
+ sessions = order.payment_sessions.where(payment_method: self)
226
+ if sessions.exists?(status: 'completed')
227
+ raise Spree::Core::GatewayError, I18n.t('spree.stripe.payment_session_errors.payment_in_progress')
228
+ end
229
+
230
+ # A failed confirm leaves the intent payable. It is canceled with the
231
+ # open ones, unless its charge is still in flight.
232
+ open_sessions = sessions.active.order(:id).to_a + sessions.where(status: 'failed').order(:id).to_a
233
+ return if open_sessions.empty?
234
+
235
+ open_sessions.each do |payment_session|
236
+ payment_intent = find_payment_intent(payment_session.external_id)
237
+ next unless payment_intent && payment_intent_in_progress?(payment_intent)
238
+
239
+ raise Spree::Core::GatewayError, I18n.t('spree.stripe.payment_session_errors.payment_in_progress')
240
+ end
241
+
242
+ open_sessions.each do |payment_session|
243
+ cancel_payment_session(payment_session: payment_session)
244
+ end
245
+ rescue *RETRYABLE_STRIPE_ERRORS => error
246
+ # Checkout speaks GatewayError. The unused-session job does not: it
247
+ # retries these, and has to see them unwrapped.
248
+ raise Spree::Core::GatewayError, error.message
249
+ end
250
+
251
+ # A card can sit in `processing` while its charge is in flight.
252
+ # `payment_intent_accepted?` does not record that yet, and canceling
253
+ # the intent can drop or refund the charge.
254
+ def payment_intent_in_progress?(payment_intent)
255
+ payment_intent.status == 'processing' || payment_intent_accepted?(payment_intent)
256
+ end
257
+
258
+ # nil when the account the keys now reach has no such intent.
259
+ def find_payment_intent(payment_intent_id)
260
+ retrieve_payment_intent(payment_intent_id)
261
+ rescue Stripe::InvalidRequestError => error
262
+ raise Spree::Core::GatewayError, error.message unless error.code == 'resource_missing'
263
+ rescue *RETRYABLE_STRIPE_ERRORS
264
+ raise
265
+ rescue Stripe::StripeError => error
266
+ raise Spree::Core::GatewayError, error.message
267
+ end
268
+
269
+ def payment_intent_unpayable?(payment_intent_id)
270
+ payment_intent = find_payment_intent(payment_intent_id)
271
+ payment_intent.nil? || payment_intent.status == 'canceled'
272
+ end
273
+
173
274
  # @param order [Spree::Cart, Spree::Order]
174
275
  # @return [Spree::PaymentResponse]
175
- def create_payment_intent(amount_in_cents, order, payment_method_id: nil, customer_profile_id: nil)
276
+ def create_payment_intent(stripe_amount, order, payment_method_id: nil, customer_profile_id: nil)
176
277
  payload = {
177
- amount: amount_in_cents,
278
+ amount: stripe_amount,
178
279
  currency: order.currency,
179
280
  customer: customer_profile_id,
180
281
  payment_method: payment_method_id,
@@ -203,10 +304,10 @@ module SpreeStripe
203
304
  end
204
305
 
205
306
  # Only the fields that can legitimately change while a session is pending.
206
- def update_payment_intent(payment_intent_id, amount_in_cents, order, payment_method_id = nil)
307
+ def update_payment_intent(payment_intent_id, stripe_amount, order, payment_method_id = nil)
207
308
  protect_from_error do
208
309
  payload = {
209
- amount: amount_in_cents,
310
+ amount: stripe_amount,
210
311
  currency: order.currency,
211
312
  customer: fetch_or_create_customer(order: order)&.profile_id,
212
313
  payment_method: payment_method_id,
@@ -3,6 +3,8 @@ module SpreeStripe
3
3
  # created and confirmed through sessions; core's payment lifecycle then drives
4
4
  # capture, refund and cancellation against the resulting intent.
5
5
  class Gateway < ::Spree::Gateway
6
+ self.accepts_money_amounts = true
7
+
6
8
  include SpreeStripe::Gateway::PaymentSessions
7
9
  include SpreeStripe::Gateway::PaymentSetupSessions
8
10
  include SpreeStripe::Gateway::Webhooks
@@ -22,6 +24,14 @@ module SpreeStripe
22
24
  validates :preferred_secret_key, :preferred_publishable_key, presence: true
23
25
  validate :validate_secret_key, unless: -> { Rails.env.test? }, if: -> { preferred_secret_key.present? }
24
26
 
27
+ def self.logo_url
28
+ 'https://spreecommerce.org/docs/images/integrations/logos/stripe.png'
29
+ end
30
+
31
+ def self.docs_url
32
+ 'https://spreecommerce.org/docs/integrations/payments/stripe'
33
+ end
34
+
25
35
  def provider_class
26
36
  self.class
27
37
  end
@@ -50,12 +60,10 @@ module SpreeStripe
50
60
  #
51
61
  # @return [Boolean]
52
62
  def only_webhook_registration_changed?
53
- before, after = saved_change_to_preferences
54
- return false unless before.is_a?(Hash) && after.is_a?(Hash)
55
-
56
- changed = (before.keys | after.keys).reject { |key| before[key] == after[key] }
63
+ return false if previously_new_record?
57
64
 
58
- changed.any? && changed.all? { |key| WEBHOOK_REGISTRATION_PREFERENCES.include?(key.to_sym) }
65
+ changed = previously_changed_preference_names
66
+ changed.any? && changed.all? { |key| WEBHOOK_REGISTRATION_PREFERENCES.include?(key) }
59
67
  end
60
68
 
61
69
  # Endpoints are registered per Stripe account, so a rotated key leaves the
@@ -67,10 +75,7 @@ module SpreeStripe
67
75
  # read as every key having changed.
68
76
  return false if previously_new_record?
69
77
 
70
- # The preference macro's own reader rather than a hand-rolled diff: it
71
- # reads the change through indifferent access, so it answers the same
72
- # whether the serialized hash came back with symbol or string keys.
73
- preferred_secret_key_previously_changed?
78
+ saved_change_to_preferred_secret_key?
74
79
  end
75
80
 
76
81
  def gateway_dashboard_payment_url(payment)
@@ -83,26 +88,26 @@ module SpreeStripe
83
88
  # is already confirmed client-side in the session flow, so this reads back the
84
89
  # intent rather than initiating a charge.
85
90
  #
86
- # @param amount_in_cents [Integer]
91
+ # @param money [Spree::Money]
87
92
  # @param payment_source [Spree::PaymentSource, Spree::CreditCard]
88
93
  # @param gateway_options [Hash] Spree::Payment::GatewayOptions#to_hash
89
94
  # @return [Spree::PaymentResponse]
90
- def authorize(amount_in_cents, payment_source, gateway_options = {})
91
- handle_authorize_or_purchase(amount_in_cents, payment_source, gateway_options)
95
+ def authorize(money, payment_source, gateway_options = {})
96
+ handle_authorize_or_purchase(money, payment_source, gateway_options)
92
97
  end
93
98
 
94
99
  # @see #authorize — capture vs authorize is decided by the intent's capture
95
100
  # method, so both resolve the same way.
96
- def purchase(amount_in_cents, payment_source, gateway_options = {})
97
- handle_authorize_or_purchase(amount_in_cents, payment_source, gateway_options)
101
+ def purchase(money, payment_source, gateway_options = {})
102
+ handle_authorize_or_purchase(money, payment_source, gateway_options)
98
103
  end
99
104
 
100
- def capture(amount_in_cents, payment_intent_id, _gateway_options = {})
105
+ def capture(money, payment_intent_id, _gateway_options = {})
101
106
  protect_from_error do
102
107
  stripe_payment_intent = retrieve_payment_intent(payment_intent_id)
103
108
 
104
109
  response = if payment_intent_requires_capture?(stripe_payment_intent)
105
- capture_payment_intent(payment_intent_id, amount_in_cents)
110
+ capture_payment_intent(payment_intent_id, SpreeStripe::Units.to_stripe(money, money.currency))
106
111
  elsif stripe_payment_intent.status == 'succeeded'
107
112
  stripe_payment_intent
108
113
  else
@@ -113,10 +118,10 @@ module SpreeStripe
113
118
  end
114
119
  end
115
120
 
116
- def credit(amount_in_cents, _source, payment_intent_id, _gateway_options = {})
121
+ def credit(money, _source, payment_intent_id, _gateway_options = {})
117
122
  protect_from_error do
118
123
  response = send_request do |opts|
119
- Stripe::Refund.create({ amount: amount_in_cents, payment_intent: payment_intent_id }, opts)
124
+ Stripe::Refund.create({ amount: SpreeStripe::Units.to_stripe(money, money.currency), payment_intent: payment_intent_id }, opts)
120
125
  end
121
126
 
122
127
  success(response.id, response)
@@ -266,7 +271,7 @@ module SpreeStripe
266
271
 
267
272
  private
268
273
 
269
- def handle_authorize_or_purchase(amount_in_cents, _payment_source, gateway_options)
274
+ def handle_authorize_or_purchase(_money, _payment_source, gateway_options)
270
275
  # Scoped through this gateway's own payments — a cart-owned payment
271
276
  # (checkout is still in flight) has no order to join through, and the
272
277
  # payment method already belongs to exactly one store. Found by the
@@ -302,14 +307,14 @@ module SpreeStripe
302
307
  def validate_secret_key
303
308
  Stripe::Refund.list({ limit: 0 }, api_options)
304
309
  rescue Stripe::AuthenticationError
305
- errors.add(:base, :secret_key_invalid, message: Spree.t('stripe.errors.secret_key_invalid'))
310
+ errors.add(:base, :secret_key_invalid, message: I18n.t('spree.stripe.errors.secret_key_invalid'))
306
311
  rescue Stripe::PermissionError => e
307
312
  return unless e.error&.code == 'secret_key_required'
308
313
 
309
314
  errors.add(:base, :publishable_key_provided,
310
- message: Spree.t('stripe.errors.publishable_key_provided'))
315
+ message: I18n.t('spree.stripe.errors.publishable_key_provided'))
311
316
  rescue Stripe::StripeError
312
- errors.add(:base, :stripe_unavailable, message: Spree.t('stripe.errors.stripe_unavailable'))
317
+ errors.add(:base, :stripe_unavailable, message: I18n.t('spree.stripe.errors.stripe_unavailable'))
313
318
  end
314
319
 
315
320
  def build_customer_payload(order: nil, customer: nil)
@@ -6,11 +6,11 @@ module SpreeStripe
6
6
  end
7
7
 
8
8
  def self.display_name
9
- Spree.t(:bank_transfer)
9
+ I18n.t('spree.bank_transfer')
10
10
  end
11
11
 
12
12
  def name
13
- Spree.t(:bank_transfer)
13
+ I18n.t('spree.bank_transfer')
14
14
  end
15
15
  end
16
16
  end
@@ -258,7 +258,7 @@ module SpreeStripe
258
258
  wanted = currency.to_s.downcase
259
259
  minor = balance.available.select { |entry| entry.currency == wanted }.sum(&:amount)
260
260
 
261
- Spree::Money::Rounding.from_minor_units(minor, currency)
261
+ SpreeStripe::Units.from_stripe(minor, currency)
262
262
  rescue *AMBIGUOUS_ERRORS => e
263
263
  # The sweep must not read silence as "nothing to send" and settle a
264
264
  # smaller batch than the seller is owed, nor as "no limit" and ask for
@@ -290,8 +290,7 @@ module SpreeStripe
290
290
  return {} if balance_transaction.blank? || balance_transaction.try(:currency).blank?
291
291
 
292
292
  {
293
- settled_amount: Spree::Money::Rounding.from_minor_units(balance_transaction.amount,
294
- balance_transaction.currency),
293
+ settled_amount: SpreeStripe::Units.from_stripe(balance_transaction.amount, balance_transaction.currency),
295
294
  settled_currency: balance_transaction.currency.upcase
296
295
  }
297
296
  end
@@ -322,7 +321,7 @@ module SpreeStripe
322
321
  end
323
322
 
324
323
  def minor_units(record)
325
- Spree::Money::Rounding.to_minor_units(record.amount.abs, record.currency)
324
+ SpreeStripe::Units.to_stripe(record.amount.abs, record.currency, payout: true)
326
325
  end
327
326
 
328
327
  # Ties transfers paid from the platform balance to the checkout they
@@ -0,0 +1,52 @@
1
+ module SpreeStripe
2
+ # Stripe's integer amounts. Mostly the currency's ISO minor unit, with
3
+ # Stripe's own exceptions (https://docs.stripe.com/currencies): its
4
+ # zero-decimal currencies are sent in whole units, and ISK and UGX, zero-decimal
5
+ # since, are still sent as two-decimal values ending in 00. Stripe also takes
6
+ # three-decimal currencies only in steps of 0.010, and pays out HUF and TWD
7
+ # only in whole units; an amount it would refuse raises here, naming the rule,
8
+ # rather than being rounded to a sum other than the one Spree records.
9
+ module Units
10
+ module_function
11
+
12
+ ZERO_DECIMAL = %w[BIF CLP DJF GNF JPY KMF KRW MGA PYG RWF VND VUV XAF XOF XPF].freeze
13
+ WHOLE_IN_HUNDREDTHS = %w[ISK UGX].freeze
14
+ THREE_DECIMAL = %w[BHD JOD KWD OMR TND].freeze
15
+ WHOLE_PAYOUTS = %w[HUF TWD].freeze
16
+
17
+ class UnsupportedAmount < Spree::Core::GatewayError; end
18
+
19
+ # @param amount [BigDecimal, Spree::Money]
20
+ # @param currency [String]
21
+ # @param payout [Boolean] a payout or transfer rather than a charge
22
+ # @return [Integer]
23
+ # @raise [UnsupportedAmount] when Stripe would refuse the amount
24
+ def to_stripe(amount, currency, payout: false)
25
+ amount = amount.to_d if amount.respond_to?(:to_d)
26
+ code = currency.to_s.upcase
27
+ return Spree::Money::Rounding.quantize(amount, 0).to_i if ZERO_DECIMAL.include?(code)
28
+ return Spree::Money::Rounding.quantize(amount, 0).to_i * 100 if WHOLE_IN_HUNDREDTHS.include?(code)
29
+
30
+ units = Spree::Money::Rounding.to_minor_units(amount, code)
31
+ if THREE_DECIMAL.include?(code) && (units % 10).nonzero?
32
+ raise UnsupportedAmount, "Stripe takes #{code} only in steps of 0.010, got #{amount.to_s('F')}"
33
+ end
34
+ if payout && WHOLE_PAYOUTS.include?(code) && (units % 100).nonzero?
35
+ raise UnsupportedAmount, "Stripe pays out #{code} only in whole units, got #{amount.to_s('F')}"
36
+ end
37
+
38
+ units
39
+ end
40
+
41
+ # @param units [Integer] as Stripe reports it
42
+ # @param currency [String]
43
+ # @return [BigDecimal]
44
+ def from_stripe(units, currency)
45
+ code = currency.to_s.upcase
46
+ return BigDecimal(units) if ZERO_DECIMAL.include?(code)
47
+ return BigDecimal(units) / 100 if WHOLE_IN_HUNDREDTHS.include?(code)
48
+
49
+ Spree::Money::Rounding.from_minor_units(units, code)
50
+ end
51
+ end
52
+ end
@@ -7,6 +7,6 @@ en:
7
7
  publishable_key_provided: You have provided your publishable key instead of your secret key
8
8
  secret_key_invalid: Secret key is invalid
9
9
  stripe_unavailable: Something went wrong with Stripe. Try again later.
10
- payment_could_not_be_processed: Your payment could not be processed. Please try again.
11
10
  payment_session_errors:
11
+ payment_in_progress: A payment for this checkout is already in progress.
12
12
  zero_amount: Payment session amount must be greater than zero
@@ -5,12 +5,6 @@ module SpreeStripe
5
5
  isolate_namespace Spree
6
6
  engine_name 'spree_stripe'
7
7
 
8
- config.paths.add 'app/subscribers', eager_load: true
9
-
10
- config.generators do |g|
11
- g.test_framework :rspec
12
- end
13
-
14
8
  # Core assigns the payment method registry in its own after_initialize, so
15
9
  # appending has to happen in a later one — engine callbacks run in load order.
16
10
  config.after_initialize do
@@ -40,11 +40,14 @@ module SpreeStripe
40
40
  next
41
41
  end
42
42
 
43
+ # Through the preference writers, so the signing secret lands in the
44
+ # encrypted column; saved without callbacks, which would re-register
45
+ # the endpoint the secret belongs to.
46
+ gateway.preferred_webhook_endpoint_id = key.stripe_id
47
+ gateway.preferred_webhook_signing_secret = key.signing_secret
43
48
  gateway.update_columns(
44
- preferences: gateway.preferences.merge(
45
- webhook_endpoint_id: key.stripe_id,
46
- webhook_signing_secret: key.signing_secret
47
- ),
49
+ preferences: gateway.preferences,
50
+ secret_preferences: gateway.secret_preferences,
48
51
  updated_at: Time.current
49
52
  )
50
53
  migrated += 1
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.0.beta4
4
+ version: 6.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vendo Connect Inc.
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2026-09-24 00:00:00.000000000 Z
12
+ date: 2026-10-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: spree_core
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - '='
19
19
  - !ruby/object:Gem::Version
20
- version: 6.0.0.beta4
20
+ version: 6.0.0.rc2
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - '='
26
26
  - !ruby/object:Gem::Version
27
- version: 6.0.0.beta4
27
+ version: 6.0.0.rc2
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: stripe
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -89,6 +89,7 @@ files:
89
89
  - app/models/spree_stripe/payment_sources/przelewy24.rb
90
90
  - app/models/spree_stripe/payment_sources/sepa_debit.rb
91
91
  - app/models/spree_stripe/payout_provider.rb
92
+ - app/models/spree_stripe/units.rb
92
93
  - app/presenters/spree_stripe/customer_presenter.rb
93
94
  - app/presenters/spree_stripe/statement_descriptor_suffix_presenter.rb
94
95
  - app/services/spree_stripe/create_gateway_webhooks.rb
@@ -110,9 +111,9 @@ licenses:
110
111
  - MIT
111
112
  metadata:
112
113
  bug_tracker_uri: https://github.com/spree/spree/issues
113
- changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.0.beta4
114
+ changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.0.rc2
114
115
  documentation_uri: https://docs.spreecommerce.org/
115
- source_code_uri: https://github.com/spree/spree/tree/v6.0.0.beta4
116
+ source_code_uri: https://github.com/spree/spree/tree/v6.0.0.rc2
116
117
  post_install_message:
117
118
  rdoc_options: []
118
119
  require_paths: