spree_razorpay_checkout 0.3.0 → 0.3.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 +4 -4
- data/app/controllers/spree/razorpay/_webhooks_controller.rb +78 -0
- data/app/models/spree/gateway/razorpay_gateway.rb +79 -25
- data/app/models/spree/payment_sessions/razorpay.rb +37 -1
- data/app/views/spree/admin/payment_methods/configuration_guides/_razorpay.html.erb +1 -1
- data/config/routes.rb +3 -6
- data/lib/spree_razorpay_checkout/version.rb +1 -1
- metadata +3 -3
- data/app/controllers/spree/razorpay/webhooks_controller.rb +0 -72
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 59ea8bc12e162b79eacdbefce1a1ee167cd9a4d4e7c2cd7cd3bd53ce47a8d716
|
|
4
|
+
data.tar.gz: a4b9a022d525bb254c0b932f415ebedf63dbfc4aac3be42d648546163b149d87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc7bedce60a230b32703ff7e8613153f9eee91eee5554b51c42e7de2aa235799038825b5b103eddd4948e26e9ac8a13850d2353e1d240b514b839dd58c686fc2
|
|
7
|
+
data.tar.gz: eb72bd494b0f178939f8ad4463281ec3bb793f8bf6ef0bb0c751b8d1fa2c976ec1b42b1a9a81b774fff1680c411b783f2a2c31327f679c1d842a35dd63ce6bc1
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
class RazorpayWebhooksController < ActionController::API
|
|
3
|
+
skip_before_action :verify_authenticity_token, raise: false
|
|
4
|
+
|
|
5
|
+
# Handles asynchronous background webhooks directly from Razorpay's servers
|
|
6
|
+
def create
|
|
7
|
+
payload = request.body.read
|
|
8
|
+
signature = request.headers['X-Razorpay-Signature'] || request.headers['HTTP_X_RAZORPAY_SIGNATURE']
|
|
9
|
+
|
|
10
|
+
gateway = Spree::Gateway::RazorpayGateway.active.first
|
|
11
|
+
return head :not_found unless gateway && gateway.preferred_webhook_secret.present?
|
|
12
|
+
|
|
13
|
+
begin
|
|
14
|
+
# 1. Use the gateway's parser to verify signature and map the action
|
|
15
|
+
parsed_event = gateway.parse_webhook_event(payload, { 'HTTP_X_RAZORPAY_SIGNATURE' => signature })
|
|
16
|
+
|
|
17
|
+
# If it's an event we don't care about, acknowledge and return
|
|
18
|
+
return head :ok unless parsed_event
|
|
19
|
+
|
|
20
|
+
# 2. Extract Data
|
|
21
|
+
payment_session = parsed_event[:payment_session]
|
|
22
|
+
action = parsed_event[:action]
|
|
23
|
+
|
|
24
|
+
event_data = JSON.parse(payload)
|
|
25
|
+
metadata = event_data.dig('payload', 'payment', 'entity') || {}
|
|
26
|
+
|
|
27
|
+
# 3. Trigger the Core Spree 5.5 Webhook Handler Service
|
|
28
|
+
Spree::Payments::HandleWebhook.call(
|
|
29
|
+
payment_method: gateway,
|
|
30
|
+
action: action,
|
|
31
|
+
payment_session: payment_session,
|
|
32
|
+
metadata: metadata
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
rescue Spree::PaymentMethod::WebhookSignatureError => e
|
|
36
|
+
Rails.logger.error("Razorpay Webhook Verification Failed: #{e.message}")
|
|
37
|
+
return head :unauthorized
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
Rails.logger.error("Razorpay Webhook Processing Error: #{e.message}")
|
|
40
|
+
return head :unprocessable_entity
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
head :ok
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Handles synchronous frontend verification from Next.js Storefront
|
|
47
|
+
def verify
|
|
48
|
+
razorpay_order_id = params[:razorpay_order_id]
|
|
49
|
+
razorpay_payment_id = params[:razorpay_payment_id]
|
|
50
|
+
razorpay_signature = params[:razorpay_signature]
|
|
51
|
+
|
|
52
|
+
session = Spree::PaymentSession.find_by(external_id: razorpay_order_id)
|
|
53
|
+
return head :not_found unless session
|
|
54
|
+
|
|
55
|
+
gateway = Spree::Gateway::RazorpayGateway.active.first
|
|
56
|
+
return render json: { success: false, error: 'Gateway not configured' }, status: :internal_server_error unless gateway
|
|
57
|
+
gateway.provider
|
|
58
|
+
|
|
59
|
+
begin
|
|
60
|
+
::Razorpay::Utility.verify_payment_signature(
|
|
61
|
+
razorpay_order_id: razorpay_order_id,
|
|
62
|
+
razorpay_payment_id: razorpay_payment_id,
|
|
63
|
+
razorpay_signature: razorpay_signature
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
session.external_data ||= {}
|
|
67
|
+
session.external_data['razorpay_payment_id'] = razorpay_payment_id
|
|
68
|
+
session.external_data['razorpay_signature'] = razorpay_signature
|
|
69
|
+
session.save!
|
|
70
|
+
|
|
71
|
+
render json: { success: true }
|
|
72
|
+
rescue ::Razorpay::Errors::SignatureVerificationError => e
|
|
73
|
+
Rails.logger.error("Razorpay Frontend Verification Failed: #{e.message}")
|
|
74
|
+
render json: { success: false, error: e.message }, status: :unprocessable_entity
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -14,6 +14,9 @@ module Spree
|
|
|
14
14
|
preference :merchant_address, :string, default: 'Razorpay, Bangalore, India'
|
|
15
15
|
preference :theme_color, :string, default: '#2e5bff'
|
|
16
16
|
preference :headless_api_mode, :boolean, default: false
|
|
17
|
+
|
|
18
|
+
# NEW: Allow manual capture vs auto-capture choice from Spree Admin Panel
|
|
19
|
+
preference :auto_capture, :boolean, default: true
|
|
17
20
|
|
|
18
21
|
def name
|
|
19
22
|
'Razorpay Secure (UPI, Wallets, Cards & Netbanking)'
|
|
@@ -52,7 +55,7 @@ module Spree
|
|
|
52
55
|
end
|
|
53
56
|
|
|
54
57
|
def auto_capture?
|
|
55
|
-
|
|
58
|
+
preferred_auto_capture
|
|
56
59
|
end
|
|
57
60
|
|
|
58
61
|
def request_type
|
|
@@ -95,7 +98,9 @@ module Spree
|
|
|
95
98
|
Spree::PaymentSessions::Razorpay if defined?(Spree::PaymentSession)
|
|
96
99
|
end
|
|
97
100
|
|
|
101
|
+
# =========================================================================
|
|
98
102
|
# SPREE 5.4+ HEADLESS API FLOW (Protected by defined? check)
|
|
103
|
+
# =========================================================================
|
|
99
104
|
|
|
100
105
|
if defined?(Spree::PaymentSession)
|
|
101
106
|
def create_payment_session(order:, amount: nil, external_data: {})
|
|
@@ -107,7 +112,7 @@ module Spree
|
|
|
107
112
|
amount: amount_in_cents,
|
|
108
113
|
currency: order.currency || 'INR',
|
|
109
114
|
receipt: order.number,
|
|
110
|
-
payment_capture: 1,
|
|
115
|
+
payment_capture: auto_capture? ? 1 : 0, # UPDATED: Respects Manual Capture
|
|
111
116
|
notes: { spree_order_number: order.number, email: order.email }
|
|
112
117
|
)
|
|
113
118
|
|
|
@@ -140,7 +145,7 @@ module Spree
|
|
|
140
145
|
amount: amount_in_cents,
|
|
141
146
|
currency: payment_session.currency,
|
|
142
147
|
receipt: payment_session.order.number,
|
|
143
|
-
payment_capture: 1
|
|
148
|
+
payment_capture: auto_capture? ? 1 : 0 # UPDATED: Respects Manual Capture
|
|
144
149
|
)
|
|
145
150
|
|
|
146
151
|
payment_session.update!(amount: amount, external_id: new_rzp_order.id)
|
|
@@ -151,34 +156,60 @@ module Spree
|
|
|
151
156
|
def complete_payment_session(payment_session:, params: {})
|
|
152
157
|
provider
|
|
153
158
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
159
|
+
# Robustly parse the JSON string sent from Next.js via the Spree API
|
|
160
|
+
result_data = {}
|
|
161
|
+
if params[:session_result].present?
|
|
162
|
+
begin
|
|
163
|
+
result_data = params[:session_result].is_a?(String) ? JSON.parse(params[:session_result]) : params[:session_result]
|
|
164
|
+
rescue JSON::ParserError
|
|
165
|
+
result_data = {}
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
rzp_payment_id = result_data['razorpay_payment_id'] || result_data[:razorpay_payment_id] || payment_session.external_data['razorpay_payment_id']
|
|
170
|
+
rzp_signature = result_data['razorpay_signature'] || result_data[:razorpay_signature] || payment_session.external_data['razorpay_signature']
|
|
157
171
|
|
|
158
172
|
begin
|
|
173
|
+
# Verify the Signature
|
|
159
174
|
::Razorpay::Utility.verify_payment_signature(
|
|
160
175
|
razorpay_order_id: payment_session.external_id,
|
|
161
176
|
razorpay_payment_id: rzp_payment_id,
|
|
162
177
|
razorpay_signature: rzp_signature
|
|
163
178
|
)
|
|
164
179
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
payment
|
|
175
|
-
|
|
180
|
+
# Lock the order database row to prevent race conditions with Webhooks
|
|
181
|
+
payment_session.order.with_lock do
|
|
182
|
+
|
|
183
|
+
# Save the verified IDs into the session
|
|
184
|
+
session_data = payment_session.external_data || {}
|
|
185
|
+
session_data['razorpay_payment_id'] = rzp_payment_id
|
|
186
|
+
session_data['razorpay_signature'] = rzp_signature
|
|
187
|
+
payment_session.update!(external_data: session_data)
|
|
188
|
+
|
|
189
|
+
# Fetch payment status directly from Razorpay for instant frontend resolution
|
|
190
|
+
rzp_payment = ::Razorpay::Payment.fetch(rzp_payment_id)
|
|
191
|
+
|
|
192
|
+
# Process and Create Payment
|
|
193
|
+
payment_session.process! if payment_session.can_process?
|
|
194
|
+
|
|
195
|
+
payment = payment_session.find_or_create_payment!
|
|
196
|
+
|
|
197
|
+
if payment.present? && !payment.completed?
|
|
198
|
+
payment.started_processing! if payment.checkout?
|
|
199
|
+
|
|
200
|
+
# SYNCHRONOUS FIX: Immediately transition payment state so Next.js can complete the order
|
|
201
|
+
if rzp_payment.status == 'captured'
|
|
202
|
+
payment.complete! if payment.can_complete?
|
|
203
|
+
elsif rzp_payment.status == 'authorized'
|
|
204
|
+
payment.pend! if payment.can_pend?
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
payment_session.complete! if payment_session.can_complete?
|
|
176
209
|
end
|
|
177
210
|
|
|
178
|
-
payment_session.complete! if payment_session.can_complete?
|
|
179
|
-
|
|
180
211
|
rescue StandardError => e
|
|
181
|
-
Rails.logger.error("Razorpay 5.4 API Completion Failed: #{e.message}")
|
|
212
|
+
Rails.logger.error("Razorpay 5.4+ API Completion Failed: #{e.message}")
|
|
182
213
|
payment_session.fail! if payment_session.can_fail?
|
|
183
214
|
raise Spree::Core::GatewayError, e.message
|
|
184
215
|
end
|
|
@@ -198,9 +229,12 @@ module Spree
|
|
|
198
229
|
session = Spree::PaymentSession.find_by(external_id: payment_entity['order_id'])
|
|
199
230
|
return nil unless session
|
|
200
231
|
|
|
232
|
+
# UPDATED: Split authorized vs captured to align with new Spree webhook architecture
|
|
201
233
|
case event['event']
|
|
202
|
-
when 'payment.captured', '
|
|
234
|
+
when 'payment.captured', 'order.paid'
|
|
203
235
|
{ action: :captured, payment_session: session }
|
|
236
|
+
when 'payment.authorized'
|
|
237
|
+
{ action: :authorized, payment_session: session }
|
|
204
238
|
when 'payment.failed'
|
|
205
239
|
{ action: :failed, payment_session: session }
|
|
206
240
|
else
|
|
@@ -211,6 +245,10 @@ module Spree
|
|
|
211
245
|
end
|
|
212
246
|
end
|
|
213
247
|
|
|
248
|
+
# =========================================================================
|
|
249
|
+
# LEGACY / ACTIVEMERCHANT FLOW
|
|
250
|
+
# =========================================================================
|
|
251
|
+
|
|
214
252
|
def purchase(_amount, source, _gateway_options = {})
|
|
215
253
|
provider
|
|
216
254
|
|
|
@@ -240,7 +278,7 @@ module Spree
|
|
|
240
278
|
end
|
|
241
279
|
end
|
|
242
280
|
|
|
243
|
-
def resolve_razorpay_payment_id(response_code)
|
|
281
|
+
def resolve_razorpay_payment_id(response_code)
|
|
244
282
|
return nil if response_code.blank?
|
|
245
283
|
|
|
246
284
|
if response_code.to_s.start_with?('order_')
|
|
@@ -257,8 +295,24 @@ def resolve_razorpay_payment_id(response_code)
|
|
|
257
295
|
end
|
|
258
296
|
end
|
|
259
297
|
|
|
260
|
-
|
|
261
|
-
|
|
298
|
+
# UPDATED: Fully implemented Capture method so you can click "Capture" inside Spree Admin
|
|
299
|
+
def capture(amount_in_cents, response_code, gateway_options = {})
|
|
300
|
+
provider
|
|
301
|
+
begin
|
|
302
|
+
rzp_payment_id = resolve_razorpay_payment_id(response_code)
|
|
303
|
+
|
|
304
|
+
raise StandardError, "Missing Razorpay Payment ID." if rzp_payment_id.blank?
|
|
305
|
+
|
|
306
|
+
rzp_payment = ::Razorpay::Payment.fetch(rzp_payment_id)
|
|
307
|
+
if rzp_payment.status == 'authorized'
|
|
308
|
+
rzp_payment.capture({ amount: amount_in_cents, currency: gateway_options[:currency] || 'INR' })
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
ActiveMerchant::Billing::Response.new(true, 'Razorpay Capture Successful', {}, test: preferred_test_mode, authorization: rzp_payment_id)
|
|
312
|
+
rescue StandardError => e
|
|
313
|
+
Rails.logger.error("Razorpay Capture Failed: #{e.message}")
|
|
314
|
+
ActiveMerchant::Billing::Response.new(false, "Capture failed: #{e.message}", {}, test: preferred_test_mode)
|
|
315
|
+
end
|
|
262
316
|
end
|
|
263
317
|
|
|
264
318
|
def credit(credit_cents, response_code, _gateway_options = {})
|
|
@@ -301,4 +355,4 @@ def resolve_razorpay_payment_id(response_code)
|
|
|
301
355
|
void(response_code)
|
|
302
356
|
end
|
|
303
357
|
end
|
|
304
|
-
end
|
|
358
|
+
end
|
|
@@ -9,6 +9,42 @@ module Spree
|
|
|
9
9
|
def razorpay_order_id
|
|
10
10
|
external_id
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
def find_or_create_payment!(metadata = {})
|
|
14
|
+
return unless persisted?
|
|
15
|
+
return payment if payment.present?
|
|
16
|
+
|
|
17
|
+
order.with_lock do
|
|
18
|
+
rzp_payment_id = external_data['razorpay_payment_id'] || metadata['id']
|
|
19
|
+
|
|
20
|
+
existing_payment = order.payments.where(
|
|
21
|
+
payment_method: payment_method,
|
|
22
|
+
response_code: rzp_payment_id || external_id
|
|
23
|
+
).first
|
|
24
|
+
|
|
25
|
+
return existing_payment if existing_payment.present?
|
|
26
|
+
|
|
27
|
+
rzp_status = metadata['status'] || 'pending'
|
|
28
|
+
|
|
29
|
+
source = ::Spree::RazorpayCheckout.create!(
|
|
30
|
+
order_id: order.id,
|
|
31
|
+
razorpay_payment_id: rzp_payment_id,
|
|
32
|
+
razorpay_order_id: external_id,
|
|
33
|
+
razorpay_signature: external_data['razorpay_signature'],
|
|
34
|
+
status: rzp_status,
|
|
35
|
+
payment_method: payment_method.name
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
order.payments.create!(
|
|
39
|
+
payment_method: payment_method,
|
|
40
|
+
amount: amount,
|
|
41
|
+
response_code: rzp_payment_id || external_id,
|
|
42
|
+
source: source,
|
|
43
|
+
skip_source_requirement: true
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
12
48
|
end
|
|
13
49
|
end
|
|
14
|
-
end
|
|
50
|
+
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.
|
|
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"/>
|
data/config/routes.rb
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
Spree::Core::Engine.add_routes do
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
post :verify, to: 'webhooks#verify'
|
|
6
|
-
end
|
|
7
|
-
end
|
|
2
|
+
post '/razorpay/webhooks', to: 'razorpay_webhooks#create'
|
|
3
|
+
post '/razorpay/verify', to: 'razorpay_webhooks#verify'
|
|
4
|
+
end
|
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.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Umesh Ravani
|
|
@@ -79,7 +79,7 @@ dependencies:
|
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
81
|
version: '0'
|
|
82
|
-
description: Seamless Razorpay checkout integration for Spree 5.
|
|
82
|
+
description: Seamless Razorpay checkout integration for Spree 5.5. Features include
|
|
83
83
|
Hotwire/Turbo compatibility, Zero Drop-off Webhook captures, native Spree Dashboard
|
|
84
84
|
refunds, and the Affordability Widget.
|
|
85
85
|
email:
|
|
@@ -95,7 +95,7 @@ files:
|
|
|
95
95
|
- app/assets/images/payment_icons/window_modal.svg
|
|
96
96
|
- app/controllers/concerns/spree/razor_pay.rb
|
|
97
97
|
- app/controllers/spree/products_controller_decorator.rb
|
|
98
|
-
- app/controllers/spree/razorpay/
|
|
98
|
+
- app/controllers/spree/razorpay/_webhooks_controller.rb
|
|
99
99
|
- app/controllers/spree/razorpay_controller.rb
|
|
100
100
|
- app/javascript/spree_razorpay/application.js
|
|
101
101
|
- app/javascript/spree_razorpay/controllers/checkout_razorpay_controller.js
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
module Spree
|
|
2
|
-
module Razorpay
|
|
3
|
-
class WebhooksController < ActionController::API
|
|
4
|
-
skip_before_action :verify_authenticity_token, raise: false
|
|
5
|
-
|
|
6
|
-
# Handles asynchronous background webhooks directly from Razorpay's servers
|
|
7
|
-
def create
|
|
8
|
-
payload = request.body.read
|
|
9
|
-
signature = request.headers['X-Razorpay-Signature']
|
|
10
|
-
|
|
11
|
-
gateway = Spree::Gateway::RazorpayGateway.active.first
|
|
12
|
-
return head :not_found unless gateway && gateway.preferred_webhook_secret.present?
|
|
13
|
-
|
|
14
|
-
begin
|
|
15
|
-
::Razorpay::Utility.verify_webhook_signature(
|
|
16
|
-
payload,
|
|
17
|
-
signature,
|
|
18
|
-
gateway.preferred_webhook_secret
|
|
19
|
-
)
|
|
20
|
-
rescue ::Razorpay::Errors::SignatureVerificationError => e
|
|
21
|
-
Rails.logger.error("Razorpay Webhook Verification Failed: #{e.message}")
|
|
22
|
-
return head :unauthorized
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
event = JSON.parse(payload)
|
|
26
|
-
|
|
27
|
-
# Listen for 'payment.authorized' which fires immediately after OTP!
|
|
28
|
-
if ['order.paid', 'payment.captured', 'payment.authorized'].include?(event['event'])
|
|
29
|
-
::SpreeRazorpayCheckout::HandleWebhookEventJob.perform_later(event)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
head :ok
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Handles synchronous frontend verification from Next.js Storefront
|
|
36
|
-
def verify
|
|
37
|
-
razorpay_order_id = params[:razorpay_order_id]
|
|
38
|
-
razorpay_payment_id = params[:razorpay_payment_id]
|
|
39
|
-
razorpay_signature = params[:razorpay_signature]
|
|
40
|
-
|
|
41
|
-
session = Spree::PaymentSession.find_by(external_id: razorpay_order_id)
|
|
42
|
-
return head :not_found unless session
|
|
43
|
-
|
|
44
|
-
# Initialize the Razorpay gem with your active API keys
|
|
45
|
-
gateway = Spree::Gateway::RazorpayGateway.active.first
|
|
46
|
-
return render json: { success: false, error: 'Gateway not configured' }, status: :internal_server_error unless gateway
|
|
47
|
-
gateway.provider
|
|
48
|
-
|
|
49
|
-
begin
|
|
50
|
-
# 1. Verify the signature securely on the server
|
|
51
|
-
::Razorpay::Utility.verify_payment_signature(
|
|
52
|
-
razorpay_order_id: razorpay_order_id,
|
|
53
|
-
razorpay_payment_id: razorpay_payment_id,
|
|
54
|
-
razorpay_signature: razorpay_signature
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
# 2. Inject the signatures into the session's external_data
|
|
58
|
-
session.external_data ||= {}
|
|
59
|
-
session.external_data['razorpay_payment_id'] = razorpay_payment_id
|
|
60
|
-
session.external_data['razorpay_signature'] = razorpay_signature
|
|
61
|
-
session.save!
|
|
62
|
-
|
|
63
|
-
render json: { success: true }
|
|
64
|
-
rescue ::Razorpay::Errors::SignatureVerificationError => e
|
|
65
|
-
Rails.logger.error("Razorpay Frontend Verification Failed: #{e.message}")
|
|
66
|
-
render json: { success: false, error: e.message }, status: :unprocessable_entity
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|