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 @@
namespace Adyen\Payment\Block\Transparent;
use Adyen\Payment\Helper\Data;
use Adyen\Service\Validator\DataArrayValidator;
use Magento\Framework\View\Element\Template;
......@@ -32,12 +33,20 @@ class Redirect extends Template
* @var \Magento\Framework\UrlInterface
*/
private $url;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
protected $adyenLogger;
/**
* @var Data
*/
protected $adyenHelper;
/**
* Redirect constructor.
*
* @param Template\Context $context
* @param \Magento\Framework\UrlInterface $url
* @param array $data
......@@ -46,24 +55,41 @@ class Redirect extends Template
Template\Context $context,
\Magento\Framework\UrlInterface $url,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
Data $adyenHelper,
array $data = []
) {
$this->url = $url;
$this->adyenLogger = $adyenLogger;
$this->adyenHelper = $adyenHelper;
parent::__construct($context, $data);
}
/**
* Returns url for redirect.
*
* @return string|null
*/
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.
*
* @return array
*/
public function getPostParams()
......
This diff is collapsed.
......@@ -24,6 +24,8 @@
namespace Adyen\Payment\Controller\Process;
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
{
......@@ -89,6 +91,13 @@ class Result extends \Magento\Framework\App\Action\Action
$this->_adyenLogger = $adyenLogger;
$this->storeManager = $storeManager;
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
*/
public function execute()
{
// GET and POST params together
$response = $this->getRequest()->getParams();
$this->_adyenLogger->addAdyenResult(print_r($response, true));
......@@ -153,6 +163,7 @@ class Result extends \Magento\Framework\App\Action\Action
$this->_adyenLogger->addAdyenResult('Processing ResultUrl');
// TODO check if needed since response is validated when calling this function
if (empty($response)) {
$this->_adyenLogger->addAdyenResult(
'Response is empty, please check your webserver that the result url accepts parameters'
......@@ -164,53 +175,44 @@ class Result extends \Magento\Framework\App\Action\Action
}
// 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'])) {
// authenticate result url
$authStatus = $this->_authenticate($response);
if (!$authStatus) {
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'])) {
$incrementId = $response['merchantReference'];
}
$order = $this->_order;
$order = $this->_getOrder($incrementId);
if ($order->getId()) {
$this->_eventManager->dispatch(
'adyen_payment_process_resulturl_before',
[
'order' => $order,
'adyen_response' => $response
]
);
if (isset($response['handled'])) {
return $response['handled_response'];
}
// update the order
$result = $this->_validateUpdateOrder($order, $response);
$this->_eventManager->dispatch(
'adyen_payment_process_resulturl_before',
[
'order' => $order,
'adyen_response' => $response
]
);
$this->_eventManager->dispatch(
'adyen_payment_process_resulturl_after',
[
'order' => $order,
'adyen_response' => $response
]
);
} else {
throw new \Magento\Framework\Exception\LocalizedException(
__('Order does not exists with increment_id: %1', $incrementId)
);
// TODO is handled in the response?
if (isset($response['handled'])) {
return $response['handled_response'];
}
// update the order
$result = $this->_validateUpdateOrder($order, $response);
$this->_eventManager->dispatch(
'adyen_payment_process_resulturl_after',
[
'order' => $order,
'adyen_response' => $response
]
);
return $result;
}
......@@ -382,42 +384,58 @@ class Result extends \Magento\Framework\App\Action\Action
* @return mixed
* @throws \Adyen\AdyenException
*/
protected function validatePayloadAndReturnResponse($response)
protected function validatePayloadAndReturnResponse($result)
{
$client = $this->_adyenHelper->initializeAdyenClient($this->storeManager->getStore()->getId());
$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()) &&
!empty($this->_session->getLastRealOrder()->getPayment())
) {
if (!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation('paymentData'))) {
$request['paymentData'] = $this->_session->getLastRealOrder()->getPayment()->
getAdditionalInformation('paymentData');
if (!$order->getId()) {
throw new \Magento\Framework\Exception\LocalizedException(
__('Order cannot be loaded')
);
}
// remove paymentData from db
$this->_session->getLastRealOrder()->getPayment()->unsAdditionalInformation('paymentData');
$this->_session->getLastRealOrder()->getPayment()->save();
$payment = $order->getPayment();
$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
// 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'))) {
$request['paymentData'] = $this->_session->getLastRealOrder()->getPayment()->
getAdditionalInformation("adyenPaymentData");
if (!empty($payment->getAdditionalInformation('adyenPaymentData'))) {
$request['paymentData'] = $payment->getAdditionalInformation("adyenPaymentData");
// remove paymentData from db
$this->_session->getLastRealOrder()->getPayment()->unsAdditionalInformation('adyenPaymentData');
$this->_session->getLastRealOrder()->getPayment()->save();
$payment->unsAdditionalInformation('adyenPaymentData');
$payment->save();
}
} 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;
if (!empty($this->_session->getLastRealOrder()) &&
// TODO check if this is ever reached
/*if (!empty($this->_session->getLastRealOrder()) &&
!empty($this->_session->getLastRealOrder()->getPayment()) &&
!empty($this->_session->getLastRealOrder()->getPayment()->getAdditionalInformation("details"))
) {
......@@ -427,10 +445,20 @@ class Result extends \Magento\Framework\App\Action\Action
if ($key !== false) {
$request["details"] = ["returnUrlQueryString" => http_build_query($response)];
}
}
}*/
try {
$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) {
$response['error'] = $e->getMessage();
}
......
......@@ -85,6 +85,7 @@ class CheckoutDataBuilder implements BuilderInterface
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
/** @var \Magento\Sales\Model\Order $order */
$order = $payment->getOrder();
$storeId = $order->getStoreId();
......@@ -96,7 +97,7 @@ class CheckoutDataBuilder implements BuilderInterface
$requestBody['returnUrl'] = $this->storeManager->getStore()->getBaseUrl(
\Magento\Framework\UrlInterface::URL_TYPE_LINK
) . 'adyen/process/result';
) . 'adyen/transparent/redirect?merchantReference=' . $order->getIncrementId();
// Additional data for ACH
if ($payment->getAdditionalInformation("bankAccountNumber")) {
......
......@@ -90,6 +90,10 @@ class CheckoutResponseValidator extends AbstractValidator
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
}
if (!empty($response['details'])) {
$payment->setAdditionalInformation('details', $response['details']);
}
switch ($resultCode) {
case "Authorised":
case "Received":
......
......@@ -145,6 +145,10 @@ class PaymentResponseHandler
$payment->setAdditionalInformation('adyenPaymentData', $paymentsResponse['paymentData']);
}
if (!empty($paymentsResponse['details'])) {
$payment->setAdditionalInformation('details', $paymentsResponse['details']);
}
switch ($paymentsResponse['resultCode']) {
case self::PRESENT_TO_SHOPPER:
case self::PENDING:
......
......@@ -116,7 +116,7 @@ class AdyenCcConfigProvider implements ConfigProviderInterface
'vaultCode' => self::CC_VAULT_CODE,
'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect/',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
)
]
......
......@@ -106,7 +106,7 @@ class AdyenGooglePayConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->urlBuilder->getUrl(
'adyen/process/redirect/',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
),
'successUrl' => $this->urlBuilder->getUrl(
......
......@@ -117,7 +117,7 @@ class AdyenHppConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->urlBuilder->getUrl(
'adyen/process/redirect',
'checkout/onepage/success',
['_secure' => $this->getRequest()->isSecure()]
)
]
......
......@@ -121,7 +121,7 @@ class AdyenOneclickConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect/',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
)
]
......
......@@ -84,7 +84,7 @@ class AdyenPayByMailConfigProvider implements ConfigProviderInterface
self::CODE => [
'isActive' => true,
'redirectUrl' => $this->_urlBuilder->getUrl(
'adyen/process/redirect',
'checkout/onepage/success',
['_secure' => $this->_getRequest()->isSecure()]
)
]
......
......@@ -301,6 +301,7 @@ define(
modalClass: 'cc_actionModal',
});
// TODO only show modal when it's redirect shopper
popupModal.modal('openModal');
adyenPaymentService.paymentDetails(request).
......
......@@ -169,6 +169,7 @@ define(
validateThreeDSOrPlaceOrder: function (responseJSON) {
var response = JSON.parse(responseJSON);
if (response && response.type === 'RedirectShopper') {
// TODO do redirect with the component
window.location.replace(url.build(
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