We will be off from 27/1 (Monday) to 31/1 (Friday) (GMT +7) for our Tet Holiday (Lunar New Year) in our country

Commit c8e009f6 authored by Attila Kiss's avatar Attila Kiss Committed by GitHub

[PW-3111] Use getOrigin helper function for returnUrl parameter in redirect controller (#924)

* Add PWA origin for the getRedirectUrl() in the transparent redirect

Add support for PWA dedicated frontend urls per store

* Add query when redirecting to the result controller

* Delete Redirect.php - not used anymore

* Add merchant reference in the return url as get param to support PWA

* Store details in the payment additional information object

* [WIP] use result as a generic handler for redirects

Validate all the redirects via payments/details
Validate the parameters for payments/details with the details list from
the first payments response

* [WIP] use result as a generic handler for redirects

* Update Controller/Process/Result.php
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>
Co-authored-by: default avatarÁngel Campos <angel.campos@adyen.com>
parent 1d5d1ed8
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
namespace Adyen\Payment\Block\Transparent; namespace Adyen\Payment\Block\Transparent;
use Adyen\Payment\Helper\Data;
use Adyen\Service\Validator\DataArrayValidator; use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\View\Element\Template; use Magento\Framework\View\Element\Template;
...@@ -32,12 +33,20 @@ class Redirect extends Template ...@@ -32,12 +33,20 @@ class Redirect extends Template
* @var \Magento\Framework\UrlInterface * @var \Magento\Framework\UrlInterface
*/ */
private $url; private $url;
/** /**
* @var \Adyen\Payment\Logger\AdyenLogger * @var \Adyen\Payment\Logger\AdyenLogger
*/ */
protected $adyenLogger; protected $adyenLogger;
/**
* @var Data
*/
protected $adyenHelper;
/** /**
* Redirect constructor. * Redirect constructor.
*
* @param Template\Context $context * @param Template\Context $context
* @param \Magento\Framework\UrlInterface $url * @param \Magento\Framework\UrlInterface $url
* @param array $data * @param array $data
...@@ -46,24 +55,41 @@ class Redirect extends Template ...@@ -46,24 +55,41 @@ class Redirect extends Template
Template\Context $context, Template\Context $context,
\Magento\Framework\UrlInterface $url, \Magento\Framework\UrlInterface $url,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger, \Adyen\Payment\Logger\AdyenLogger $adyenLogger,
Data $adyenHelper,
array $data = [] array $data = []
) { ) {
$this->url = $url; $this->url = $url;
$this->adyenLogger = $adyenLogger; $this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
parent::__construct($context, $data); parent::__construct($context, $data);
} }
/** /**
* Returns url for redirect. * Returns url for redirect.
*
* @return string|null * @return string|null
*/ */
public function getRedirectUrl() public function getRedirectUrl()
{ {
return $this->url->getUrl("adyen/process/redirect"); //TODO this will be replaced by getOrigin() for PWA integrations $pwaOrigin = $this->adyenHelper->getAdyenAbstractConfigData("payment_origin_url", $this->_storeManager->getStore()->getId());
if ($pwaOrigin) {
$returnUrl = $pwaOrigin . "/adyen/process/result";
} else {
$returnUrl = $this->url->getUrl("adyen/process/result");
}
if (!empty($this->getRequest()->getQueryValue())) {
$query = http_build_query($this->getRequest()->getQueryValue(), '', '&');
$returnUrl .= '?' . $query;
}
return $returnUrl;
} }
/** /**
* Returns params to be redirected. * Returns params to be redirected.
*
* @return array * @return array
*/ */
public function getPostParams() public function getPostParams()
......
This diff is collapsed.
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
namespace Adyen\Payment\Controller\Process; namespace Adyen\Payment\Controller\Process;
use \Adyen\Payment\Model\Notification; use \Adyen\Payment\Model\Notification;
use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\App\Request\Http as Http;
class Result extends \Magento\Framework\App\Action\Action class Result extends \Magento\Framework\App\Action\Action
{ {
...@@ -89,6 +91,13 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -89,6 +91,13 @@ class Result extends \Magento\Framework\App\Action\Action
$this->_adyenLogger = $adyenLogger; $this->_adyenLogger = $adyenLogger;
$this->storeManager = $storeManager; $this->storeManager = $storeManager;
parent::__construct($context); parent::__construct($context);
if (interface_exists(\Magento\Framework\App\CsrfAwareActionInterface::class)) {
$request = $this->getRequest();
if ($request instanceof Http && $request->isPost()) {
$request->setParam('isAjax', true);
$request->getHeaders()->addHeaderLine('X_REQUESTED_WITH', 'XMLHttpRequest');
}
}
} }
/** /**
...@@ -96,6 +105,7 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -96,6 +105,7 @@ class Result extends \Magento\Framework\App\Action\Action
*/ */
public function execute() public function execute()
{ {
// GET and POST params together
$response = $this->getRequest()->getParams(); $response = $this->getRequest()->getParams();
$this->_adyenLogger->addAdyenResult(print_r($response, true)); $this->_adyenLogger->addAdyenResult(print_r($response, true));
...@@ -153,6 +163,7 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -153,6 +163,7 @@ class Result extends \Magento\Framework\App\Action\Action
$this->_adyenLogger->addAdyenResult('Processing ResultUrl'); $this->_adyenLogger->addAdyenResult('Processing ResultUrl');
// TODO check if needed since response is validated when calling this function
if (empty($response)) { if (empty($response)) {
$this->_adyenLogger->addAdyenResult( $this->_adyenLogger->addAdyenResult(
'Response is empty, please check your webserver that the result url accepts parameters' 'Response is empty, please check your webserver that the result url accepts parameters'
...@@ -164,26 +175,20 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -164,26 +175,20 @@ class Result extends \Magento\Framework\App\Action\Action
} }
// If the merchant signature is present, authenticate the result url // If the merchant signature is present, authenticate the result url
// TODO validate if merchant signature is still used or can be removed
if (!empty($response['merchantSig'])) { if (!empty($response['merchantSig'])) {
// authenticate result url // authenticate result url
$authStatus = $this->_authenticate($response); $authStatus = $this->_authenticate($response);
if (!$authStatus) { if (!$authStatus) {
throw new \Magento\Framework\Exception\LocalizedException(__('ResultUrl authentification failure')); throw new \Magento\Framework\Exception\LocalizedException(__('ResultUrl authentification failure'));
} }
// Otherwise validate the pazload and get back the response that can be used to finish the order
} else {
// send the payload verification payment\details request to validate the response
$response = $this->validatePayloadAndReturnResponse($response);
} }
$incrementId = null; // send the payload verification payment\details request to validate the response
$response = $this->validatePayloadAndReturnResponse($response);
if (!empty($response['merchantReference'])) { $order = $this->_order;
$incrementId = $response['merchantReference'];
}
$order = $this->_getOrder($incrementId);
if ($order->getId()) {
$this->_eventManager->dispatch( $this->_eventManager->dispatch(
'adyen_payment_process_resulturl_before', 'adyen_payment_process_resulturl_before',
[ [
...@@ -191,6 +196,8 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -191,6 +196,8 @@ class Result extends \Magento\Framework\App\Action\Action
'adyen_response' => $response 'adyen_response' => $response
] ]
); );
// TODO is handled in the response?
if (isset($response['handled'])) { if (isset($response['handled'])) {
return $response['handled_response']; return $response['handled_response'];
} }
...@@ -205,11 +212,6 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -205,11 +212,6 @@ class Result extends \Magento\Framework\App\Action\Action
'adyen_response' => $response 'adyen_response' => $response
] ]
); );
} else {
throw new \Magento\Framework\Exception\LocalizedException(
__('Order does not exists with increment_id: %1', $incrementId)
);
}
return $result; return $result;
} }
...@@ -382,42 +384,58 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -382,42 +384,58 @@ class Result extends \Magento\Framework\App\Action\Action
* @return mixed * @return mixed
* @throws \Adyen\AdyenException * @throws \Adyen\AdyenException
*/ */
protected function validatePayloadAndReturnResponse($response) protected function validatePayloadAndReturnResponse($result)
{ {
$client = $this->_adyenHelper->initializeAdyenClient($this->storeManager->getStore()->getId()); $client = $this->_adyenHelper->initializeAdyenClient($this->storeManager->getStore()->getId());
$service = $this->_adyenHelper->createAdyenCheckoutService($client); $service = $this->_adyenHelper->createAdyenCheckoutService($client);
$request = []; if (!empty($result['merchantReference'])) {
//TODO Replace with order repository search for best practice
$order = $this->_orderFactory->create()->loadByIncrementId($result['merchantReference']);
} else {
$order = $this->_session->getLastRealOrder();
}
if (!empty($this->_session->getLastRealOrder()) && if (!$order->getId()) {
!empty($this->_session->getLastRealOrder()->getPayment()) throw new \Magento\Framework\Exception\LocalizedException(
) { __('Order cannot be loaded')
if (!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation('paymentData'))) { );
$request['paymentData'] = $this->_session->getLastRealOrder()->getPayment()-> }
getAdditionalInformation('paymentData');
// remove paymentData from db $payment = $order->getPayment();
$this->_session->getLastRealOrder()->getPayment()->unsAdditionalInformation('paymentData');
$this->_session->getLastRealOrder()->getPayment()->save(); $request = [];
// filter details to match the keys
$allowedParams = $payment->getAdditionalInformation('details');
$details = $result;
if (!empty($allowedParams)) {
$allowedParamsArray = [];
// TODO build a validator class which also validates the type of the param
foreach ($allowedParams as $allowedParam) {
$allowedParamsArray[] = $allowedParam['key'];
}
$details = DataArrayValidator::getArrayOnlyWithApprovedKeys($details, $allowedParamsArray);
} }
$request["details"] = $details;
if (!empty($payment)) {
// for pending payment that redirect we store this under adyenPaymentData // for pending payment that redirect we store this under adyenPaymentData
// TODO: refactor the code in the plugin that all paymentData is stored in paymentData and not in adyenPaymentData // TODO: refactor the code in the plugin that all paymentData is stored in paymentData and not in adyenPaymentData
if (!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation('adyenPaymentData'))) { if (!empty($payment->getAdditionalInformation('adyenPaymentData'))) {
$request['paymentData'] = $this->_session->getLastRealOrder()->getPayment()-> $request['paymentData'] = $payment->getAdditionalInformation("adyenPaymentData");
getAdditionalInformation("adyenPaymentData");
// remove paymentData from db // remove paymentData from db
$this->_session->getLastRealOrder()->getPayment()->unsAdditionalInformation('adyenPaymentData'); $payment->unsAdditionalInformation('adyenPaymentData');
$this->_session->getLastRealOrder()->getPayment()->save(); $payment->save();
} }
} else { } else {
$this->_adyenLogger->addError("Can't load the order id from the session"); $this->_adyenLogger->addError("Payment object cannot be loaded from order");
} }
$request["details"] = $response; // TODO check if this is ever reached
/*if (!empty($this->_session->getLastRealOrder()) &&
if (!empty($this->_session->getLastRealOrder()) &&
!empty($this->_session->getLastRealOrder()->getPayment()) && !empty($this->_session->getLastRealOrder()->getPayment()) &&
!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation("details")) !empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation("details"))
) { ) {
...@@ -427,10 +445,20 @@ class Result extends \Magento\Framework\App\Action\Action ...@@ -427,10 +445,20 @@ class Result extends \Magento\Framework\App\Action\Action
if ($key !== false) { if ($key !== false) {
$request["details"] = ["returnUrlQueryString" => http_build_query($response)]; $request["details"] = ["returnUrlQueryString" => http_build_query($response)];
} }
} }*/
try { try {
$response = $service->paymentsDetails($request); $response = $service->paymentsDetails($request);
if (!empty($response['merchantReference'])) {
if ($order->getIncrementId() === $response['merchantReference']) {
$this->_order = $order;
}
} else {
// TODO error handling
$this->_adyenLogger->addError("Wrong merchantReference was set in the query or in the session");
// TODO error page
}
} catch (\Adyen\AdyenException $e) { } catch (\Adyen\AdyenException $e) {
$response['error'] = $e->getMessage(); $response['error'] = $e->getMessage();
} }
......
...@@ -85,6 +85,7 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -85,6 +85,7 @@ class CheckoutDataBuilder implements BuilderInterface
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */ /** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject); $paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment(); $payment = $paymentDataObject->getPayment();
/** @var \Magento\Sales\Model\Order $order */
$order = $payment->getOrder(); $order = $payment->getOrder();
$storeId = $order->getStoreId(); $storeId = $order->getStoreId();
...@@ -96,7 +97,7 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -96,7 +97,7 @@ class CheckoutDataBuilder implements BuilderInterface
$requestBody['returnUrl'] = $this->storeManager->getStore()->getBaseUrl( $requestBody['returnUrl'] = $this->storeManager->getStore()->getBaseUrl(
\Magento\Framework\UrlInterface::URL_TYPE_LINK \Magento\Framework\UrlInterface::URL_TYPE_LINK
) . 'adyen/process/result'; ) . 'adyen/transparent/redirect?merchantReference=' . $order->getIncrementId();
// Additional data for ACH // Additional data for ACH
if ($payment->getAdditionalInformation("bankAccountNumber")) { if ($payment->getAdditionalInformation("bankAccountNumber")) {
......
...@@ -90,6 +90,10 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -90,6 +90,10 @@ class CheckoutResponseValidator extends AbstractValidator
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']); $payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
} }
if (!empty($response['details'])) {
$payment->setAdditionalInformation('details', $response['details']);
}
switch ($resultCode) { switch ($resultCode) {
case "Authorised": case "Authorised":
case "Received": case "Received":
......
...@@ -145,6 +145,10 @@ class PaymentResponseHandler ...@@ -145,6 +145,10 @@ class PaymentResponseHandler
$payment->setAdditionalInformation('adyenPaymentData', $paymentsResponse['paymentData']); $payment->setAdditionalInformation('adyenPaymentData', $paymentsResponse['paymentData']);
} }
if (!empty($paymentsResponse['details'])) {
$payment->setAdditionalInformation('details', $paymentsResponse['details']);
}
switch ($paymentsResponse['resultCode']) { switch ($paymentsResponse['resultCode']) {
case self::PRESENT_TO_SHOPPER: case self::PRESENT_TO_SHOPPER:
case self::PENDING: case self::PENDING:
......
...@@ -116,7 +116,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface ...@@ -116,7 +116,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
'vaultCode' => self::CC_VAULT_CODE, 'vaultCode' => self::CC_VAULT_CODE,
'isActive' => true, 'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl( 'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect/', 'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()] ['_secure' => $this->_getRequest()->isSecure()]
) )
] ]
......
...@@ -106,7 +106,7 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface ...@@ -106,7 +106,7 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
self::CODE => [ self::CODE => [
'isActive' => true, 'isActive' => true,
'redirectUrl' => $this->urlBuilder->getUrl( 'redirectUrl' => $this->urlBuilder->getUrl(
'adyen/process/redirect/', 'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()] ['_secure' => $this->_getRequest()->isSecure()]
), ),
'successUrl' => $this->urlBuilder->getUrl( 'successUrl' => $this->urlBuilder->getUrl(
......
...@@ -117,7 +117,7 @@ class AdyenHppConfigProvider implements ConfigProviderInterface ...@@ -117,7 +117,7 @@ class AdyenHppConfigProvider implements ConfigProviderInterface
self::CODE => [ self::CODE => [
'isActive' => true, 'isActive' => true,
'redirectUrl' => $this->urlBuilder->getUrl( 'redirectUrl' => $this->urlBuilder->getUrl(
'adyen/process/redirect', 'checkout/onepage/success',
['_secure' => $this->getRequest()->isSecure()] ['_secure' => $this->getRequest()->isSecure()]
) )
] ]
......
...@@ -121,7 +121,7 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface ...@@ -121,7 +121,7 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
self::CODE => [ self::CODE => [
'isActive' => true, 'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl( 'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect/', 'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()] ['_secure' => $this->_getRequest()->isSecure()]
) )
] ]
......
...@@ -84,7 +84,7 @@ class AdyenPayByMailConfigProvider implements ConfigProviderInterface ...@@ -84,7 +84,7 @@ class AdyenPayByMailConfigProvider implements ConfigProviderInterface
self::CODE => [ self::CODE => [
'isActive' => true, 'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl( 'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect', 'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()] ['_secure' => $this->_getRequest()->isSecure()]
) )
] ]
......
...@@ -301,6 +301,7 @@ define( ...@@ -301,6 +301,7 @@ define(
modalClass: 'cc_actionModal', modalClass: 'cc_actionModal',
}); });
// TODO only show modal when it's redirect shopper
popupModal.modal('openModal'); popupModal.modal('openModal');
adyenPaymentService.paymentDetails(request). adyenPaymentService.paymentDetails(request).
......
...@@ -169,6 +169,7 @@ define( ...@@ -169,6 +169,7 @@ define(
validateThreeDSOrPlaceOrder: function (responseJSON) { validateThreeDSOrPlaceOrder: function (responseJSON) {
var response = JSON.parse(responseJSON); var response = JSON.parse(responseJSON);
if (response && response.type === 'RedirectShopper') { if (response && response.type === 'RedirectShopper') {
// TODO do redirect with the component
window.location.replace(url.build( window.location.replace(url.build(
window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl
)); ));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment