Class: SpreeAdyen::Gateway
- Inherits:
-
Spree::Gateway
- Object
- Spree::Gateway
- SpreeAdyen::Gateway
show all
- Includes:
- PaymentSessions
- Defined in:
- app/models/spree_adyen/gateway.rb,
app/models/spree_adyen/gateway/payment_sessions.rb
Defined Under Namespace
Modules: PaymentSessions
Constant Summary
collapse
- CAPTURE_PSP_REFERENCE_METAFIELD_KEY =
'adyen.capture_psp_reference'.freeze
- CANCELLATION_PSP_REFERENCE_METAFIELD_KEY =
'adyen.cancellation_psp_reference'.freeze
Instance Method Summary
collapse
-
#add_allowed_origin(domain) ⇒ Object
-
#apple_domain_association_file_content ⇒ Object
-
#authorize(amount_in_cents, payment_source, gateway_options = {}) ⇒ Object
-
#cancel(id, payment) ⇒ Object
-
#capture(amount_in_cents, response_code, _gateway_options = {}) ⇒ Object
This only checks if the capture was successful by checking the presence of the capture PSP reference The actual capture is requested in #request_capture and handled in the SpreeAdyen::Webhooks::EventProcessors::CaptureEventProcessor.
-
#configuration_guide_partial_name ⇒ Object
-
#create_adyen_session(amount, order, channel, return_url) ⇒ Spree::PaymentResponse
Creates an Adyen session via the Adyen Sessions API.
-
#create_profile(payment) ⇒ Object
-
#credit(amount_in_cents, _source, payment_id, gateway_options = {}) ⇒ Object
-
#custom_form_fields_partial_name ⇒ Object
-
#default_name ⇒ Object
-
#description_partial_name ⇒ Object
-
#environment ⇒ Object
-
#gateway_dashboard_payment_url(payment) ⇒ Object
-
#generate_client_key ⇒ Object
-
#generate_hmac_key ⇒ Object
-
#get_api_credential_details ⇒ Object
-
#handle_authorize_or_purchase(amount_in_cents, payment_source, gateway_options = {}) ⇒ Object
-
#method_type ⇒ Object
-
#parse_webhook_event(raw_body, headers) ⇒ Object
-
#payment_icon_name ⇒ Object
-
#payment_profiles_supported? ⇒ Boolean
this is used by spree to determine whenever payment source must be passed to gateway methods.
-
#payment_session_result(payment_session_id, session_result) ⇒ Object
-
#provider_class ⇒ Object
-
#purchase(amount_in_cents, payment_source, gateway_options = {}) ⇒ Object
-
#request_capture(amount_in_cents, response_code, _gateway_options = {}) ⇒ Object
-
#request_void(response_code, _source, _gateway_options) ⇒ Object
-
#reusable_sources(order) ⇒ Object
-
#set_up_webhook(url) ⇒ Object
-
#test_webhook ⇒ Object
-
#void(response_code, _source, _gateway_options) ⇒ Object
This only checks if the void was successful by checking the presence of the cancellation PSP reference The actual void is requested in #request_void and handled in the SpreeAdyen::Webhooks::EventProcessors::CancellationEventProcessor.
-
#webhook_url ⇒ Object
#complete_payment_session, #create_payment_session, #payment_session_class, #session_required?, #update_payment_session
Instance Method Details
#add_allowed_origin(domain) ⇒ Object
364
365
366
367
368
369
370
371
372
373
374
|
# File 'app/models/spree_adyen/gateway.rb', line 364
def add_allowed_origin(domain)
response = client.management.my_api_credential_api.add_allowed_origin({ domain: domain })
if response.status.to_i == 200
success(response.response.id, response.response)
else
failure(response.response)
end
rescue Adyen::AdyenError => e
failure(parse_adyen_error_response(e))
end
|
#apple_domain_association_file_content ⇒ Object
426
427
428
|
# File 'app/models/spree_adyen/gateway.rb', line 426
def apple_domain_association_file_content
@apple_domain_association_file_content ||= apple_developer_merchantid_domain_association&.download
end
|
#authorize(amount_in_cents, payment_source, gateway_options = {}) ⇒ Object
55
56
57
|
# File 'app/models/spree_adyen/gateway.rb', line 55
def authorize(amount_in_cents, payment_source, gateway_options = {})
handle_authorize_or_purchase(amount_in_cents, payment_source, gateway_options)
end
|
#cancel(id, payment) ⇒ Object
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
# File 'app/models/spree_adyen/gateway.rb', line 79
def cancel(id, payment)
transaction_id = id
payment ||= Spree::Payment.find_by(response_code: id)
if payment.completed?
amount = payment.credit_allowed
return success(transaction_id, {}) if amount.zero?
return success(transaction_id, {}) if payment.respond_to?(:for_shipment?) && payment.for_shipment?
refund = payment.refunds.create!(
amount: amount,
reason: Spree::RefundReason.order_canceled_reason,
refunder_id: payment.order.canceler_id
)
success(transaction_id, refund.response.params)
else
payment.void!
success(transaction_id, {})
end
end
|
#capture(amount_in_cents, response_code, _gateway_options = {}) ⇒ Object
This only checks if the capture was successful by checking the presence of the capture PSP reference The actual capture is requested in #request_capture and handled in the SpreeAdyen::Webhooks::EventProcessors::CaptureEventProcessor
158
159
160
161
162
163
164
165
166
|
# File 'app/models/spree_adyen/gateway.rb', line 158
def capture(amount_in_cents, response_code, _gateway_options = {})
payment = Spree::Payment.find_by(response_code: response_code)
return failure("#{response_code} - Payment not found") if payment.blank?
return failure("#{response_code} - Payment is already captured") if payment.completed?
return failure("#{response_code} - Capture PSP reference not found") unless payment.has_metafield?(CAPTURE_PSP_REFERENCE_METAFIELD_KEY)
success(payment.response_code, {})
end
|
#configuration_guide_partial_name ⇒ Object
326
327
328
|
# File 'app/models/spree_adyen/gateway.rb', line 326
def configuration_guide_partial_name
'spree_adyen'
end
|
#create_adyen_session(amount, order, channel, return_url) ⇒ Spree::PaymentResponse
Creates an Adyen session via the Adyen Sessions API. Used internally by the v3 PaymentSessions module and by the legacy SpreeAdyen::PaymentSession model.
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
# File 'app/models/spree_adyen/gateway.rb', line 281
def create_adyen_session(amount, order, channel, return_url)
payload = SpreeAdyen::PaymentSessions::RequestPayloadPresenter.new(
order: order,
amount: amount,
user: order.user,
merchant_account: preferred_merchant_account,
payment_method: self,
channel: channel,
return_url: return_url
).to_h
response = send_request do
client.checkout.payments_api.sessions(payload, headers: { 'Idempotency-Key' => SecureRandom.uuid })
end
response_body = response.response
if response.status.to_i == 201
success(response_body.id, response_body)
else
failure(response_body.slice('pspReference', 'message').values.join(' - '))
end
end
|
#create_profile(payment) ⇒ Object
258
|
# File 'app/models/spree_adyen/gateway.rb', line 258
def create_profile(payment); end
|
#credit(amount_in_cents, _source, payment_id, gateway_options = {}) ⇒ Object
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# File 'app/models/spree_adyen/gateway.rb', line 104
def credit(amount_in_cents, _source, payment_id, gateway_options = {})
refund = gateway_options[:originator]
payment = refund.present? ? refund.payment : Spree::Payment.find_by(response_code: payment_id)
return failure("#{payment_id} - Payment not found") unless payment
payload = SpreeAdyen::RefundPayloadPresenter.new(
payment: payment,
amount_in_cents: amount_in_cents,
payment_method: self,
currency: payment.currency,
refund: refund
).to_h
response = send_request do
client.checkout.modifications_api.refund_captured_payment(payload, payment.transaction_id, headers: { 'Idempotency-Key' => SecureRandom.uuid })
end
if response.status.to_i == 201
success(response.response['pspReference'], response)
else
failure(response.response.slice('pspReference', 'message').values.join(' - '))
end
end
|
330
331
332
|
# File 'app/models/spree_adyen/gateway.rb', line 330
def custom_form_fields_partial_name
'spree_adyen'
end
|
#default_name ⇒ Object
310
311
312
|
# File 'app/models/spree_adyen/gateway.rb', line 310
def default_name
'Adyen'
end
|
#description_partial_name ⇒ Object
322
323
324
|
# File 'app/models/spree_adyen/gateway.rb', line 322
def description_partial_name
'spree_adyen'
end
|
#environment ⇒ Object
250
251
252
253
254
255
256
|
# File 'app/models/spree_adyen/gateway.rb', line 250
def environment
if preferred_test_mode
:test
else
:live
end
end
|
#gateway_dashboard_payment_url(payment) ⇒ Object
334
335
336
337
338
|
# File 'app/models/spree_adyen/gateway.rb', line 334
def gateway_dashboard_payment_url(payment)
return if payment.transaction_id.blank?
"https://ca-#{environment}.adyen.com/ca/ca/accounts/showTx.shtml?pspReference=#{payment.transaction_id}&txType=Payment"
end
|
#generate_client_key ⇒ Object
414
415
416
417
418
419
420
421
422
423
424
|
# File 'app/models/spree_adyen/gateway.rb', line 414
def generate_client_key
response = client.management.my_api_credential_api.generate_client_key
if response.status.to_i == 200
success(response.response.clientKey, response.response)
else
failure(response.response.message)
end
rescue Adyen::AdyenError => e
failure(parse_adyen_error_response(e)['message'])
end
|
#generate_hmac_key ⇒ Object
402
403
404
405
406
407
408
409
410
411
412
|
# File 'app/models/spree_adyen/gateway.rb', line 402
def generate_hmac_key
response = client.management.webhooks_merchant_level_api.generate_hmac_key(preferred_merchant_account, preferred_webhook_id)
if response.status.to_i == 200
success(response.response.hmacKey, response.response)
else
failure(response.response)
end
rescue Adyen::AdyenError => e
failure(parse_adyen_error_response(e)['message'])
end
|
#get_api_credential_details ⇒ Object
350
351
352
353
354
355
356
357
358
359
360
361
362
|
# File 'app/models/spree_adyen/gateway.rb', line 350
def get_api_credential_details
response = client.management.my_api_credential_api.get_api_credential_details
if response.status.to_i == 200
success(response.response.id, response.response)
else
failure(response.response.message)
end
rescue Adyen::AuthenticationError, Adyen::PermissionError
raise
rescue Adyen::AdyenError => e
failure(parse_adyen_error_response(e)['message'])
end
|
#handle_authorize_or_purchase(amount_in_cents, payment_source, gateway_options = {}) ⇒ Object
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
# File 'app/models/spree_adyen/gateway.rb', line 59
def handle_authorize_or_purchase(amount_in_cents, payment_source, gateway_options = {})
payload = SpreeAdyen::Payments::RequestPayloadPresenter.new(
source: payment_source,
amount_in_cents: amount_in_cents,
manual_capture: !auto_capture?,
gateway_options: gateway_options
).to_h
response = send_request do
client.checkout.payments_api.payments(payload, headers: { 'Idempotency-Key' => SecureRandom.uuid })
end
response_body = response.response
if response.status.to_i == 200
success(response_body.pspReference, response_body)
else
failure(response_body.slice('pspReference', 'message').values.join(' - '))
end
end
|
#method_type ⇒ Object
314
315
316
|
# File 'app/models/spree_adyen/gateway.rb', line 314
def method_type
'spree_adyen'
end
|
#parse_webhook_event(raw_body, headers) ⇒ Object
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
# File 'app/models/spree_adyen/gateway.rb', line 217
def parse_webhook_event(raw_body, )
payload = JSON.parse(raw_body).with_indifferent_access
event = SpreeAdyen::Webhooks::Event.new(event_data: payload)
webhook_request_item = payload.dig('notificationItems', 0, 'NotificationRequestItem') || {}
unless valid_hmac?(webhook_request_item)
raise Spree::PaymentMethod::WebhookSignatureError, 'Invalid HMAC signature'
end
payment_session = event.session_id.present? ?
Spree::PaymentSessions::Adyen.find_by(payment_method: self, external_id: event.session_id) : nil
return nil unless payment_session
case event.code
when 'AUTHORISATION'
action = event.success? ? :authorized : :failed
{ action: action, payment_session: payment_session, metadata: { adyen_event: event } }
when 'CAPTURE'
{ action: :captured, payment_session: payment_session, metadata: { adyen_event: event } }
when 'CANCELLATION'
{ action: :canceled, payment_session: payment_session, metadata: { adyen_event: event } }
else
nil
end
end
|
#payment_icon_name ⇒ Object
318
319
320
|
# File 'app/models/spree_adyen/gateway.rb', line 318
def payment_icon_name
'adyen'
end
|
#payment_profiles_supported? ⇒ Boolean
this is used by spree to determine whenever payment source must be passed to gateway methods
306
307
308
|
# File 'app/models/spree_adyen/gateway.rb', line 306
def payment_profiles_supported?
true
end
|
#payment_session_result(payment_session_id, session_result) ⇒ Object
260
261
262
263
264
265
266
267
268
269
270
271
|
# File 'app/models/spree_adyen/gateway.rb', line 260
def payment_session_result(payment_session_id, session_result)
response = send_request do
client.checkout.payments_api.get_result_of_payment_session(payment_session_id, query_params: { sessionResult: session_result })
end
response_body = response.response
if response.status.to_i == 200
success(response_body.id, response_body)
else
failure(response_body.slice('pspReference', 'message').values.join(' - '))
end
end
|
#provider_class ⇒ Object
246
247
248
|
# File 'app/models/spree_adyen/gateway.rb', line 246
def provider_class
self.class
end
|
#purchase(amount_in_cents, payment_source, gateway_options = {}) ⇒ Object
48
49
50
|
# File 'app/models/spree_adyen/gateway.rb', line 48
def purchase(amount_in_cents, payment_source, gateway_options = {})
handle_authorize_or_purchase(amount_in_cents, payment_source, gateway_options)
end
|
#request_capture(amount_in_cents, response_code, _gateway_options = {}) ⇒ Object
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# File 'app/models/spree_adyen/gateway.rb', line 129
def request_capture(amount_in_cents, response_code, _gateway_options = {})
payment = Spree::Payment.find_by(response_code: response_code)
return failure("#{response_code} - Payment not found") if payment.blank?
return failure("#{response_code} - Payment is already captured") if payment.completed?
payload = SpreeAdyen::CapturePayloadPresenter.new(
amount_in_cents: amount_in_cents,
payment: payment,
payment_method: self
).to_h
response = send_request do
client.checkout.modifications_api.capture_authorised_payment(
payload,
payment.response_code,
headers: { 'Idempotency-Key' => SecureRandom.uuid }
)
end
if response.status.to_i == 201
success(response.response['paymentPspReference'], response)
else
failure(response.response.slice('paymentPspReference', 'message').values.join(' - '))
end
end
|
#request_void(response_code, _source, _gateway_options) ⇒ Object
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
# File 'app/models/spree_adyen/gateway.rb', line 168
def request_void(response_code, _source, _gateway_options)
payment = Spree::Payment.find_by(response_code: response_code)
return failure("#{response_code} - Payment not found") if payment.blank?
return failure("#{response_code} - Payment is already void") if payment.void?
payload = SpreeAdyen::CancelPayloadPresenter.new(
payment: payment,
payment_method: self
).to_h
response = send_request do
client.checkout.modifications_api.cancel_authorised_payment_by_psp_reference(
payload,
payment.response_code,
headers: { 'Idempotency-Key' => SecureRandom.uuid }
)
end
if response.status.to_i == 201
success(response.response['paymentPspReference'], response)
else
failure(response.response.slice('paymentPspReference', 'message').values.join(' - '))
end
end
|
#reusable_sources(order) ⇒ Object
340
341
342
343
344
345
346
347
348
|
# File 'app/models/spree_adyen/gateway.rb', line 340
def reusable_sources(order)
if order.completed?
sources_by_order order
elsif order.user.present?
credit_cards.where(user_id: order.user_id)
else
[]
end
end
|
#set_up_webhook(url) ⇒ Object
376
377
378
379
380
381
382
383
384
385
386
387
|
# File 'app/models/spree_adyen/gateway.rb', line 376
def set_up_webhook(url)
payload = SpreeAdyen::WebhookPayloadPresenter.new(url).to_h
response = client.management.webhooks_merchant_level_api.set_up_webhook(payload, preferred_merchant_account)
if response.status.to_i == 200
success(response.response.id, response.response)
else
failure(response.response)
end
rescue Adyen::AdyenError => e
failure(parse_adyen_error_response(e)['message'])
end
|
#test_webhook ⇒ Object
389
390
391
392
393
394
395
396
397
398
399
400
|
# File 'app/models/spree_adyen/gateway.rb', line 389
def test_webhook
response = client.management.webhooks_merchant_level_api.test_webhook({ types: ['AUTHORISATION'] }, preferred_merchant_account,
preferred_webhook_id)
if response.status.to_i == 200 && response.response.dig('data', 0, 'status') == 'success'
success(nil, response.response)
else
failure(response.response)
end
rescue Adyen::AdyenError => e
failure(parse_adyen_error_response(e)['message'])
end
|
#void(response_code, _source, _gateway_options) ⇒ Object
This only checks if the void was successful by checking the presence of the cancellation PSP reference The actual void is requested in #request_void and handled in the SpreeAdyen::Webhooks::EventProcessors::CancellationEventProcessor
196
197
198
199
200
201
202
203
204
|
# File 'app/models/spree_adyen/gateway.rb', line 196
def void(response_code, _source, _gateway_options)
payment = Spree::Payment.find_by(response_code: response_code)
return failure("#{response_code} - Payment not found") if payment.blank?
return failure("#{response_code} - Payment is already void") if payment.void?
return failure("#{response_code} - Cancellation PSP reference not found") unless payment.has_metafield?(CANCELLATION_PSP_REFERENCE_METAFIELD_KEY)
success(payment.response_code, {})
end
|
#webhook_url ⇒ Object
206
207
208
209
210
211
212
213
214
215
|
# File 'app/models/spree_adyen/gateway.rb', line 206
def webhook_url
store = stores.first
return nil unless store
if SpreeAdyen::Config[:use_legacy_webhook_handlers]
"#{store.formatted_url}/adyen/webhooks"
else
"#{store.formatted_url}/api/v3/webhooks/payments/#{prefixed_id}"
end
end
|