spree_stripe 6.0.0 → 6.0.2

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: f11b0571ed27cbf8d0fc226eb6be6e4fd0132dd10c813bd721ab9b821620eea0
4
- data.tar.gz: 628e43f18f6a8101d50aef245a30fadf58361d468e0047ec44632fd91bf4d678
3
+ metadata.gz: c1fcd61b50a152f08e6a5434ca784000df9701d20a21504862e8bbaf163f0b08
4
+ data.tar.gz: '096b6f4bdcc0e118a9013b0c50c6f411e76fc22796bef8558de31074eaf58e3b'
5
5
  SHA512:
6
- metadata.gz: 1aaf8e88ef87e4eaff0212cf55c4ac7dd5b5db46e208bf19fbdf1bcb5a06c77e634ae29fc1b06d1bff56b8c0a5825ed5f16081b92965fa9e4a2889dabc3a37b6
7
- data.tar.gz: 5d15a1b370f4f8f4fa1630854173bb9d0f049df47a3f4acf1c7a9d4f8b3fa8a5d8771df7ee2ffc161a8066e0a74fc8913e356e45288d4cc43f2fc5b1c33b5875
6
+ metadata.gz: 023b9092770dc58004da4557a2c11cc29e2e6be1b018f7222d501647c2d27975d5cee59da47b2c20ff409526a4b3048025d12dd2323b7c8cea856c7ee4b4a558
7
+ data.tar.gz: f8265ae450f3f8afac7ed4c9a1dd07cadd68db361981d0c82e5f15e8e1e79cbb44b4eb1b0031abd48f30994b8810ef73f65a4ecf58d9f6fb4aa4cec73cbca313
@@ -93,7 +93,7 @@ module SpreeStripe
93
93
  def connect_webhook_url
94
94
  return nil unless store
95
95
 
96
- "#{store.url_or_custom_domain}/api/v3/webhooks/payouts/#{prefixed_id}"
96
+ "#{store.formatted_url_or_custom_domain}/api/v3/webhooks/payouts/#{prefixed_id}"
97
97
  end
98
98
 
99
99
  def create_connect_webhook_endpoint
@@ -130,6 +130,12 @@ module SpreeStripe
130
130
  end
131
131
  end
132
132
 
133
+ # Voiding cancels the PaymentIntent, which Stripe refuses once it has
134
+ # succeeded; a captured payment has to be refunded instead.
135
+ def can_void?(payment)
136
+ !payment.completed?
137
+ end
138
+
133
139
  def void(response_code, _source, _gateway_options)
134
140
  return failure('Response code is blank') if response_code.blank?
135
141
 
@@ -266,15 +266,58 @@ module SpreeStripe
266
266
  raise Spree::Core::AmbiguousGatewayError, e.message
267
267
  end
268
268
 
269
- # Pulls a seller's money back after a refund.
269
+ # Pulls a seller's share of a refund back from their connected account.
270
270
  #
271
- # Ledger-only in open source: the row is written either way, so the books
272
- # stay correct, but reversing the Stripe transfer — and netting a negative
273
- # balance against future earnings — is where a marketplace needs the money
274
- # operations that Enterprise provides.
271
+ # Reverses the transfer that paid the earning, by the reversal's amount,
272
+ # so the money returns to the platform that refunded the customer. A
273
+ # seller who has already been paid out is left with a negative Stripe
274
+ # balance, which their next earnings make up before anything more is paid
275
+ # out to them.
276
+ #
277
+ # The reversal waits until its earning has reached Stripe: until then
278
+ # there is no transfer to take from. It is left pending, and the
279
+ # pending-transfers job asks again once the earning is sent.
280
+ #
281
+ # A retry first looks for a reversal an earlier attempt already made, so
282
+ # the seller is never charged twice for one refund.
275
283
  def reverse!(seller_transfer)
276
- seller_transfer.update!(status: 'completed')
284
+ return complete_without_sending(seller_transfer) if minor_units(seller_transfer).zero?
285
+
286
+ earning = seller_transfer.reversed_from
287
+ raise Spree::Core::GatewayError, 'Reversal has no earning to take back from' if earning.nil?
288
+ # Never sent, so nothing reached the seller's account.
289
+ return complete_without_sending(seller_transfer) if earning.failed?
290
+ return seller_transfer unless earning.completed?
291
+
292
+ # Confirmed without a transfer to point at — settled by hand, say. Only
293
+ # a person can say where that money is.
294
+ if earning.reference.blank?
295
+ raise Spree::Core::AmbiguousGatewayError, 'The earning has no Stripe transfer to reverse'
296
+ end
297
+
298
+ api_options = gateway_for(seller_transfer.seller.store).api_options
299
+ reversal = made_reversal(earning, seller_transfer, api_options) || Stripe::Transfer.create_reversal(
300
+ earning.reference,
301
+ {
302
+ amount: minor_units(seller_transfer),
303
+ metadata: {
304
+ spree_seller_transfer_id: seller_transfer.id,
305
+ spree_order_number: seller_transfer.order.number
306
+ }
307
+ },
308
+ api_options.merge(idempotency_key: idempotency_key(seller_transfer))
309
+ )
310
+
311
+ # The earning may have been sent after this row was written, and only
312
+ # then learned the currency it settled in.
313
+ seller_transfer.update!(
314
+ { status: 'completed', reference: reversal.id }.merge(earning.reversal_settlement(seller_transfer.amount.abs))
315
+ )
277
316
  seller_transfer
317
+ rescue *AMBIGUOUS_ERRORS => e
318
+ # The reversal may have been made before the answer was lost, so core
319
+ # parks it rather than taking the money back twice.
320
+ raise Spree::Core::AmbiguousGatewayError, e.message
278
321
  end
279
322
 
280
323
  private
@@ -300,6 +343,21 @@ module SpreeStripe
300
343
  seller_transfer
301
344
  end
302
345
 
346
+ # The reversal an earlier attempt made but never recorded — the row failed
347
+ # to save, or the process stopped first. Found by the row it names, since
348
+ # the idempotency key that would also stop a second one lasts only a day.
349
+ #
350
+ # A failed lookup moved no money, so it is a refusal the retry job can
351
+ # repeat rather than an outcome nobody knows.
352
+ def made_reversal(earning, seller_transfer, api_options)
353
+ reversals = Stripe::Transfer.list_reversals(earning.reference, { limit: 100 }, api_options)
354
+ reversals.auto_paging_each.find do |reversal|
355
+ reversal.metadata['spree_seller_transfer_id'] == seller_transfer.id.to_s
356
+ end
357
+ rescue Stripe::StripeError => e
358
+ raise Spree::Core::GatewayError, e.message
359
+ end
360
+
303
361
  # Nil rather than raising: a checklist row asking why it is incomplete
304
362
  # must not take the page down because Stripe is unreachable.
305
363
  def retrieve_account(seller)
@@ -50,7 +50,8 @@ module SpreeStripe
50
50
 
51
51
  def find_or_create_credit_card
52
52
  if customer
53
- exact_source = customer.credit_cards.find_by(gateway_payment_profile_id: stripe_payment_method_id)
53
+ exact_source = customer.credit_cards.where(payment_method: gateway).
54
+ find_by(gateway_payment_profile_id: stripe_payment_method_id)
54
55
  return exact_source if exact_source
55
56
 
56
57
  matching_source = match_credit_card_by_fingerprint
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
4
+ version: 6.0.2
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-10-27 00:00:00.000000000 Z
12
+ date: 2026-11-02 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
20
+ version: 6.0.2
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
27
+ version: 6.0.2
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: stripe
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -112,9 +112,9 @@ licenses:
112
112
  - MIT
113
113
  metadata:
114
114
  bug_tracker_uri: https://github.com/spree/spree/issues
115
- changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.0
116
- documentation_uri: https://docs.spreecommerce.org/
117
- source_code_uri: https://github.com/spree/spree/tree/v6.0.0
115
+ changelog_uri: https://github.com/spree/spree/releases/tag/v6.0.2
116
+ documentation_uri: https://spreecommerce.org/docs/
117
+ source_code_uri: https://github.com/spree/spree/tree/v6.0.2
118
118
  post_install_message:
119
119
  rdoc_options: []
120
120
  require_paths: