1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2019 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Model;
use \Adyen\Payment\Api\AdyenThreeDS2ProcessInterface;
class AdyenThreeDS2Process implements AdyenThreeDS2ProcessInterface
{
/**
* @var \Magento\Checkout\Model\Session
*/
private $checkoutSession;
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* @var \Magento\Sales\Model\OrderFactory
*/
private $orderFactory;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
private $adyenLogger;
/**
* AdyenThreeDS2Process constructor.
*
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Sales\Model\OrderFactory $orderFactory
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
*/
public function __construct(
\Magento\Checkout\Model\Session $checkoutSession,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Sales\Model\OrderFactory $orderFactory,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger
)
{
$this->checkoutSession = $checkoutSession;
$this->adyenHelper = $adyenHelper;
$this->orderFactory = $orderFactory;
$this->adyenLogger = $adyenLogger;
}
/**
* @api
* @param string $payload
* @return string
*/
public function initiate($payload)
{
// Decode payload from frontend
$payload = json_decode($payload, true);
// Validate JSON that has just been parsed if it was in a valid format
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed because the request was not a valid JSON'));
}
if (empty($payload['orderId'])) {
$order = $this->getOrder();
// In the next major release remove support for retrieving order from session and throw exception instead
//throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed because of a missing order id'));
} else {
// Create order by order id
$order = $this->orderFactory->create()->load($payload['orderId']);
}
$payment = $order->getPayment();
// Init payments/details request
$result = [];
if ($paymentData = $payment->getAdditionalInformation("threeDS2PaymentData")) {
// Add payment data into the request object
$request = [
"paymentData" => $payment->getAdditionalInformation("threeDS2PaymentData")
];
// unset payment data from additional information
$payment->unsAdditionalInformation("threeDS2PaymentData");
} else {
$this->adyenLogger->error("3D secure 2.0 failed, payment data not found");
throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed, payment data not found'));
}
// Depends on the component's response we send a fingerprint or the challenge result
if (!empty($payload['details']['threeds2.fingerprint'])) {
$request['details']['threeds2.fingerprint'] = $payload['details']['threeds2.fingerprint'];
} elseif (!empty($payload['details']['threeds2.challengeResult'])) {
$request['details']['threeds2.challengeResult'] = $payload['details']['threeds2.challengeResult'];
}
// Send the request
try {
$client = $this->adyenHelper->initializeAdyenClient($order->getStoreId());
$service = $this->adyenHelper->createAdyenCheckoutService($client);
$result = $service->paymentsDetails($request);
} catch (\Adyen\AdyenException $e) {
$this->adyenLogger->error("3D secure 2.0 failed" . $e->getMessage());
throw new \Magento\Framework\Exception\LocalizedException(__('3D secure 2.0 failed'));
}
// Check if result is challenge shopper, if yes return the token
if (!empty($result['resultCode']) &&
$result['resultCode'] === 'ChallengeShopper' &&
!empty($result['authentication']['threeds2.challengeToken'])
) {
return $this->adyenHelper->buildThreeDS2ProcessResponseJson($result['resultCode'], $result['authentication']['threeds2.challengeToken']);
}
// Save the payments response because we are going to need it during the place order flow
$payment->setAdditionalInformation("paymentsResponse", $result);
// To actually save the additional info changes into the quote
$order->save();
$response = [];
if($result['resultCode'] != 'Authorised') {
$this->checkoutSession->restoreQuote();
// Always cancel the order if the paymenth has failed
if (!$order->canCancel()) {
$order->setState(\Magento\Sales\Model\Order::STATE_NEW);
}
$order->cancel()->save();
throw new \Magento\Framework\Exception\LocalizedException(__('The payment is REFUSED.'));
}
$response['result'] = $result['resultCode'];
return json_encode($response);
}
/**
* Get order object
*
* @return \Magento\Sales\Model\Order
* @deprecated Will be removed in 7.0.0
*/
protected function getOrder()
{
$incrementId = $this->checkoutSession->getLastRealOrderId();
$order = $this->orderFactory->create()->loadByIncrementId($incrementId);
return $order;
}
}