Commit 14c25f45 authored by Attila Kiss's avatar Attila Kiss Committed by GitHub

[PW-3174] Use the generic component for card payments (#840)

* Use bundle instead of the component

* Store action and additionalData from /payments response

* [WIP] handle paymentDetails for card payments

* Remove custom redirect page

The checkout redirect component does the redirect for both 3DS1(now) and
alternative payment(WIP)

* Store and return details

Store action, resultCode, additionalData, pspReference, nad paymentData

* Show challenge in a popup for 3DS2
parent 89409fb6
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Block\Redirect;
use Adyen\AdyenException;
use Symfony\Component\Config\Definition\Exception\Exception;
class Redirect extends \Magento\Payment\Block\Form
{
/**
* @var \Magento\Sales\Model\OrderFactory
*/
protected $_orderFactory;
/**
* @var \Magento\Checkout\Model\Session
*/
protected $_checkoutSession;
/**
* @var \Magento\Sales\Model\Order
*/
protected $_order;
/**
* @var \Adyen\Payment\Helper\Data
*/
protected $_adyenHelper;
/**
* @var ResolverInterface
*/
protected $_resolver;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
*/
protected $_adyenLogger;
/**
* @var \Magento\Tax\Model\Config
*/
protected $_taxConfig;
/**
* @var \Magento\Tax\Model\Calculation
*/
protected $_taxCalculation;
/**
* Request object
*/
protected $_request;
/**
* Redirect constructor.
*
* @param \Magento\Framework\View\Element\Template\Context $context
* @param array $data
* @param \Magento\Sales\Model\OrderFactory $orderFactory
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Locale\ResolverInterface $resolver
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Magento\Tax\Model\Config $taxConfig
* @param \Magento\Tax\Model\Calculation $taxCalculation
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Sales\Model\OrderFactory $orderFactory,
\Magento\Checkout\Model\Session $checkoutSession,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Locale\ResolverInterface $resolver,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Magento\Tax\Model\Config $taxConfig,
\Magento\Tax\Model\Calculation $taxCalculation,
array $data = []
) {
$this->_orderFactory = $orderFactory;
$this->_checkoutSession = $checkoutSession;
parent::__construct($context, $data);
$this->_adyenHelper = $adyenHelper;
$this->_resolver = $resolver;
$this->_adyenLogger = $adyenLogger;
$this->_getOrder();
$this->_taxConfig = $taxConfig;
$this->_taxCalculation = $taxCalculation;
$this->_request = $context->getRequest();
}
/**
* @return mixed|string[]
* @throws AdyenException
*/
public function getRedirectMethod()
{
if ($redirectMethod = $this->getPayment()->getAdditionalInformation('redirectMethod')) {
return $redirectMethod;
}
throw new AdyenException("No redirect method is provided.");
}
/**
* @return Redirect
*/
public function _prepareLayout()
{
return parent::_prepareLayout();
}
/**
* Retrieves redirect url for the flow of checkout API
*
* @return string[]
* @throws AdyenException
*/
public function getRedirectUrl()
{
if ($redirectUrl = $this->getPayment()->getAdditionalInformation('redirectUrl')) {
return $redirectUrl;
}
throw new AdyenException("No redirect url is provided.");
}
/**
* @return string
*/
public function getFormUrl()
{
$url = "";
try {
if ($this->_order->getPayment()) {
switch ($this->_adyenHelper->isDemoMode()) {
case true:
if ($this->_adyenHelper->doesPaymentMethodSkipDetails(
$this->_order->getPayment()->getAdditionalInformation('brand_code')
)
) {
$url = "https://test.adyen.com/hpp/skipDetails.shtml";
} else {
$url = "https://test.adyen.com/hpp/details.shtml";
}
break;
default:
if ($this->_adyenHelper->doesPaymentMethodSkipDetails(
$this->_order->getPayment()->getAdditionalInformation('brand_code')
)
) {
$url = "https://live.adyen.com/hpp/skipDetails.shtml";
} else {
$url = "https://live.adyen.com/hpp/details.shtml";
}
break;
}
}
} catch (Exception $e) {
// do nothing for now
throw($e);
}
return $url;
}
/**
* @return mixed
*/
private function getBrandCode()
{
return $this->getPayment()->getAdditionalInformation('brand_code');
}
/**
* Set Billing Address data
*
* @param $formFields
*/
protected function setBillingAddressData($formFields)
{
$billingAddress = $this->_order->getBillingAddress();
if ($billingAddress) {
$formFields['shopper.firstName'] = trim($billingAddress->getFirstname());
$middleName = trim($billingAddress->getMiddlename());
if ($middleName != "") {
$formFields['shopper.infix'] = trim($middleName);
}
$formFields['shopper.lastName'] = trim($billingAddress->getLastname());
$formFields['shopper.telephoneNumber'] = trim($billingAddress->getTelephone());
if ($this->_adyenHelper->isSeparateHouseNumberRequired($billingAddress->getCountryId())) {
$street = $this->_adyenHelper->getStreet($billingAddress);
if (!empty($street['name'])) {
$formFields['billingAddress.street'] = $street['name'];
}
if (!empty($street['house_number'])) {
$formFields['billingAddress.houseNumberOrName'] = $street['house_number'];
} else {
$formFields['billingAddress.houseNumberOrName'] = "NA";
}
} else {
$formFields['billingAddress.street'] = implode(" ", $billingAddress->getStreet());
}
if (trim($billingAddress->getCity()) == "") {
$formFields['billingAddress.city'] = "NA";
} else {
$formFields['billingAddress.city'] = trim($billingAddress->getCity());
}
if (trim($billingAddress->getPostcode()) == "") {
$formFields['billingAddress.postalCode'] = "";
} else {
$formFields['billingAddress.postalCode'] = trim($billingAddress->getPostcode());
}
if (trim($billingAddress->getRegionCode()) == "") {
$formFields['billingAddress.stateOrProvince'] = "";
} else {
$formFields['billingAddress.stateOrProvince'] = trim($billingAddress->getRegionCode());
}
if (trim($billingAddress->getCountryId()) == "") {
$formFields['billingAddress.country'] = "ZZ";
} else {
$formFields['billingAddress.country'] = trim($billingAddress->getCountryId());
}
}
return $formFields;
}
/**
* Set Shipping Address data
*
* @param $formFields
*/
protected function setShippingAddressData($formFields)
{
$shippingAddress = $this->_order->getShippingAddress();
if ($shippingAddress) {
if ($this->_adyenHelper->isSeparateHouseNumberRequired($shippingAddress->getCountryId())) {
$street = $this->_adyenHelper->getStreet($shippingAddress);
if (isset($street['name']) && $street['name'] != "") {
$formFields['deliveryAddress.street'] = $street['name'];
}
if (isset($street['house_number']) && $street['house_number'] != "") {
$formFields['deliveryAddress.houseNumberOrName'] = $street['house_number'];
} else {
$formFields['deliveryAddress.houseNumberOrName'] = "NA";
}
} else {
$formFields['deliveryAddress.street'] = implode(" ", $shippingAddress->getStreet());
}
if (trim($shippingAddress->getCity()) == "") {
$formFields['deliveryAddress.city'] = "NA";
} else {
$formFields['deliveryAddress.city'] = trim($shippingAddress->getCity());
}
if (trim($shippingAddress->getPostcode()) == "") {
$formFields['deliveryAddress.postalCode'] = "";
} else {
$formFields['deliveryAddress.postalCode'] = trim($shippingAddress->getPostcode());
}
if (trim($shippingAddress->getRegionCode()) == "") {
$formFields['deliveryAddress.stateOrProvince'] = "";
} else {
$formFields['deliveryAddress.stateOrProvince'] = trim($shippingAddress->getRegionCode());
}
if (trim($shippingAddress->getCountryId()) == "") {
$formFields['deliveryAddress.country'] = "ZZ";
} else {
$formFields['deliveryAddress.country'] = trim($shippingAddress->getCountryId());
}
}
return $formFields;
}
/**
* @param $formFields
* @return mixed
*/
protected function setOpenInvoiceData($formFields)
{
$count = 0;
$currency = $this->_order->getOrderCurrencyCode();
foreach ($this->_order->getAllVisibleItems() as $item) {
/** @var $item \Magento\Sales\Model\Order\Item */
++$count;
$numberOfItems = (int)$item->getQtyOrdered();
$formFields = $this->_adyenHelper->createOpenInvoiceLineItem(
$formFields,
$count,
$item->getName(),
$item->getPrice(),
$currency,
$item->getTaxAmount(),
$item->getPriceInclTax(),
$item->getTaxPercent(),
$numberOfItems,
$this->_order->getPayment(),
$item->getId()
);
}
// Discount cost
if ($this->_order->getDiscountAmount() > 0 || $this->_order->getDiscountAmount() < 0) {
++$count;
$description = __('Total Discount');
$itemAmount = $this->_adyenHelper->formatAmount($this->_order->getDiscountAmount(), $currency);
$itemVatAmount = "0";
$itemVatPercentage = "0";
$numberOfItems = 1;
$formFields = $this->_adyenHelper->getOpenInvoiceLineData(
$formFields,
$count,
$currency,
$description,
$itemAmount,
$itemVatAmount,
$itemVatPercentage,
$numberOfItems,
$this->_order->getPayment(),
"totalDiscount"
);
}
// Shipping cost
if ($this->_order->getShippingAmount() > 0 || $this->_order->getShippingTaxAmount() > 0) {
++$count;
$formFields = $this->_adyenHelper->createOpenInvoiceLineShipping(
$formFields,
$count,
$this->_order,
$this->_order->getShippingAmount(),
$this->_order->getShippingTaxAmount(),
$currency,
$this->_order->getPayment()
);
}
$formFields['openinvoicedata.refundDescription'] = "Refund / Correction for " .
$formFields['merchantReference'];
$formFields['openinvoicedata.numberOfLines'] = $count;
return $formFields;
}
/**
* @param $genderId
* @return string
*/
protected function getGenderText($genderId)
{
$result = "";
if ($genderId == '1') {
$result = 'MALE';
} elseif ($genderId == '2') {
$result = 'FEMALE';
}
return $result;
}
/**
* The character escape function is called from the array_map function in _signRequestParams
*
* @param $val
* @return mixed
*/
protected function escapeString($val)
{
return str_replace(':', '\\:', str_replace('\\', '\\\\', $val));
}
/**
* Get frontend checkout session object
*
* @return \Magento\Checkout\Model\Session
*/
protected function _getCheckout()
{
return $this->_checkoutSession;
}
/**
* Retrieve request object
*
* @return \Magento\Framework\App\RequestInterface
*/
protected function _getRequest()
{
return $this->_request;
}
/**
* Get order object
*
* @return \Magento\Sales\Model\Order
*/
protected function _getOrder()
{
if (!$this->_order) {
$incrementId = $this->_getCheckout()->getLastRealOrderId();
$this->_order = $this->_orderFactory->create()->loadByIncrementId($incrementId);
}
return $this->_order;
}
/**
* @return mixed
*/
public function getPaReq()
{
if ($paReq = $this->getPayment()->getAdditionalInformation('paRequest')) {
return $paReq;
}
throw new AdyenException("No paRequest is provided.");
}
/**
* @return string[]
* @throws AdyenException
*/
public function getMd()
{
if ($md = $this->getPayment()->getAdditionalInformation('md')) {
return $md;
}
throw new AdyenException("No MD is provided.");
}
/**
* @return mixed
*/
public function getTermUrl()
{
if ($termUrl = $this->getPayment()->getAdditionalInformation('termUrl')) {
return $termUrl;
}
throw new AdyenException("No termUrl is provided.");
}
/**
* Retrieve payment object if available
*
* @return \Magento\Framework\DataObject|\Magento\Sales\Api\Data\OrderPaymentInterface|mixed|null
* @throws AdyenException
*/
private function getPayment()
{
try {
$paymentObject = $this->_order->getPayment();
if (!empty($paymentObject)) {
return $paymentObject;
}
} catch (Exception $e) {
// do nothing for now
throw($e);
}
throw new AdyenException("No payment object is found.");
}
}
...@@ -148,7 +148,6 @@ class Redirect extends \Magento\Framework\App\Action\Action ...@@ -148,7 +148,6 @@ class Redirect extends \Magento\Framework\App\Action\Action
if ($order->getPayment()) { if ($order->getPayment()) {
$active = $order->getPayment()->getAdditionalInformation('3dActive'); $active = $order->getPayment()->getAdditionalInformation('3dActive');
$success = $order->getPayment()->getAdditionalInformation('3dSuccess'); $success = $order->getPayment()->getAdditionalInformation('3dSuccess');
$checkoutAPM = $order->getPayment()->getAdditionalInformation('checkoutAPM');
} }
// check if 3D secure is active. If not just go to success page // check if 3D secure is active. If not just go to success page
...@@ -247,27 +246,7 @@ class Redirect extends \Magento\Framework\App\Action\Action ...@@ -247,27 +246,7 @@ class Redirect extends \Magento\Framework\App\Action\Action
$this->_redirect($this->_adyenHelper->getAdyenAbstractConfigData('return_path')); $this->_redirect($this->_adyenHelper->getAdyenAbstractConfigData('return_path'));
} }
} else {
$this->_adyenLogger->addAdyenResult("Customer was redirected to bank for 3D-secure validation.");
$order->addStatusHistoryComment(
__(
'Customer was redirected to bank for 3D-secure validation. Once the shopper authenticated,
the order status will be updated accordingly.
<br />Make sure that your notifications are being processed!
<br />If the order is stuck on this status, the shopper abandoned the session.
The payment can be seen as unsuccessful.
<br />The order can be automatically cancelled based on the OFFER_CLOSED notification.
Please contact Adyen Support to enable this.'
)
)->save();
$this->_view->loadLayout();
$this->_view->getLayout()->initMessages();
$this->_view->renderLayout();
} }
} elseif (!empty($checkoutAPM)) {
$this->_view->loadLayout();
$this->_view->getLayout()->initMessages();
$this->_view->renderLayout();
} else { } else {
$this->_redirect('checkout/onepage/success', ['_query' => ['utm_nooverride' => '1']]); $this->_redirect('checkout/onepage/success', ['_query' => ['utm_nooverride' => '1']]);
} }
......
...@@ -69,25 +69,27 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -69,25 +69,27 @@ class CheckoutResponseValidator extends AbstractValidator
// validate result // validate result
if (!empty($response['resultCode'])) { if (!empty($response['resultCode'])) {
$payment->setAdditionalInformation('resultCode', $response['resultCode']); $payment->setAdditionalInformation('resultCode', $response['resultCode']);
switch ($response['resultCode']) {
case "IdentifyShopper": if (!empty($response['action'])) {
$payment->setAdditionalInformation('threeDSType', $response['resultCode']); $payment->setAdditionalInformation('action', $response['action']);
$payment->setAdditionalInformation( }
'threeDS2Token',
$response['authentication']['threeds2.fingerprintToken'] if (!empty($response['additionalData'])) {
); $payment->setAdditionalInformation('additionalData', $response['additionalData']);
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']); }
break;
case "ChallengeShopper": if (!empty($response['pspReference'])) {
$payment->setAdditionalInformation('threeDSType', $response['resultCode']); $payment->setAdditionalInformation('pspReference', $response['pspReference']);
$payment->setAdditionalInformation( }
'threeDS2Token',
$response['authentication']['threeds2.challengeToken'] if (!empty($response['paymentData'])) {
);
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']); $payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']);
break; }
switch ($response['resultCode']) {
case "Authorised": case "Authorised":
case "Received": case "Received":
// TODO refactor since the full additionalData is stored in additionalInformation already
// For banktransfers store all bankTransfer details // For banktransfers store all bankTransfer details
if (!empty($response['additionalData']['bankTransfer.owner'])) { if (!empty($response['additionalData']['bankTransfer.owner'])) {
foreach ($response['additionalData'] as $key => $value) { foreach ($response['additionalData'] as $key => $value) {
...@@ -115,21 +117,14 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -115,21 +117,14 @@ class CheckoutResponseValidator extends AbstractValidator
} }
$payment->setAdditionalInformation('pspReference', $response['pspReference']); $payment->setAdditionalInformation('pspReference', $response['pspReference']);
break; break;
case "IdentifyShopper":
case "ChallengeShopper":
case "PresentToShopper": case "PresentToShopper":
if (!empty($response['action'])) {
$payment->setAdditionalInformation('action', $response['action']);
}
if (!empty($response['pspReference'])) {
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
}
break;
case 'Pending': case 'Pending':
$payment->setAdditionalInformation('adyenPaymentData', $response['paymentData']); // nothing extra
if (!empty($response['action'])) {
$payment->setAdditionalInformation('action', $response['action']);
}
break; break;
case "RedirectShopper": case "RedirectShopper":
// TODO refactor this resultCode handling
$payment->setAdditionalInformation('threeDSType', $response['resultCode']); $payment->setAdditionalInformation('threeDSType', $response['resultCode']);
$redirectUrl = null; $redirectUrl = null;
......
...@@ -100,15 +100,50 @@ class PaymentResponseHandler ...@@ -100,15 +100,50 @@ class PaymentResponseHandler
$this->adyenLogger->error("Payment details call failed, paymentsResponse is empty"); $this->adyenLogger->error("Payment details call failed, paymentsResponse is empty");
return false; return false;
} }
if (!empty($paymentsResponse['resultCode']))
$payment->setAdditionalInformation('resultCode', $paymentsResponse['resultCode']);
if (!empty($paymentsResponse['action'])) {
$payment->setAdditionalInformation('action', $paymentsResponse['action']);
}
if (!empty($paymentsResponse['additionalData'])) {
$payment->setAdditionalInformation('additionalData', $paymentsResponse['additionalData']);
}
if (!empty($paymentsResponse['pspReference'])) {
$payment->setAdditionalInformation('pspReference', $paymentsResponse['pspReference']);
}
if (!empty($paymentsResponse['paymentData'])) {
$payment->setAdditionalInformation('adyenPaymentData', $paymentsResponse['paymentData']);
}
switch ($paymentsResponse['resultCode']) { switch ($paymentsResponse['resultCode']) {
case self::PRESENT_TO_SHOPPER: case self::PRESENT_TO_SHOPPER:
case self::PENDING: case self::PENDING:
case self::RECEIVED: case self::RECEIVED:
$payment->setAdditionalInformation("paymentsResponse", $paymentsResponse);
break; break;
//We don't need to handle these resultCodes //We don't need to handle these resultCodes
case self::AUTHORISED:
case self::REDIRECT_SHOPPER: case self::REDIRECT_SHOPPER:
$this->adyenLogger->addAdyenResult("Customer was redirected.");
if ($order) {
$order->addStatusHistoryComment(
__(
'Customer was redirected to an external payment page. (In case of card payments the shopper is redirected to the bank for 3D-secure validation.) Once the shopper is authenticated,
the order status will be updated accordingly.
<br />Make sure that your notifications are being processed!
<br />If the order is stuck on this status, the shopper abandoned the session.
The payment can be seen as unsuccessful.
<br />The order can be automatically cancelled based on the OFFER_CLOSED notification.
Please contact Adyen Support to enable this.'
)
)->save();
}
break;
case self::AUTHORISED:
case self::IDENTIFY_SHOPPER: case self::IDENTIFY_SHOPPER:
case self::CHALLENGE_SHOPPER: case self::CHALLENGE_SHOPPER:
break; break;
......
...@@ -151,6 +151,17 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface ...@@ -151,6 +151,17 @@ class AdyenPaymentDetails implements AdyenPaymentDetailsInterface
$this->checkoutSession->restoreQuote(); $this->checkoutSession->restoreQuote();
throw new LocalizedException(__('The payment is REFUSED.')); throw new LocalizedException(__('The payment is REFUSED.'));
} }
return json_encode($this->paymentResponseHandler->formatPaymentResponse($paymentDetails['resultCode']));
$action = null;
if (!empty($paymentDetails['action'])) {
$action = $paymentDetails['action'];
}
$additionalData = null;
if (!empty($paymentDetails['additionalData'])) {
$additionalData = $paymentDetails['additionalData'];
}
return json_encode($this->paymentResponseHandler->formatPaymentResponse($paymentDetails['resultCode'], $action, $additionalData));
} }
} }
<?xml version="1.0"?>
<!--
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
-->
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
<container name="root">
<block class="Adyen\Payment\Block\Redirect\Redirect" name="adyen-redirect-form" template="redirect/redirect.phtml" cacheable="false"/>
</container>
</layout>
\ No newline at end of file
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment module (https://www.adyen.com/)
*
* Copyright (c) 2015 Adyen BV (https://www.adyen.com/)
* See LICENSE.txt for license details.
*
* Author: Adyen <magento@adyen.com>
*/
?>
<?php
if ($block->getRedirectMethod() == "GET") { ?>
<body>
<script>
window.location.replace("<?= $block->escapeJs($block->getRedirectUrl()); ?>");
</script>
</body>
<?php
} else { ?>
<body onload="document.getElementById('3dform').submit();">
<form method="POST" action="<?= $block->escapeHtml($block->getRedirectUrl()); ?>" id="3dform">
<input type="hidden" name="PaReq" value="<?= $block->escapeHtml($block->getPaReq()); ?>"/>
<input type="hidden" name="MD" value="<?= $block->escapeHtml($block->getMd()); ?>"/>
<input type="hidden" name="TermUrl" value="<?= $block->escapeHtml($block->getTermUrl()); ?>"/>
<noscript>
<br>
<br>
<div style="text-align: center">
<h1>Processing your 3-D Secure Transaction</h1>
<p>Please click continue to continue the processing of your 3-D Secure transaction.</p>
<input type="submit" class="button" value="continue"/>
</div>
</noscript>
</form>
</body>
<?php
} ?>
\ No newline at end of file
...@@ -40,7 +40,6 @@ define( ...@@ -40,7 +40,6 @@ define(
'Adyen_Payment/js/model/payment-details', 'Adyen_Payment/js/model/payment-details',
'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/error-processor',
'Adyen_Payment/js/model/adyen-payment-service', 'Adyen_Payment/js/model/adyen-payment-service',
'adyenCheckout',
'Adyen_Payment/js/bundle' 'Adyen_Payment/js/bundle'
], ],
function ( function (
...@@ -63,7 +62,6 @@ define( ...@@ -63,7 +62,6 @@ define(
paymentDetails, paymentDetails,
errorProcessor, errorProcessor,
adyenPaymentService, adyenPaymentService,
AdyenCheckout,
AdyenComponent AdyenComponent
) { ) {
...@@ -79,7 +77,8 @@ define( ...@@ -79,7 +77,8 @@ define(
creditCardOwner: '', creditCardOwner: '',
storeCc: false, storeCc: false,
installment: '', installment: '',
creditCardDetailsValid: false creditCardDetailsValid: false,
orderId: 0
}, },
/** /**
* @returns {exports.initialize} * @returns {exports.initialize}
...@@ -92,9 +91,11 @@ define( ...@@ -92,9 +91,11 @@ define(
// initialize adyen component for general use // initialize adyen component for general use
this.checkout = new AdyenCheckout({ this.checkout = new AdyenCheckout({
hasHolderName: true,
locale: this.getLocale(), locale: this.getLocale(),
originKey: this.getOriginKey(), originKey: this.getOriginKey(),
environment: this.getCheckoutEnvironment() environment: this.getCheckoutEnvironment(),
onAdditionalDetails: this.handleOnAdditionalDetails.bind(this)
}); });
return this; return this;
...@@ -144,11 +145,7 @@ define( ...@@ -144,11 +145,7 @@ define(
self.cardComponent = self.checkout.create('card', { self.cardComponent = self.checkout.create('card', {
originKey: self.getOriginKey(),
environment: self.getCheckoutEnvironment(),
type: 'card', type: 'card',
hasHolderName: true,
holderNameRequired: true,
enableStoreDetails: self.getEnableStoreDetails(), enableStoreDetails: self.getEnableStoreDetails(),
groupTypes: self.getAvailableCardTypeAltCodes(), groupTypes: self.getAvailableCardTypeAltCodes(),
...@@ -206,101 +203,29 @@ define( ...@@ -206,101 +203,29 @@ define(
} }
}).mount(cardNode); }).mount(cardNode);
}, },
/**
* Rendering the 3DS2.0 components
* To do the device fingerprint at the response of IdentifyShopper render the threeDS2DeviceFingerprint
* component
* To render the challenge for the customer at the response of ChallengeShopper render the
* threeDS2Challenge component
* Both of them is going to be rendered in a Magento dialog popup
*
* @param type
* @param token
*/
renderThreeDS2Component: function (type, token, orderId) {
var self = this;
var threeDS2Node = document.getElementById('threeDS2Container');
if (type == "IdentifyShopper") {
self.threeDS2IdentifyComponent = self.checkout
.create('threeDS2DeviceFingerprint', {
fingerprintToken: token,
onComplete: function (result) {
self.threeDS2IdentifyComponent.unmount();
var request = result.data;
request.orderId = orderId;
paymentDetails.process(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId)
}).fail(function (result) {
errorProcessor.process(result, self.messageContainer);
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
}
});
self.threeDS2IdentifyComponent.mount(threeDS2Node);
} else if (type == "ChallengeShopper") {
fullScreenLoader.stopLoader();
var popupModal = $('#threeDS2Modal').modal({
// disable user to hide popup
clickableOverlay: false,
responsive: true,
innerScroll: false,
// empty buttons, we don't need that
buttons: [],
modalClass: 'threeDS2Modal'
});
popupModal.modal("openModal"); handleAction: function (action, orderId) {
var self = this;
self.threeDS2ChallengeComponent = self.checkout try {
.create('threeDS2Challenge', { var component = self.checkout.createFromAction(action).mount('#cc_actionContainer');
challengeToken: token, } catch (e) {
size: '05', console.log(e);
onComplete: function (result) {
self.threeDS2ChallengeComponent.unmount();
self.closeModal(popupModal);
fullScreenLoader.startLoader();
var request = result.data;
request.orderId = orderId;
paymentDetails.process(request).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId);
}).fail(function (result) {
errorProcessor.process(result, self.messageContainer);
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
}
});
self.threeDS2ChallengeComponent.mount(threeDS2Node);
} }
}, },
threedsfallback: function (action) {
var self = this;
var actionNode = document.getElementById('ActionContainer');
self.threedsfallbackComponent = self.checkout.createFromAction(action).mount(actionNode);
},
/** /**
* This method is a workaround to close the modal in the right way and reconstruct the threeDS2Modal. * This method is a workaround to close the modal in the right way and reconstruct the threeDS2Modal.
* This will solve issues when you cancel the 3DS2 challenge and retry the payment * This will solve issues when you cancel the 3DS2 challenge and retry the payment
*/ */
closeModal: function (popupModal) { closeModal: function (popupModal) {
popupModal.modal("closeModal"); popupModal.modal("closeModal");
$('.threeDS2Modal').remove(); $('.cc_actionModal').remove();
$('.modals-overlay').remove(); $('.modals-overlay').remove();
$('body').removeClass('_has-modal'); $('body').removeClass('_has-modal');
// reconstruct the threeDS2Modal container again otherwise component can not find the threeDS2Modal // reconstruct the threeDS2Modal container again otherwise component can not find the threeDS2Modal
$('#threeDS2Wrapper').append("<div id=\"threeDS2Modal\">" + $('#cc_actionModalWrapper').append("<div id=\"cc_actionModal\">" +
"<div id=\"threeDS2Container\"></div>" + "<div id=\"cc_actionContainer\"></div>" +
"</div>"); "</div>");
}, },
/** /**
...@@ -370,9 +295,10 @@ define( ...@@ -370,9 +295,10 @@ define(
).done( ).done(
function (orderId) { function (orderId) {
self.afterPlaceOrder(); self.afterPlaceOrder();
self.orderId = orderId;
adyenPaymentService.getOrderPaymentStatus(orderId) adyenPaymentService.getOrderPaymentStatus(orderId)
.done(function (responseJSON) { .done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON, orderId) self.handleAdyenResult(responseJSON, orderId)
}); });
} }
); );
...@@ -383,22 +309,47 @@ define( ...@@ -383,22 +309,47 @@ define(
* Based on the response we can start a 3DS2 validation or place the order * Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON * @param responseJSON
*/ */
validateThreeDS2OrPlaceOrder: function (responseJSON, orderId) { handleAdyenResult: function (responseJSON, orderId) {
var self = this; var self = this;
var response = JSON.parse(responseJSON); var response = JSON.parse(responseJSON);
if (!!response.threeDS2) { if (!!response.isFinal) {
// render component // Status is final redirect to the redirectUrl
self.renderThreeDS2Component(response.type, response.token, orderId);
} else {
if (response.type === 'RedirectShopper' && response.action) {
self.threedsfallback(response.action);
} else {
window.location.replace(url.build( window.location.replace(url.build(
window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl
)); ));
} else {
// Handle action
self.handleAction(response.action, orderId);
} }
} },
handleOnAdditionalDetails: function (result) {
var self = this;
var request = result.data;
request.orderId = self.orderId;
fullScreenLoader.stopLoader();
var popupModal = $('#cc_actionModal').modal({
// disable user to hide popup
clickableOverlay: false,
responsive: true,
innerScroll: false,
// empty buttons, we don't need that
buttons: [],
modalClass: 'cc_actionModal'
});
popupModal.modal("openModal");
paymentDetails.process(request).done(function (responseJSON) {
self.handleAdyenResult(responseJSON, self.orderId)
}).fail(function (result) {
errorProcessor.process(result, self.messageContainer);
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
}, },
/** /**
* Validates the payment date when clicking the pay button * Validates the payment date when clicking the pay button
......
...@@ -38,7 +38,6 @@ define( ...@@ -38,7 +38,6 @@ define(
'Magento_Ui/js/model/messages', 'Magento_Ui/js/model/messages',
'Adyen_Payment/js/model/payment-details', 'Adyen_Payment/js/model/payment-details',
'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/error-processor',
'adyenCheckout',
'Adyen_Payment/js/bundle' 'Adyen_Payment/js/bundle'
], ],
function( function(
...@@ -59,7 +58,6 @@ define( ...@@ -59,7 +58,6 @@ define(
Messages, Messages,
paymentDetails, paymentDetails,
errorProcessor, errorProcessor,
AdyenCheckout,
AdyenComponent AdyenComponent
) { ) {
'use strict'; 'use strict';
......
...@@ -42,9 +42,7 @@ define( ...@@ -42,9 +42,7 @@ define(
'Adyen_Payment/js/model/payment-details', 'Adyen_Payment/js/model/payment-details',
'Magento_Checkout/js/model/error-processor', 'Magento_Checkout/js/model/error-processor',
'Adyen_Payment/js/model/adyen-payment-service', 'Adyen_Payment/js/model/adyen-payment-service',
'adyenCheckout', 'Adyen_Payment/js/bundle',
]
'Adyen_Payment/js/bundle';
], ],
function( function(
...@@ -69,8 +67,7 @@ function( ...@@ -69,8 +67,7 @@ function(
paymentDetails, paymentDetails,
errorProcessor, errorProcessor,
adyenPaymentService, adyenPaymentService,
AdyenCheckout, AdyenComponent
AdyenComponent,
) { ) {
'use strict'; 'use strict';
......
...@@ -95,9 +95,9 @@ ...@@ -95,9 +95,9 @@
<div class="checkout-component-dock" afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div> <div class="checkout-component-dock" afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div>
</div> </div>
<div id="threeDS2Wrapper"> <div id="cc_actionModalWrapper">
<div id="threeDS2Modal"> <div id="cc_actionModal">
<div id="threeDS2Container"></div> <div id="cc_actionContainer"></div>
</div> </div>
</div> </div>
......
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