spree_razorpay_checkout 0.3.0 → 0.3.1

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: a2ae9eca9f07041baff888721f0da631374e73925e8237eeafe32ccfe5185298
4
- data.tar.gz: b087fa0f6961cc60c77c38cef002566104a19f6a3a87519658d69c2eb0174ec0
3
+ metadata.gz: c4200b3ff85e0fea3d0c4412d81dd7af4cf4a66cdb5d582b871b88a8ac6bc2fc
4
+ data.tar.gz: d142c51d56ba5b2f1eb445780fc887012e1e199abb767f5edaf85f8badc8ce17
5
5
  SHA512:
6
- metadata.gz: 4262af60d12805b8d7ee60cae23b03f95d9211a806bc39d88d8a4cbe556e280428921d1c9c14b940f56d92128b1e952e7ea99f0d69436bb00071b16c425b83e5
7
- data.tar.gz: bf60c0322601d7dfed075e214828ab5fabf98f55a57760ab3f7b73c9b40edc3c3da7a19ac04ac5ff267b23f8130171332c4a522da996533832d1568e23f0652d
6
+ metadata.gz: 48701e4dda07a8fa192f320981418ae79c5b744bff3e650935a4fac1485c66878bd19414bc4ca72d7411b5ad829bcbf2b0161ed214818057a459630e76cc267d
7
+ data.tar.gz: 800b0a224a91684f8f7072adc953665091702bda9aafba80f6898bc009cf466300567a579707f53fba9ab855218e76da543beafacc24c562c6a8f3dd6b77eee5
@@ -162,21 +162,35 @@ module Spree
162
162
  razorpay_signature: rzp_signature
163
163
  )
164
164
 
165
- rzp_payment = ::Razorpay::Payment.fetch(rzp_payment_id)
166
- if rzp_payment.status == 'authorized'
167
- rzp_payment.capture({ amount: (payment_session.amount.to_f * 100).to_i })
165
+ # Lock the order database row to prevent race conditions with Webhooks
166
+ payment_session.order.with_lock do
167
+
168
+ # Save the verified IDs into the session so the new Session Class can read them
169
+ session_data = payment_session.external_data || {}
170
+ session_data['razorpay_payment_id'] = rzp_payment_id
171
+ session_data['razorpay_signature'] = rzp_signature
172
+ payment_session.update!(external_data: session_data)
173
+
174
+ # Capture the payment
175
+ rzp_payment = ::Razorpay::Payment.fetch(rzp_payment_id)
176
+ if rzp_payment.status == 'authorized'
177
+ rzp_payment.capture({ amount: (payment_session.amount.to_f * 100).to_i })
178
+ end
179
+
180
+ # Process and Create Payment
181
+ payment_session.process! if payment_session.can_process?
182
+
183
+ # This safely calls your new Spree::PaymentSessions::Razorpay class!
184
+ payment = payment_session.find_or_create_payment!
185
+
186
+ if payment.present? && !payment.completed?
187
+ payment.started_processing! if payment.checkout?
188
+ payment.complete! if payment.can_complete?
189
+ end
190
+
191
+ payment_session.complete! if payment_session.can_complete?
168
192
  end
169
193
 
170
- payment_session.process! if payment_session.can_process?
171
- payment = payment_session.find_or_create_payment!
172
-
173
- if payment.present? && !payment.completed?
174
- payment.started_processing! if payment.checkout?
175
- payment.complete! if payment.can_complete?
176
- end
177
-
178
- payment_session.complete! if payment_session.can_complete?
179
-
180
194
  rescue StandardError => e
181
195
  Rails.logger.error("Razorpay 5.4 API Completion Failed: #{e.message}")
182
196
  payment_session.fail! if payment_session.can_fail?
@@ -240,7 +254,7 @@ module Spree
240
254
  end
241
255
  end
242
256
 
243
- def resolve_razorpay_payment_id(response_code)
257
+ def resolve_razorpay_payment_id(response_code)
244
258
  return nil if response_code.blank?
245
259
 
246
260
  if response_code.to_s.start_with?('order_')
@@ -301,4 +315,4 @@ def resolve_razorpay_payment_id(response_code)
301
315
  void(response_code)
302
316
  end
303
317
  end
304
- end
318
+ end
@@ -9,6 +9,45 @@ module Spree
9
9
  def razorpay_order_id
10
10
  external_id
11
11
  end
12
+
13
+ # Required for Headless API V3 to properly create the source and prevent double-charges
14
+ def find_or_create_payment!(metadata = {})
15
+ return unless persisted?
16
+ return payment if payment.present?
17
+
18
+ # 1. Lock the order to prevent race conditions from Webhooks
19
+ order.with_lock do
20
+ rzp_payment_id = external_data['razorpay_payment_id']
21
+
22
+ # 2. Check if the webhook already created this payment
23
+ existing_payment = order.payments.where(
24
+ payment_method: payment_method,
25
+ response_code: rzp_payment_id || external_id
26
+ ).first
27
+
28
+ return existing_payment if existing_payment.present?
29
+
30
+ # 3. Create your custom RazorpayCheckout source record for Headless!
31
+ source = ::Spree::RazorpayCheckout.create!(
32
+ order_id: order.id,
33
+ razorpay_payment_id: rzp_payment_id,
34
+ razorpay_order_id: external_id,
35
+ razorpay_signature: external_data['razorpay_signature'],
36
+ status: 'captured',
37
+ payment_method: payment_method.name
38
+ )
39
+
40
+ # 4. Create the actual Spree::Payment
41
+ order.payments.create!(
42
+ payment_method: payment_method,
43
+ amount: amount,
44
+ response_code: rzp_payment_id || external_id,
45
+ source: source,
46
+ skip_source_requirement: true
47
+ )
48
+ end
49
+ end
50
+
12
51
  end
13
52
  end
14
- end
53
+ end
@@ -47,7 +47,7 @@
47
47
  <h6 class="font-weight-bold text-dark mb-2" style="font-size: 0.95rem;">Next.js Storefront</h6>
48
48
 
49
49
  <div class="input-group bg-gray-25 border border-gray-100 mb-3 d-flex align-items-center rounded" data-controller="clipboard" data-clipboard-success-content-value="Copied!">
50
- <input type="text" readonly value="<%= base_url %>/api/v3/webhooks/payments/<%= @payment_method.id %>" class="text-gray-600 py-2 grow pl-3 border-0 bg-transparent shadow-none" style="font-family: monospace; font-size: 0.85rem; outline: none; min-width: 0;" data-clipboard-target="source">
50
+ <input type="text" readonly value="<%= base_url %>/api/v3/webhooks/payments/<%= @payment_method.prefixed_id %>" class="text-gray-600 py-2 grow pl-3 border-0 bg-transparent shadow-none" style="font-family: monospace; font-size: 0.85rem; outline: none; min-width: 0;" data-clipboard-target="source">
51
51
  <button type="button" class="btn btn-sm btn-light mr-1 d-flex align-items-center justify-content-center p-1" title="Copy to clipboard" data-action="clipboard#copy" data-clipboard-target="button">
52
52
  <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none" viewBox="0 0 24 24" class="text-muted">
53
53
  <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 4h3a1 1 0 0 1 1 1v15a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h3m0 3h6m-6 5h6m-6 4h6M10 3v4h4V3h-4Z"/>
@@ -1,5 +1,5 @@
1
1
  module SpreeRazorpayCheckout
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '0.3.1'.freeze
3
3
 
4
4
  module_function
5
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_razorpay_checkout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Umesh Ravani