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 6f6a2efe authored by cyattilakiss's avatar cyattilakiss Committed by GitHub

Merge pull request #452 from Adyen/develop

Release 4.2.0
parents 5b8e6426 296f8de9
...@@ -15,32 +15,20 @@ ...@@ -15,32 +15,20 @@
* *
* Adyen Payment Module * Adyen Payment Module
* *
* Copyright (c) 2018 Adyen B.V. * Copyright (c) 2019 Adyen B.V.
* This file is open source and available under the MIT license. * This file is open source and available under the MIT license.
* See the LICENSE file for more info. * See the LICENSE file for more info.
* *
* Author: Adyen <magento@adyen.com> * Author: Adyen <magento@adyen.com>
*/ */
namespace Adyen\Payment\Model; namespace Adyen\Payment\Api;
class AdyenPaymentInformationManagement extends \Magento\Checkout\Model\PaymentInformationManagement interface AdyenPaymentProcessInterface
{ {
/** /**
* {@inheritDoc} * @param string $payload
* @return string
*/ */
public function savePaymentInformationAndPlaceOrder( public function initiate($payload);
$cartId,
\Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
\Magento\Quote\Api\Data\AddressInterface $billingAddress = null
) {
$this->savePaymentInformation($cartId, $paymentMethod, $billingAddress);
try {
$orderId = $this->cartManagement->placeOrder($cartId);
} catch (\Exception $e) {
throw $e;
}
return $orderId;
}
} }
<?php
/**
* ######
* ######
* ############ ####( ###### #####. ###### ############ ############
* ############# #####( ###### #####. ###### ############# #############
* ###### #####( ###### #####. ###### ##### ###### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ##### ######
* ###### ###### #####( ###### #####. ###### ##### ##### ######
* ############# ############# ############# ############# ##### ######
* ############ ############ ############# ############ ##### ######
* ######
* #############
* ############
*
* Adyen Payment Module
*
* Copyright (c) 2019 Adyen B.V.
* This file is open source and available under the MIT license.
* See the LICENSE file for more info.
*
* Author: Adyen <magento@adyen.com>
*/
namespace Adyen\Payment\Api;
interface AdyenThreeDS2ProcessInterface
{
/**
* @param string $payload
* @return string
*/
public function initiate($payload);
}
...@@ -112,29 +112,6 @@ class Redirect extends \Magento\Payment\Block\Form ...@@ -112,29 +112,6 @@ class Redirect extends \Magento\Payment\Block\Form
$this->_request = $context->getRequest(); $this->_request = $context->getRequest();
} }
/**
* Returns if the payment should follow the old HPP or the new Checkout flow
* - hpp will submit a form with all the additional information that the API requests\
* - checkout will redirect to a url without form submission
*
* @return bool
* @throws \Exception
*/
public function isCheckoutAPM() {
try {
if ($paymentObject = $this->_order->getPayment()) {
if ($paymentObject->getAdditionalInformation('CheckoutAPM')) {
return true;
}
}
} catch (Exception $e) {
// do nothing for now
throw($e);
}
return false;
}
/** /**
* @return mixed|string[] * @return mixed|string[]
* @throws AdyenException * @throws AdyenException
......
...@@ -55,6 +55,13 @@ class TransactionPayment implements ClientInterface ...@@ -55,6 +55,13 @@ class TransactionPayment implements ClientInterface
public function placeRequest(\Magento\Payment\Gateway\Http\TransferInterface $transferObject) public function placeRequest(\Magento\Payment\Gateway\Http\TransferInterface $transferObject)
{ {
$request = $transferObject->getBody(); $request = $transferObject->getBody();
// If the payments call is already done return the request
if (!empty($request['resultCode'])) {
//Initiate has already a response
return $request;
}
$client = $this->adyenHelper->initializeAdyenClient(); $client = $this->adyenHelper->initializeAdyenClient();
$service = new \Adyen\Service\Checkout($client); $service = new \Adyen\Service\Checkout($client);
......
...@@ -31,20 +31,20 @@ use Magento\Payment\Gateway\Request\BuilderInterface; ...@@ -31,20 +31,20 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
class AddressDataBuilder implements BuilderInterface class AddressDataBuilder implements BuilderInterface
{ {
/** /**
* @var \Adyen\Payment\Helper\Data * @var \Adyen\Payment\Helper\Requests
*/ */
private $adyenHelper; private $adyenRequestsHelper;
/** /**
* AddressDataBuilder constructor. * AddressDataBuilder constructor.
* *
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/ */
public function __construct( public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper \Adyen\Payment\Helper\Requests $adyenRequestsHelper
) )
{ {
$this->adyenHelper = $adyenHelper; $this->adyenRequestsHelper = $adyenRequestsHelper;
} }
/** /**
...@@ -59,76 +59,8 @@ class AddressDataBuilder implements BuilderInterface ...@@ -59,76 +59,8 @@ class AddressDataBuilder implements BuilderInterface
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject); $paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$order = $paymentDataObject->getOrder(); $order = $paymentDataObject->getOrder();
$billingAddress = $order->getBillingAddress(); $billingAddress = $order->getBillingAddress();
$result = [];
if ($billingAddress) {
$requestBilling = [
"street" => "N/A",
"postalCode" => '',
"city" => "N/A",
"houseNumberOrName" => '',
"stateOrProvince" => '',
"country" => "ZZ"
];
$address = $this->adyenHelper->getStreetFromString($billingAddress->getStreetLine1());
if ($address) {
$requestBilling["street"] = $address["name"];
$requestBilling["houseNumberOrName"] = $address["house_number"];
}
if ($billingAddress->getPostcode()) {
$requestBilling["postalCode"] = $billingAddress->getPostcode();
}
if ($billingAddress->getCity()) {
$requestBilling["city"] = $billingAddress->getCity();
}
if ($billingAddress->getRegionCode()) {
$requestBilling["stateOrProvince"] = $billingAddress->getRegionCode();
}
if ($billingAddress->getCountryId()) {
$requestBilling["country"] = $billingAddress->getCountryId();
}
$result['billingAddress'] = $requestBilling;
}
$shippingAddress = $order->getShippingAddress(); $shippingAddress = $order->getShippingAddress();
if ($shippingAddress) { return $this->adyenRequestsHelper->buildAddressData([], $billingAddress, $shippingAddress);
$address = $this->adyenHelper->getStreetFromString($shippingAddress->getStreetLine1());
if ($address) {
$requestDelivery["street"] = $address["name"];
$requestDelivery["houseNumberOrName"] = $address["house_number"];
}
if ($shippingAddress->getPostcode()) {
$requestDelivery["postalCode"] = $shippingAddress->getPostcode();
}
if ($shippingAddress->getCity()) {
$requestDelivery["city"] = $shippingAddress->getCity();
}
if ($shippingAddress->getRegionCode()) {
$requestDelivery["stateOrProvince"] = $shippingAddress->getRegionCode();
}
if ($shippingAddress->getCountryId()) {
$requestDelivery["country"] = $shippingAddress->getCountryId();
}
$result['deliveryAddress'] = $requestDelivery;
}
return $result;
} }
} }
...@@ -29,18 +29,29 @@ use Magento\Payment\Gateway\Request\BuilderInterface; ...@@ -29,18 +29,29 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
*/ */
class BrowserInfoDataBuilder implements BuilderInterface class BrowserInfoDataBuilder implements BuilderInterface
{ {
/**
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenRequestsHelper;
/**
* BrowserInfoDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
public function __construct(
\Adyen\Payment\Helper\Requests $adyenRequestsHelper
)
{
$this->adyenRequestsHelper = $adyenRequestsHelper;
}
/** /**
* @param array $buildSubject * @param array $buildSubject
* @return array * @return array
*/ */
public function build(array $buildSubject) public function build(array $buildSubject)
{ {
return [ return $this->adyenRequestsHelper->buildBrowserData();
'browserInfo' =>
[
'userAgent' => $_SERVER['HTTP_USER_AGENT'],
'acceptHeader' => $_SERVER['HTTP_ACCEPT']
]
];
} }
} }
...@@ -102,7 +102,7 @@ class CaptureDataBuilder implements BuilderInterface ...@@ -102,7 +102,7 @@ class CaptureDataBuilder implements BuilderInterface
// The latest invoice will contain only the selected items(and quantities) for the (partial) capture // The latest invoice will contain only the selected items(and quantities) for the (partial) capture
$latestInvoice = $invoices->getLastItem(); $latestInvoice = $invoices->getLastItem();
foreach ($latestInvoice->getItemsCollection() as $invoiceItem) { foreach ($latestInvoice->getItems() as $invoiceItem) {
++$count; ++$count;
$numberOfItems = (int)$invoiceItem->getQty(); $numberOfItems = (int)$invoiceItem->getQty();
$formFields = $this->adyenHelper->createOpenInvoiceLineItem( $formFields = $this->adyenHelper->createOpenInvoiceLineItem(
...@@ -113,7 +113,7 @@ class CaptureDataBuilder implements BuilderInterface ...@@ -113,7 +113,7 @@ class CaptureDataBuilder implements BuilderInterface
$currency, $currency,
$invoiceItem->getTaxAmount(), $invoiceItem->getTaxAmount(),
$invoiceItem->getPriceInclTax(), $invoiceItem->getPriceInclTax(),
$invoiceItem->getTaxPercent(), $invoiceItem->getOrderItem()->getTaxPercent(),
$numberOfItems, $numberOfItems,
$payment, $payment,
$invoiceItem->getId() $invoiceItem->getId()
......
...@@ -24,91 +24,30 @@ ...@@ -24,91 +24,30 @@
namespace Adyen\Payment\Gateway\Request; namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface; use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
class CcAuthorizationDataBuilder implements BuilderInterface class CcAuthorizationDataBuilder implements BuilderInterface
{ {
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* @var \Magento\Framework\App\State
*/
private $appState;
/**
* CcAuthorizationDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Model\Context $context
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Model\Context $context
) {
$this->adyenHelper = $adyenHelper;
$this->appState = $context->getAppState();
}
/** /**
* @param array $buildSubject * @param array $buildSubject
* @return mixed * @return array|mixed
* @throws \Magento\Framework\Exception\LocalizedException
*/ */
public function build(array $buildSubject) public function build(array $buildSubject)
{ {
/** @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();
$order = $paymentDataObject->getOrder();
$storeId = $order->getStoreId();
$request = [];
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
$request['paymentMethod']['type'] = "scheme";
if ($cardNumber = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER)) {
$request['paymentMethod']['encryptedCardNumber'] = $cardNumber;
}
if ($expiryMonth = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH)) {
$request['paymentMethod']['encryptedExpiryMonth'] = $expiryMonth;
}
if ($expiryYear = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR)) {
$request['paymentMethod']['encryptedExpiryYear'] = $expiryYear;
}
if ($holderName = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME)) {
$request['paymentMethod']['holderName'] = $holderName;
}
if ($securityCode = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE)) {
$request['paymentMethod']['encryptedSecurityCode'] = $securityCode;
}
// retrieve payments response which we already got and saved in the payment controller
if ($response = $payment->getAdditionalInformation("paymentsResponse")) {
// the payments response needs to be passed to the next process because after this point we don't have
// access to the payment object therefore to the additionalInformation array
$request = $response;
// Remove from additional data // Remove from additional data
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER); $payment->unsAdditionalInformation("paymentsResponse");
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH); } else {
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR); $errorMsg = __('Error with payment method please select different payment method.');
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE); throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME);
/**
* if MOTO for backend is enabled use MOTO as shopper interaction type
*/
$enableMoto = $this->adyenHelper->getAdyenCcConfigDataFlag('enable_moto', $storeId);
if ($this->appState->getAreaCode() === \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE &&
$enableMoto
) {
$request['shopperInteraction'] = "Moto";
}
// if installments is set add it into the request
if ($payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS) &&
$payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS) > 0
) {
$request['installments']['value'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS);
} }
return $request; return $request;
......
<?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\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
class CcBackendAuthorizationDataBuilder implements BuilderInterface
{
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* @var \Magento\Framework\App\State
*/
private $appState;
/**
* CcAuthorizationDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Model\Context $context
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Framework\Model\Context $context
) {
$this->adyenHelper = $adyenHelper;
$this->appState = $context->getAppState();
}
/**
* @param array $buildSubject
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function build(array $buildSubject)
{
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$order = $paymentDataObject->getOrder();
$storeId = $order->getStoreId();
$request = [];
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
$request['paymentMethod']['type'] = 'scheme';
if ($cardNumber = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER)) {
$request['paymentMethod']['encryptedCardNumber'] = $cardNumber;
}
if ($expiryMonth = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH)) {
$request['paymentMethod']['encryptedExpiryMonth'] = $expiryMonth;
}
if ($expiryYear = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR)) {
$request['paymentMethod']['encryptedExpiryYear'] = $expiryYear;
}
if ($holderName = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME)) {
$request['paymentMethod']['holderName'] = $holderName;
}
if ($securityCode = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE)) {
$request['paymentMethod']['encryptedSecurityCode'] = $securityCode;
}
// Remove from additional data
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE);
$payment->unsAdditionalInformation(AdyenCcDataAssignObserver::HOLDER_NAME);
/**
* if MOTO for backend is enabled use MOTO as shopper interaction type
*/
$enableMoto = $this->adyenHelper->getAdyenCcConfigDataFlag('enable_moto', $storeId);
if ($this->appState->getAreaCode() === \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE &&
$enableMoto
) {
$request['shopperInteraction'] = "Moto";
}
// if installments is set add it into the request
if ($payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS) &&
$payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS) > 0
) {
$request['installments']['value'] = $payment->getAdditionalInformation(AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS);
}
return $request;
}
}
...@@ -219,15 +219,15 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -219,15 +219,15 @@ class CheckoutDataBuilder implements BuilderInterface
foreach ($this->quote->getAllVisibleItems() as $item) { foreach ($this->quote->getAllVisibleItems() as $item) {
$numberOfItems = (int)$item->getQtyOrdered(); $numberOfItems = (int)$item->getQty();
// Summarize the discount amount item by item // Summarize the discount amount item by item
$discountAmount += $item->getDiscountAmount(); $discountAmount += $item->getDiscountAmount();
$priceExcludingTax = $item->getPriceInclTax() - $item->getTaxAmount(); $formattedPriceExcludingTax = $this->adyenHelper->formatAmount($item->getPrice(), $currency);
$formattedPriceExcludingTax = $this->adyenHelper->formatAmount($priceExcludingTax, $currency);
$formattedTaxAmount = $this->adyenHelper->formatAmount($item->getTaxAmount(), $currency); $taxAmount = $item->getPrice() * ($item->getTaxPercent() / 100);
$formattedTaxAmount = $this->adyenHelper->formatAmount($taxAmount, $currency);
$formattedTaxPercentage = $item->getTaxPercent() * 100; $formattedTaxPercentage = $item->getTaxPercent() * 100;
$formFields['lineItems'][] = [ $formFields['lineItems'][] = [
...@@ -236,7 +236,7 @@ class CheckoutDataBuilder implements BuilderInterface ...@@ -236,7 +236,7 @@ class CheckoutDataBuilder implements BuilderInterface
'amountExcludingTax' => $formattedPriceExcludingTax, 'amountExcludingTax' => $formattedPriceExcludingTax,
'taxAmount' => $formattedTaxAmount, 'taxAmount' => $formattedTaxAmount,
'description' => $item->getName(), 'description' => $item->getName(),
'quantity' => $item->getQty(), 'quantity' => $numberOfItems,
'taxCategory' => $item->getProduct()->getAttributeText('tax_class_id'), 'taxCategory' => $item->getProduct()->getAttributeText('tax_class_id'),
'taxPercentage' => $formattedTaxPercentage 'taxPercentage' => $formattedTaxPercentage
]; ];
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
namespace Adyen\Payment\Gateway\Request; namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface; use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
/** /**
* Class CustomerDataBuilder * Class CustomerDataBuilder
...@@ -31,20 +30,20 @@ use Adyen\Payment\Observer\AdyenHppDataAssignObserver; ...@@ -31,20 +30,20 @@ use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
class CustomerDataBuilder implements BuilderInterface class CustomerDataBuilder implements BuilderInterface
{ {
/** /**
* @var \Adyen\Payment\Helper\Data * @var \Adyen\Payment\Helper\Requests
*/ */
private $adyenHelper; private $adyenRequestsHelper;
/** /**
* CustomerDataBuilder constructor. * CustomerDataBuilder constructor.
* *
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/ */
public function __construct( public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper \Adyen\Payment\Helper\Requests $adyenRequestsHelper
) )
{ {
$this->adyenHelper = $adyenHelper; $this->adyenRequestsHelper = $adyenRequestsHelper;
} }
/** /**
...@@ -55,69 +54,14 @@ class CustomerDataBuilder implements BuilderInterface ...@@ -55,69 +54,14 @@ class CustomerDataBuilder implements BuilderInterface
*/ */
public function build(array $buildSubject) public function build(array $buildSubject)
{ {
$result = [];
/** @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);
$order = $paymentDataObject->getOrder(); $order = $paymentDataObject->getOrder();
$payment = $paymentDataObject->getPayment(); $payment = $paymentDataObject->getPayment();
$customerId = $order->getCustomerId(); $customerId = $order->getCustomerId();
if ($customerId > 0) {
$result['shopperReference'] = $customerId;
}
$billingAddress = $order->getBillingAddress(); $billingAddress = $order->getBillingAddress();
$storeId = $order->getStoreId();
if (!empty($billingAddress)) { return $this->adyenRequestsHelper->buildCustomerData([], $customerId, $billingAddress, $storeId, $payment);
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
) && !$this->adyenHelper->isPaymentMethodAfterpayTouchMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
)) {
if ($customerEmail = $billingAddress->getEmail()) {
$result['paymentMethod']['personalDetails']['shopperEmail'] = $customerEmail;
}
if ($customerTelephone = trim($billingAddress->getTelephone())) {
$result['paymentMethod']['personalDetails']['telephoneNumber'] = $customerTelephone;
}
if ($firstName = $billingAddress->getFirstname()) {
$result['paymentMethod']['personalDetails']['firstName'] = $firstName;
}
if ($lastName = $billingAddress->getLastname()) {
$result['paymentMethod']['personalDetails']['lastName'] = $lastName;
}
} else {
if ($customerEmail = $billingAddress->getEmail()) {
$result['shopperEmail'] = $customerEmail;
}
if ($customerTelephone = trim($billingAddress->getTelephone())) {
$result['telephoneNumber'] = $customerTelephone;
}
if ($firstName = $billingAddress->getFirstname()) {
$result['shopperName']['firstName'] = $firstName;
}
if ($lastName = $billingAddress->getLastname()) {
$result['shopperName']['lastName'] = $lastName;
}
}
if ($countryId = $billingAddress->getCountryId()) {
$result['countryCode'] = $countryId;
}
if ($shopperLocale = $this->adyenHelper->getCurrentLocaleCode($order->getStoreId())) {
$result['shopperLocale'] = $shopperLocale;
}
}
return $result;
} }
} }
...@@ -29,6 +29,21 @@ use Magento\Payment\Gateway\Request\BuilderInterface; ...@@ -29,6 +29,21 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
*/ */
class CustomerIpDataBuilder implements BuilderInterface class CustomerIpDataBuilder implements BuilderInterface
{ {
/**
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenRequestsHelper;
/**
* CustomerIpDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
public function __construct(\Adyen\Payment\Helper\Requests $adyenRequestsHelper)
{
$this->adyenRequestsHelper = $adyenRequestsHelper;
}
/** /**
* @param array $buildSubject * @param array $buildSubject
* @return array * @return array
...@@ -38,6 +53,7 @@ class CustomerIpDataBuilder implements BuilderInterface ...@@ -38,6 +53,7 @@ class CustomerIpDataBuilder 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);
$order = $paymentDataObject->getOrder(); $order = $paymentDataObject->getOrder();
return ['shopperIP' => $order->getRemoteIp()];
return $this->adyenRequestsHelper->buildCustomerIpData([], $order->getRemoteIp());
} }
} }
...@@ -28,19 +28,19 @@ use Magento\Payment\Gateway\Request\BuilderInterface; ...@@ -28,19 +28,19 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
class MerchantAccountDataBuilder implements BuilderInterface class MerchantAccountDataBuilder implements BuilderInterface
{ {
/** /**
* @var \Adyen\Payment\Helper\Data * @var \Adyen\Payment\Helper\Requests
*/ */
private $adyenHelper; private $adyenRequestsHelper;
/** /**
* RecurringDataBuilder constructor. * MerchantAccountDataBuilder constructor.
* *
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/ */
public function __construct( public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper \Adyen\Payment\Helper\Requests $adyenRequestsHelper
) { ) {
$this->adyenHelper = $adyenHelper; $this->adyenRequestsHelper = $adyenRequestsHelper;
} }
/** /**
...@@ -52,12 +52,10 @@ class MerchantAccountDataBuilder implements BuilderInterface ...@@ -52,12 +52,10 @@ class MerchantAccountDataBuilder 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);
$order = $paymentDataObject->getOrder(); $order = $paymentDataObject->getOrder();
$storeId = $order->getStoreId();
$payment = $paymentDataObject->getPayment(); $payment = $paymentDataObject->getPayment();
$storeId = $order->getStoreId();
$method = $payment->getMethod(); $method = $payment->getMethod();
$merchantAccount = $this->adyenHelper->getAdyenMerchantAccount($method, $storeId); return $this->adyenRequestsHelper->buildMerchantAccountData([], $method, $storeId);
return ["merchantAccount" => $merchantAccount];
} }
} }
...@@ -29,20 +29,19 @@ use Magento\Payment\Gateway\Request\BuilderInterface; ...@@ -29,20 +29,19 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
*/ */
class PaymentDataBuilder implements BuilderInterface class PaymentDataBuilder implements BuilderInterface
{ {
/** /**
* @var \Adyen\Payment\Helper\Data * @var \Adyen\Payment\Helper\Requests
*/ */
private $adyenHelper; private $adyenRequestsHelper;
/** /**
* PaymentDataBuilder constructor. * PaymentDataBuilder constructor.
* *
* @param \Adyen\Payment\Helper\Data $adyenHelper * @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/ */
public function __construct(\Adyen\Payment\Helper\Data $adyenHelper) public function __construct(\Adyen\Payment\Helper\Requests $adyenRequestsHelper)
{ {
$this->adyenHelper = $adyenHelper; $this->adyenRequestsHelper = $adyenRequestsHelper;
} }
/** /**
...@@ -60,14 +59,8 @@ class PaymentDataBuilder implements BuilderInterface ...@@ -60,14 +59,8 @@ class PaymentDataBuilder implements BuilderInterface
$currencyCode = $fullOrder->getOrderCurrencyCode(); $currencyCode = $fullOrder->getOrderCurrencyCode();
$amount = $fullOrder->getGrandTotal(); $amount = $fullOrder->getGrandTotal();
$reference = $order->getOrderIncrementId();
$amount = ['currency' => $currencyCode, return $this->adyenRequestsHelper->buildPaymentData([], $amount, $currencyCode, $reference);
'value' => $this->adyenHelper->formatAmount($amount, $currencyCode)];
return [
"amount" => $amount,
"reference" => $order->getOrderIncrementId(),
"fraudOffset" => "0"
];
} }
} }
...@@ -28,27 +28,27 @@ use Magento\Payment\Gateway\Request\BuilderInterface; ...@@ -28,27 +28,27 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
class RecurringDataBuilder implements BuilderInterface class RecurringDataBuilder implements BuilderInterface
{ {
/** /**
* @var \Adyen\Payment\Helper\Data * @var \Magento\Framework\App\State
*/ */
private $adyenHelper; private $appState;
/** /**
* @var \Magento\Framework\App\State * @var \Adyen\Payment\Helper\Requests
*/ */
private $appState; private $adyenRequestsHelper;
/** /**
* RecurringDataBuilder constructor. * RecurringDataBuilder constructor.
* *
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Model\Context $context
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/ */
public function __construct( public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper, \Magento\Framework\Model\Context $context,
\Magento\Framework\Model\Context $context \Adyen\Payment\Helper\Requests $adyenRequestsHelper
) { ) {
$this->adyenHelper = $adyenHelper;
$this->appState = $context->getAppState(); $this->appState = $context->getAppState();
$this->adyenRequestsHelper = $adyenRequestsHelper;
} }
...@@ -59,39 +59,12 @@ class RecurringDataBuilder implements BuilderInterface ...@@ -59,39 +59,12 @@ class RecurringDataBuilder implements BuilderInterface
*/ */
public function build(array $buildSubject) public function build(array $buildSubject)
{ {
$result = [];
// If the vault feature is on this logic is handled in the VaultDataBuilder
if (!$this->adyenHelper->isCreditCardVaultEnabled()) {
/** @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();
$storeId = null;
if ($this->appState->getAreaCode() === \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE) {
$storeId = $payment->getOrder()->getStoreId(); $storeId = $payment->getOrder()->getStoreId();
} $areaCode = $this->appState->getAreaCode();
$enableOneclick = $this->adyenHelper->getAdyenAbstractConfigData('enable_oneclick', $storeId);
$enableRecurring = $this->adyenHelper->getAdyenAbstractConfigData('enable_recurring', $storeId);
if ($enableOneclick) {
$result['enableOneClick'] = true;
} else {
$result['enableOneClick'] = false;
}
if ($enableRecurring) {
$result['enableRecurring'] = true;
} else {
$result['enableRecurring'] = false;
}
if ($payment->getAdditionalInformation('store_cc') === '1') {
$result['paymentMethod']['storeDetails'] = true;
}
}
return $result; return $this->adyenRequestsHelper->buildRecurringData([], $areaCode, $storeId, $payment);
} }
} }
...@@ -177,7 +177,10 @@ class RefundDataBuilder implements BuilderInterface ...@@ -177,7 +177,10 @@ class RefundDataBuilder implements BuilderInterface
return $result; return $result;
} }
/**
* @param \Magento\Payment\Model\InfoInterface $payment
* @return array|mixed
*/
protected function getOpenInvoiceData($payment) protected function getOpenInvoiceData($payment)
{ {
$formFields = []; $formFields = [];
...@@ -185,11 +188,11 @@ class RefundDataBuilder implements BuilderInterface ...@@ -185,11 +188,11 @@ class RefundDataBuilder implements BuilderInterface
$currency = $payment->getOrder()->getOrderCurrencyCode(); $currency = $payment->getOrder()->getOrderCurrencyCode();
/** /**
* Magento\Sales\Model\Order\Creditmemo * @var \Magento\Sales\Model\Order\Creditmemo $creditMemo
*/ */
$creditMemo = $payment->getCreditMemo(); $creditMemo = $payment->getCreditMemo();
foreach ($creditMemo->getAllItems() as $refundItem) { foreach ($creditMemo->getItems() as $refundItem) {
++$count; ++$count;
$numberOfItems = (int)$refundItem->getQty(); $numberOfItems = (int)$refundItem->getQty();
...@@ -201,7 +204,7 @@ class RefundDataBuilder implements BuilderInterface ...@@ -201,7 +204,7 @@ class RefundDataBuilder implements BuilderInterface
$currency, $currency,
$refundItem->getTaxAmount(), $refundItem->getTaxAmount(),
$refundItem->getPriceInclTax(), $refundItem->getPriceInclTax(),
$refundItem->getTaxPercent(), $refundItem->getOrderItem()->getTaxPercent(),
$numberOfItems, $numberOfItems,
$payment, $payment,
$refundItem->getId() $refundItem->getId()
......
...@@ -24,17 +24,23 @@ ...@@ -24,17 +24,23 @@
namespace Adyen\Payment\Gateway\Request; namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface; use Magento\Payment\Gateway\Request\BuilderInterface;
use Magento\Vault\Model\Ui\VaultConfigProvider;
use \Magento\Payment\Gateway\Helper\SubjectReader;
class VaultDataBuilder implements BuilderInterface class VaultDataBuilder implements BuilderInterface
{ {
/**
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenRequestsHelper;
/** /**
* Recurring variable * VaultDataBuilder constructor.
* @var string *
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/ */
private static $enableRecurring = 'enableRecurring'; public function __construct(\Adyen\Payment\Helper\Requests $adyenRequestsHelper)
{
$this->adyenRequestsHelper = $adyenRequestsHelper;
}
/** /**
* @param array $buildSubject * @param array $buildSubject
...@@ -43,21 +49,11 @@ class VaultDataBuilder implements BuilderInterface ...@@ -43,21 +49,11 @@ class VaultDataBuilder implements BuilderInterface
public function build(array $buildSubject) public function build(array $buildSubject)
{ {
// vault is enabled and shopper provided consent to store card this logic is triggered // vault is enabled and shopper provided consent to store card this logic is triggered
$request = []; /** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDO = SubjectReader::readPayment($buildSubject); $paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$payment = $paymentDO->getPayment(); $additionalInformation = $payment->getAdditionalInformation();
$data = $payment->getAdditionalInformation();
if (!empty($data[VaultConfigProvider::IS_ACTIVE_CODE]) && return $this->adyenRequestsHelper->buildVaultData([], $additionalInformation);
$data[VaultConfigProvider::IS_ACTIVE_CODE] === true
) {
// store it only as oneclick otherwise we store oneclick tokens (maestro+bcmc) that will fail
$request[self::$enableRecurring] = true;
} else {
// explicity turn this off as merchants have recurring on by default
$request[self::$enableRecurring] = false;
}
return $request;
} }
} }
...@@ -48,10 +48,9 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface ...@@ -48,10 +48,9 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface
*/ */
public function handle(array $handlingSubject, array $response) public function handle(array $handlingSubject, array $response)
{ {
$payment = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($handlingSubject); $paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($handlingSubject);
/** @var OrderPaymentInterface $payment */ $payment = $paymentDataObject->getPayment();
$payment = $payment->getPayment();
// set transaction not to processing by default wait for notification // set transaction not to processing by default wait for notification
$payment->setIsTransactionPending(true); $payment->setIsTransactionPending(true);
...@@ -69,7 +68,8 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface ...@@ -69,7 +68,8 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface
} }
if (!empty($response['additionalData']['recurring.recurringDetailReference']) && if (!empty($response['additionalData']['recurring.recurringDetailReference']) &&
!$this->adyenHelper->isCreditCardVaultEnabled() !$this->adyenHelper->isCreditCardVaultEnabled() &&
$payment->getMethodInstance()->getCode() !== \Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider::CODE
) { ) {
$order = $payment->getOrder(); $order = $payment->getOrder();
$this->adyenHelper->createAdyenBillingAgreement($order, $response['additionalData']); $this->adyenHelper->createAdyenBillingAgreement($order, $response['additionalData']);
......
...@@ -80,6 +80,9 @@ class CheckoutResponseValidator extends AbstractValidator ...@@ -80,6 +80,9 @@ class CheckoutResponseValidator extends AbstractValidator
} }
} }
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
break;
case "Received":
$payment->setAdditionalInformation('pspReference', $response['pspReference']); $payment->setAdditionalInformation('pspReference', $response['pspReference']);
break; break;
case "PresentToShopper": case "PresentToShopper":
......
<?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\Gateway\Validator;
use Magento\Payment\Gateway\Validator\AbstractValidator;
class ThreeDS2ResponseValidator extends AbstractValidator
{
/**
* GeneralResponseValidator constructor.
*
* @param \Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
*/
public function __construct(
\Magento\Payment\Gateway\Validator\ResultInterfaceFactory $resultFactory
) {
parent::__construct($resultFactory);
}
/**
* @param array $validationSubject
* @return \Magento\Payment\Gateway\Validator\ResultInterface
*/
public function validate(array $validationSubject)
{
$response = \Magento\Payment\Gateway\Helper\SubjectReader::readResponse($validationSubject);
if (!empty($validationSubject['payment'])) {
$payment = $validationSubject['payment'];
} else {
$errorMsg = __('Error with payment method during validation please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
$isValid = true;
$errorMessages = [];
// validate result
if (!empty($response['resultCode'])) {
// 3DS2.0 should have IdentifyShopper or ChallengeShopper as a resultCode
if ($response['resultCode'] == "IdentifyShopper" &&
!empty($response['authentication']['threeds2.fingerprintToken'])
) {
$payment->setAdditionalInformation('threeDS2Type', $response['resultCode']);
$payment->setAdditionalInformation('threeDS2Token', $response['authentication']['threeds2.fingerprintToken']);
$payment->setAdditionalInformation('threeDS2PaymentData', $response['paymentData']);
} elseif ($response['resultCode'] == "ChallengeShopper" &&
!empty($response['authentication']['threeds2.challengeToken'])
) {
$payment->setAdditionalInformation('threeDS2Type', $response['resultCode']);
$payment->setAdditionalInformation('threeDS2Token', $response['authentication']['threeds2.challengeToken']);
$payment->setAdditionalInformation('threeDS2PaymentData', $response['paymentData']);
} else {
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
} else {
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
return $this->createResult($isValid, $errorMessages);
}
}
...@@ -35,8 +35,8 @@ class Data extends AbstractHelper ...@@ -35,8 +35,8 @@ class Data extends AbstractHelper
const LIVE = 'live'; const LIVE = 'live';
const CHECKOUT_CONTEXT_URL_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/'; const CHECKOUT_CONTEXT_URL_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/';
const CHECKOUT_CONTEXT_URL_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/'; const CHECKOUT_CONTEXT_URL_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/';
const CHECKOUT_COMPONENT_JS_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/2.1.0/adyen.js'; const CHECKOUT_COMPONENT_JS_LIVE = 'https://checkoutshopper-live.adyen.com/checkoutshopper/sdk/2.5.0/adyen.js';
const CHECKOUT_COMPONENT_JS_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/2.1.0/adyen.js'; const CHECKOUT_COMPONENT_JS_TEST = 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/2.5.0/adyen.js';
/** /**
* @var \Magento\Framework\Encryption\EncryptorInterface * @var \Magento\Framework\Encryption\EncryptorInterface
...@@ -371,7 +371,7 @@ class Data extends AbstractHelper ...@@ -371,7 +371,7 @@ class Data extends AbstractHelper
*/ */
public function getStreetFromString($streetLine) public function getStreetFromString($streetLine)
{ {
$street = self::formatStreet(array($streetLine)); $street = self::formatStreet([$streetLine]);
$streetName = $street['0']; $streetName = $street['0'];
unset($street['0']); unset($street['0']);
$streetNr = implode(' ', $street); $streetNr = implode(' ', $street);
...@@ -449,10 +449,10 @@ class Data extends AbstractHelper ...@@ -449,10 +449,10 @@ class Data extends AbstractHelper
} }
/** /**
* Gives back adyen_cc configuration values as flag * Gives back adyen_cc_vault configuration values as flag
* *
* @param $field * @param $field
* @param null $storeId * @param int|null $storeId
* @return mixed * @return mixed
*/ */
public function getAdyenCcVaultConfigDataFlag($field, $storeId = null) public function getAdyenCcVaultConfigDataFlag($field, $storeId = null)
...@@ -460,6 +460,18 @@ class Data extends AbstractHelper ...@@ -460,6 +460,18 @@ class Data extends AbstractHelper
return $this->getConfigData($field, 'adyen_cc_vault', $storeId, true); return $this->getConfigData($field, 'adyen_cc_vault', $storeId, true);
} }
/**
* Gives back adyen_cc_threeds2 configuration values as flag
*
* @param $field
* @param null $storeId
* @return mixed
*/
public function getAdyenCcThreeDS2ConfigDataFlag($field, $storeId = null)
{
return $this->getConfigData($field, 'adyen_cc_threeds2', $storeId, true);
}
/** /**
* Gives back adyen_hpp configuration values * Gives back adyen_hpp configuration values
* *
...@@ -1110,6 +1122,15 @@ class Data extends AbstractHelper ...@@ -1110,6 +1122,15 @@ class Data extends AbstractHelper
return $this->scopeConfig->getValue($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId); return $this->scopeConfig->getValue($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId);
} }
/**
* Format Magento locale codes with undersocre to ISO locale codes with dash
* @param $localeCode
*/
public function formatLocaleCode($localeCode)
{
return str_replace("_", "-", $localeCode);
}
public function getApplePayShippingTypes() public function getApplePayShippingTypes()
{ {
return [ return [
...@@ -1348,11 +1369,15 @@ class Data extends AbstractHelper ...@@ -1348,11 +1369,15 @@ class Data extends AbstractHelper
* return the merchant account name defined in required settings. * return the merchant account name defined in required settings.
* *
* @param $paymentMethod * @param $paymentMethod
* @param int $storeId * @param int|null $storeId
* @return string * @return string
*/ */
public function getAdyenMerchantAccount($paymentMethod, $storeId) public function getAdyenMerchantAccount($paymentMethod, $storeId = null)
{ {
if (!$storeId) {
$storeId = $this->storeManager->getStore()->getId();
}
$merchantAccount = $this->getAdyenAbstractConfigData("merchant_account", $storeId); $merchantAccount = $this->getAdyenAbstractConfigData("merchant_account", $storeId);
$merchantAccountPos = $this->getAdyenPosCloudConfigData('pos_merchant_account', $storeId); $merchantAccountPos = $this->getAdyenPosCloudConfigData('pos_merchant_account', $storeId);
...@@ -1452,6 +1477,16 @@ class Data extends AbstractHelper ...@@ -1452,6 +1477,16 @@ class Data extends AbstractHelper
return new \Adyen\Client(); return new \Adyen\Client();
} }
/**
* @return string
*/
public function getOrigin() {
$baseUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_WEB);
$parsed = parse_url($baseUrl);
$origin = $parsed['scheme'] . "://" . $parsed['host'];
return $origin;
}
/** /**
* Retrieve origin keys for platform's base url * Retrieve origin keys for platform's base url
* *
...@@ -1460,15 +1495,13 @@ class Data extends AbstractHelper ...@@ -1460,15 +1495,13 @@ class Data extends AbstractHelper
*/ */
public function getOriginKeyForBaseUrl() public function getOriginKeyForBaseUrl()
{ {
$baseUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_WEB); $origin = $this->getOrigin();
$parsed = parse_url($baseUrl);
$domain = $parsed['scheme'] . "://" . $parsed['host'];
$storeId = $this->storeManager->getStore()->getId(); $storeId = $this->storeManager->getStore()->getId();
$cacheKey = 'Adyen_origin_key_for_' . $domain . '_' . $storeId; $cacheKey = 'Adyen_origin_key_for_' . $origin . '_' . $storeId;
if (!$originKey = $this->cache->load($cacheKey)) { if (!$originKey = $this->cache->load($cacheKey)) {
if ($originKey = $this->getOriginKeyForUrl($domain, $storeId)) { if ($originKey = $this->getOriginKeyForOrigin($origin, $storeId)) {
$this->cache->save($originKey, $cacheKey, array(), 60 * 60 * 24); $this->cache->save($originKey, $cacheKey, [], 60 * 60 * 24);
} }
} }
...@@ -1476,20 +1509,20 @@ class Data extends AbstractHelper ...@@ -1476,20 +1509,20 @@ class Data extends AbstractHelper
} }
/** /**
* Get origin key for a specific url using the adyen api library client * Get origin key for a specific origin using the adyen api library client
* *
* @param $url * @param $origin
* @param int|null $storeId * @param int|null $storeId
* @return string * @return string
* @throws \Adyen\AdyenException * @throws \Adyen\AdyenException
*/ */
private function getOriginKeyForUrl($url, $storeId = null) private function getOriginKeyForOrigin($origin, $storeId = null)
{ {
$params = array( $params = [
"originDomains" => array( "originDomains" => [
$url $origin
) ]
); ];
$client = $this->initializeAdyenClient($storeId); $client = $this->initializeAdyenClient($storeId);
...@@ -1502,8 +1535,8 @@ class Data extends AbstractHelper ...@@ -1502,8 +1535,8 @@ class Data extends AbstractHelper
$originKey = ""; $originKey = "";
if (!empty($response['originKeys'][$url])) { if (!empty($response['originKeys'][$origin])) {
$originKey = $response['originKeys'][$url]; $originKey = $response['originKeys'][$origin];
} }
return $originKey; return $originKey;
...@@ -1580,7 +1613,8 @@ class Data extends AbstractHelper ...@@ -1580,7 +1613,8 @@ class Data extends AbstractHelper
// Populate billing agreement data // Populate billing agreement data
$storeOneClick = $order->getPayment()->getAdditionalInformation('store_cc'); $storeOneClick = $order->getPayment()->getAdditionalInformation('store_cc');
$billingAgreement->setCcBillingAgreement($additionalData, $storeOneClick);
$billingAgreement->setCcBillingAgreement($additionalData, $storeOneClick, $order->getStoreId());
if ($billingAgreement->isValid()) { if ($billingAgreement->isValid()) {
if (!$this->agreementResourceModel->getOrderRelation($billingAgreement->getAgreementId(), if (!$this->agreementResourceModel->getOrderRelation($billingAgreement->getAgreementId(),
...@@ -1658,7 +1692,6 @@ class Data extends AbstractHelper ...@@ -1658,7 +1692,6 @@ class Data extends AbstractHelper
return $icon; return $icon;
} }
/** /**
* Check if CreditCard vault is enabled * Check if CreditCard vault is enabled
* *
...@@ -1682,6 +1715,16 @@ class Data extends AbstractHelper ...@@ -1682,6 +1715,16 @@ class Data extends AbstractHelper
return in_array(strtolower($country), $countryList); return in_array(strtolower($country), $countryList);
} }
/**
* Check if 3DS2.0 is enabled for credit cards
*
* @param int|null $storeId
* @return mixed
*/
public function isCreditCardThreeDS2Enabled($storeId = null)
{
return $this->getAdyenCcThreeDS2ConfigDataFlag('active', $storeId);
}
/** /**
* @param $client * @param $client
...@@ -1716,6 +1759,26 @@ class Data extends AbstractHelper ...@@ -1716,6 +1759,26 @@ class Data extends AbstractHelper
return $timeStamp->format($format); return $timeStamp->format($format);
} }
/**
* @param string|null $type
* @param string|null $token
* @return string
*/
public function buildThreeDS2ProcessResponseJson($type = null, $token = null)
{
$response = ['threeDS2' => false];
if ($type && $token) {
$response = [
"threeDS2" => true,
"type" => $type,
"token" => $token
];
}
return json_encode($response);
}
/** /**
* @param int $storeId * @param int $storeId
* @return mixed|string * @return mixed|string
......
<?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\Helper;
use Adyen\Payment\Observer\AdyenOneclickDataAssignObserver;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Vault\Model\Ui\VaultConfigProvider;
use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
use Magento\Quote\Api\Data\PaymentInterface;
class Requests extends AbstractHelper
{
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* Requests constructor.
*
* @param Data $adyenHelper
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper
) {
$this->adyenHelper = $adyenHelper;
}
/**
* @param $request
* @param $paymentMethod
* @param $storeId
* @return mixed
*/
public function buildMerchantAccountData($request = [], $paymentMethod, $storeId)
{
// Retrieve merchant account
$merchantAccount = $this->adyenHelper->getAdyenMerchantAccount($paymentMethod, $storeId);
// Assign merchant account to request object
$request['merchantAccount'] = $merchantAccount;
return $request;
}
/**
* @param $request
* @param int $customerId
* @param $billingAddress
* @return mixed
*/
public function buildCustomerData($request = [], $customerId = 0, $billingAddress, $storeId, $payment = null)
{
if ($customerId > 0) {
$request['shopperReference'] = $customerId;
}
$paymentMethod = '';
if ($payment) {
$paymentMethod = $payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE);
}
if (!empty($billingAddress)) {
// Openinvoice (klarna and afterpay BUT not afterpay touch) methods requires different request format
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod($paymentMethod) &&
!$this->adyenHelper->isPaymentMethodAfterpayTouchMethod($paymentMethod)
) {
if ($customerEmail = $billingAddress->getEmail()) {
$request['paymentMethod']['personalDetails']['shopperEmail'] = $customerEmail;
}
if ($customerTelephone = trim($billingAddress->getTelephone())) {
$request['paymentMethod']['personalDetails']['telephoneNumber'] = $customerTelephone;
}
if ($firstName = $billingAddress->getFirstname()) {
$request['paymentMethod']['personalDetails']['firstName'] = $firstName;
}
if ($lastName = $billingAddress->getLastname()) {
$request['paymentMethod']['personalDetails']['lastName'] = $lastName;
}
} else {
if ($customerEmail = $billingAddress->getEmail()) {
$request['shopperEmail'] = $customerEmail;
}
if ($customerTelephone = trim($billingAddress->getTelephone())) {
$request['telephoneNumber'] = $customerTelephone;
}
if ($firstName = $billingAddress->getFirstname()) {
$request['shopperName']['firstName'] = $firstName;
}
if ($lastName = $billingAddress->getLastname()) {
$request['shopperName']['lastName'] = $lastName;
}
}
if ($countryId = $billingAddress->getCountryId()) {
$request['countryCode'] = $countryId;
}
$request['shopperLocale'] = $this->adyenHelper->getCurrentLocaleCode($storeId);
}
return $request;
}
/**
* @param $request
* @param $ipAddress
* @return mixed
*/
public function buildCustomerIpData($request = [], $ipAddress)
{
$request['shopperIP'] = $ipAddress;
return $request;
}
/**
* @param $request
* @param $billingAddress
* @param $shippingAddress
* @return mixed
*/
public function buildAddressData($request = [], $billingAddress, $shippingAddress)
{
if ($billingAddress) {
// Billing address defaults
$requestBillingDefaults = [
"street" => "N/A",
"postalCode" => '',
"city" => "N/A",
"houseNumberOrName" => '',
"country" => "ZZ"
];
// Save the defaults for later to compare if anything has changed
$requestBilling = $requestBillingDefaults;
$address = $this->getStreetStringFromAddress($billingAddress);
if (!empty($address["name"])) {
$requestBilling["street"] = $address["name"];
}
if (!empty($address["house_number"])) {
$requestBilling["houseNumberOrName"] = $address["house_number"];
}
if (!empty($billingAddress->getPostcode())) {
$requestBilling["postalCode"] = $billingAddress->getPostcode();
}
if (!empty($billingAddress->getCity())) {
$requestBilling["city"] = $billingAddress->getCity();
}
if (!empty($billingAddress->getRegionCode())) {
$requestBilling["stateOrProvince"] = $billingAddress->getRegionCode();
}
if (!empty($billingAddress->getCountryId())) {
$requestBilling["country"] = $billingAddress->getCountryId();
}
// If nothing is changed which means delivery address is not filled
if ($requestBilling !== $requestBillingDefaults) {
$request['billingAddress'] = $requestBilling;
}
}
if ($shippingAddress) {
// Delivery address defaults
$requestDeliveryDefaults = [
"street" => "N/A",
"postalCode" => '',
"city" => "N/A",
"houseNumberOrName" => '',
"country" => "ZZ"
];
// Save the defaults for later to compare if anything has changed
$requestDelivery = $requestDeliveryDefaults;
// Parse address into street and house number where possible
$address = $this->getStreetStringFromAddress($shippingAddress);
if (!empty($address['name'])) {
$requestDelivery["street"] = $address["name"];
}
if (!empty($address["house_number"])) {
$requestDelivery["houseNumberOrName"] = $address["house_number"];
}
if (!empty($shippingAddress->getPostcode())) {
$requestDelivery["postalCode"] = $shippingAddress->getPostcode();
}
if (!empty($shippingAddress->getCity())) {
$requestDelivery["city"] = $shippingAddress->getCity();
}
if (!empty($shippingAddress->getRegionCode())) {
$requestDelivery["stateOrProvince"] = $shippingAddress->getRegionCode();
}
if (!empty($shippingAddress->getCountryId())) {
$requestDelivery["country"] = $shippingAddress->getCountryId();
}
// If nothing is changed which means delivery address is not filled
if ($requestDelivery !== $requestDeliveryDefaults) {
$request['deliveryAddress'] = $requestDelivery;
}
}
return $request;
}
/**
* @param $request
* @param $amount
* @param $currencyCode
* @param $reference
* @return mixed
*/
public function buildPaymentData($request = [], $amount, $currencyCode, $reference)
{
$request['amount'] = [
'currency' => $currencyCode,
'value' => $this->adyenHelper->formatAmount($amount, $currencyCode)
];
$request["reference"] = $reference;
$request["fraudOffset"] = "0";
return $request;
}
/**
* @param array $request
* @return array
*/
public function buildBrowserData($request = [])
{
$request['browserInfo'] = [
'userAgent' => $_SERVER['HTTP_USER_AGENT'],
'acceptHeader' => $_SERVER['HTTP_ACCEPT']
];
return $request;
}
/**
* @param array $request
* @param $payment
* @param $store
* @return array
*/
public function buildThreeDS2Data($request = [], $payload, $store)
{
$request['additionalData']['allow3DS2'] = true;
$request['origin'] = $this->adyenHelper->getOrigin();
$request['channel'] = 'web';
$request['browserInfo']['screenWidth'] = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::SCREEN_WIDTH];
$request['browserInfo']['screenHeight'] = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::SCREEN_HEIGHT];
$request['browserInfo']['colorDepth'] = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::SCREEN_COLOR_DEPTH];
$request['browserInfo']['timeZoneOffset'] = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::TIMEZONE_OFFSET];
$request['browserInfo']['language'] = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::LANGUAGE];
if ($javaEnabled = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::JAVA_ENABLED]) {
$request['browserInfo']['javaEnabled'] = $javaEnabled;
} else {
$request['browserInfo']['javaEnabled'] = false;
}
return $request;
}
/**
* @param $request
* @param $areaCode
* @param $storeId
* @param $payment
*/
public function buildRecurringData($request = [], $areaCode, int $storeId, $payload)
{
// If the vault feature is on this logic is handled in the VaultDataBuilder
if (!$this->adyenHelper->isCreditCardVaultEnabled()) {
if ($areaCode !== \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE) {
$storeId = null;
}
$enableOneclick = $this->adyenHelper->getAdyenAbstractConfigData('enable_oneclick', $storeId);
$enableRecurring = $this->adyenHelper->getAdyenAbstractConfigData('enable_recurring', $storeId);
if ($enableOneclick) {
$request['enableOneClick'] = true;
} else {
$request['enableOneClick'] = false;
}
if ($enableRecurring) {
$request['enableRecurring'] = true;
} else {
$request['enableRecurring'] = false;
}
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::STORE_CC]) && $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::STORE_CC] === true) {
$request['paymentMethod']['storeDetails'] = true;
}
}
return $request;
}
/**
* @param $request
* @param $payment
* @param $storeId
* @return mixed
*/
public function buildCCData($request = [], $payload, $storeId, $areaCode)
{
// If ccType is set use this. For bcmc you need bcmc otherwise it will fail
if (!empty($payload['method']) && $payload['method'] == 'adyen_oneclick' &&
!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA]['variant'])
) {
$request['paymentMethod']['type'] = $payload[PaymentInterface::KEY_ADDITIONAL_DATA]['variant'];
} else {
$request['paymentMethod']['type'] = 'scheme';
}
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER]) &&
$cardNumber = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_CREDIT_CARD_NUMBER]) {
$request['paymentMethod']['encryptedCardNumber'] = $cardNumber;
}
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH]) &&
$expiryMonth = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_MONTH]) {
$request['paymentMethod']['encryptedExpiryMonth'] = $expiryMonth;
}
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR]) &&
$expiryYear = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_EXPIRY_YEAR]) {
$request['paymentMethod']['encryptedExpiryYear'] = $expiryYear;
}
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::HOLDER_NAME]) && $holderName =
$payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::HOLDER_NAME]) {
$request['paymentMethod']['holderName'] = $holderName;
}
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE]) &&
$securityCode = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::ENCRYPTED_SECURITY_CODE]) {
$request['paymentMethod']['encryptedSecurityCode'] = $securityCode;
}
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenOneclickDataAssignObserver::RECURRING_DETAIL_REFERENCE]) &&
$recurringDetailReference = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenOneclickDataAssignObserver::RECURRING_DETAIL_REFERENCE]
) {
$request['paymentMethod']['recurringDetailReference'] = $recurringDetailReference;
}
/**
* if MOTO for backend is enabled use MOTO as shopper interaction type
*/
$enableMoto = $this->adyenHelper->getAdyenCcConfigDataFlag('enable_moto', $storeId);
if ($areaCode === \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE &&
$enableMoto
) {
$request['shopperInteraction'] = "Moto";
}
// if installments is set add it into the request
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS])) {
if (($numberOfInstallment = $payload[PaymentInterface::KEY_ADDITIONAL_DATA][AdyenCcDataAssignObserver::NUMBER_OF_INSTALLMENTS]) > 0) {
$request['installments']['value'] = $numberOfInstallment;
}
}
return $request;
}
/**
* @param $request
* @param $additionalInformation
* @return mixed
*/
public function buildVaultData($request = [], $payload)
{
if (!empty($payload[PaymentInterface::KEY_ADDITIONAL_DATA][VaultConfigProvider::IS_ACTIVE_CODE]) &&
$payload[PaymentInterface::KEY_ADDITIONAL_DATA][VaultConfigProvider::IS_ACTIVE_CODE] === true
) {
// store it only as oneclick otherwise we store oneclick tokens (maestro+bcmc) that will fail
$request['enableRecurring'] = true;
} else {
// explicity turn this off as merchants have recurring on by default
$request['enableRecurring'] = false;
}
return $request;
}
/**
* The billing address retrieved from the Quote and the one retrieved from the Order has some differences
* Therefore we need to check if the getStreetFull function exists and use that if yes, otherwise use the more
* commont getStreetLine1
*
* @param $billingAddress
* @return array
*/
private function getStreetStringFromAddress($address)
{
if (method_exists($address, 'getStreetFull')) {
// Parse address into street and house number where possible
$address = $this->adyenHelper->getStreetFromString($address->getStreetFull());
} else {
$address = $this->adyenHelper->getStreetFromString($address->getStreetLine1());
}
return $address;
}
}
<?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\AdyenPaymentProcessInterface;
class AdyenPaymentProcess implements AdyenPaymentProcessInterface
{
/**
* @var \Magento\Checkout\Model\Session
*/
private $checkoutSession;
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenRequestHelper;
/**
* @var \Magento\Framework\Model\Context
*/
private $context;
/**
* @var \Adyen\Payment\Gateway\Http\TransferFactory
*/
private $transferFactory;
/**
* @var \Adyen\Payment\Gateway\Http\Client\TransactionPayment
*/
private $transactionPayment;
/**
* @var \Adyen\Payment\Gateway\Validator\CheckoutResponseValidator
*/
private $checkoutResponseValidator;
/**
* @var \Adyen\Payment\Gateway\Validator\ThreeDS2ResponseValidator
*/
private $threeDS2ResponseValidator;
/**
* AdyenPaymentProcess constructor.
*
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Adyen\Payment\Helper\Requests $adyenRequestHelper
* @param \Adyen\Payment\Gateway\Http\TransferFactory $transferFactory
* @param \Adyen\Payment\Gateway\Http\Client\TransactionPayment $transactionPayment
* @param \Adyen\Payment\Gateway\Validator\CheckoutResponseValidator $checkoutResponseValidator
* @param \Adyen\Payment\Gateway\Validator\ThreeDS2ResponseValidator $threeDS2ResponseValidator
*/
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Checkout\Model\Session $checkoutSession,
\Adyen\Payment\Helper\Data $adyenHelper,
\Adyen\Payment\Helper\Requests $adyenRequestHelper,
\Adyen\Payment\Gateway\Http\TransferFactory $transferFactory,
\Adyen\Payment\Gateway\Http\Client\TransactionPayment $transactionPayment,
\Adyen\Payment\Gateway\Validator\CheckoutResponseValidator $checkoutResponseValidator,
\Adyen\Payment\Gateway\Validator\ThreeDS2ResponseValidator $threeDS2ResponseValidator
)
{
$this->context = $context;
$this->checkoutSession = $checkoutSession;
$this->adyenHelper = $adyenHelper;
$this->adyenRequestHelper = $adyenRequestHelper;
$this->transferFactory = $transferFactory;
$this->transactionPayment = $transactionPayment;
$this->checkoutResponseValidator = $checkoutResponseValidator;
$this->threeDS2ResponseValidator = $threeDS2ResponseValidator;
}
/**
* @api
* @param string $payload
* @return string
* @throws \Magento\Framework\Exception\LocalizedException
*/
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(__('Error with payment method please select different payment method.'));
}
// Get payment and cart information from session
$quote = $this->checkoutSession->getQuote();
$payment = $quote->getPayment();
// Init request array
$request = [];
// Merchant account data builder
$paymentMethod = $payment->getMethod();
$storeId = $quote->getStoreId();
$request = $this->adyenRequestHelper->buildMerchantAccountData($request, $paymentMethod, $storeId);
// Customer data builder
$customerId = $quote->getCustomerId();
$billingAddress = $quote->getBillingAddress();
$request = $this->adyenRequestHelper->buildCustomerData($request, $customerId, $billingAddress, $storeId);
// Customer Ip data builder
$shopperIp = $quote->getRemoteIp();
$request = $this->adyenRequestHelper->buildCustomerIpData($request, $shopperIp);
// AddressDataBuilder
$shippingAddress = $quote->getShippingAddress();
$request = $this->adyenRequestHelper->buildAddressData($request, $billingAddress, $shippingAddress);
// PaymentDataBuilder
$currencyCode = $quote->getQuoteCurrencyCode();
$amount = $quote->getGrandTotal();
// Setting the orderid to null, so that we generate a new one for each /payments call
$quote->setReservedOrderId(null);
$reference = $quote->reserveOrderId()->getReservedOrderId();
$request = $this->adyenRequestHelper->buildPaymentData($request, $amount, $currencyCode, $reference);
// Browser data builder
$request = $this->adyenRequestHelper->buildBrowserData($request);
// 3DS2.0 data builder
$isThreeDS2Enabled = $this->adyenHelper->isCreditCardThreeDS2Enabled($storeId);
if ($isThreeDS2Enabled) {
$request = $this->adyenRequestHelper->buildThreeDS2Data($request, $payload, $quote->getStore());
}
// RecurringDataBuilder
$areaCode = $this->context->getAppState()->getAreaCode();
$request = $this->adyenRequestHelper->buildRecurringData($request, $areaCode, $storeId, $payload);
// CcAuthorizationDataBuilder
$request = $this->adyenRequestHelper->buildCCData($request, $payload, $storeId, $areaCode);
// Vault data builder
$request = $this->adyenRequestHelper->buildVaultData($request, $payload);
// Create and send request
$transferObject = $this->transferFactory->create($request);
$paymentsResponse = $this->transactionPayment->placeRequest($transferObject);
// Check if 3DS2.0 validation is needed or not
// In case 3DS2.0 validation is necessary send the type and token back to the frontend
if (!empty($paymentsResponse['resultCode'])) {
if ($paymentsResponse['resultCode'] == 'IdentifyShopper' ||
$paymentsResponse['resultCode'] == 'ChallengeShopper') {
if ($this->threeDS2ResponseValidator->validate(array(
"response" => $paymentsResponse,
"payment" => $payment
))->isValid()) {
$quote->save();
return $this->adyenHelper->buildThreeDS2ProcessResponseJson($payment->getAdditionalInformation('threeDS2Type'),
$payment->getAdditionalInformation('threeDS2Token'));
}
}
} else {
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
// Save the payments response because we are going to need it during the place order flow
$payment->setAdditionalInformation("paymentsResponse", $paymentsResponse);
// To actually save the additional info changes into the quote
$quote->save();
// Original flow can continue, return to frontend and place the order
return $this->adyenHelper->buildThreeDS2ProcessResponseJson();
}
}
<?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;
/**
* AdyenThreeDS2Process constructor.
*
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Adyen\Payment\Helper\Data $adyenHelper
*/
public function __construct(
\Magento\Checkout\Model\Session $checkoutSession,
\Adyen\Payment\Helper\Data $adyenHelper
)
{
$this->checkoutSession = $checkoutSession;
$this->adyenHelper = $adyenHelper;
}
/**
* @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'));
}
// Get payment and cart information from session
$quote = $this->checkoutSession->getQuote();
$payment = $quote->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 {
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($quote->getStoreId());
$service = $this->adyenHelper->createAdyenCheckoutService($client);
$result = $service->paymentsDetails($request);
} catch (\Adyen\AdyenException $e) {
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']);
}
// Payment can get back to the original flow
// Save the payments response because we are going to need it during the place order flow
$payment->setAdditionalInformation("paymentsResponse", $result);
// Setting the placeOrder to true enables the process to skip the payments call because the paymentsResponse
// is already in place - only set placeOrder to true when you have the paymentsResponse
$payment->setAdditionalInformation('placeOrder', true);
// To actually save the additional info changes into the quote
$quote->save();
// 3DS2 flow is done, original place order flow can continue from frontend
return $this->adyenHelper->buildThreeDS2ProcessResponseJson();
}
}
...@@ -173,7 +173,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement ...@@ -173,7 +173,7 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
* @param $contractDetail * @param $contractDetail
* @return $this * @return $this
*/ */
public function setCcBillingAgreement($contractDetail, $storeOneClick) public function setCcBillingAgreement($contractDetail, $storeOneClick, $storeId)
{ {
$this $this
->setMethodCode('adyen_oneclick') ->setMethodCode('adyen_oneclick')
...@@ -212,9 +212,9 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement ...@@ -212,9 +212,9 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
$expiryDate = explode('/', $contractDetail['expiryDate']); $expiryDate = explode('/', $contractDetail['expiryDate']);
if (!empty($contractDetail['pos_payment'])) { if (!empty($contractDetail['pos_payment'])) {
$recurringType = $this->adyenHelper->getAdyenPosCloudConfigData('recurring_type'); $recurringType = $this->adyenHelper->getAdyenPosCloudConfigData('recurring_type', $storeId);
} else { } else {
$recurringType = $this->adyenHelper->getRecurringTypeFromOneclickRecurringSetting(); $recurringType = $this->adyenHelper->getRecurringTypeFromOneclickRecurringSetting($storeId);
// for bcmc and maestro recurring is not allowed so don't set this // for bcmc and maestro recurring is not allowed so don't set this
if ($recurringType === \Adyen\Payment\Model\RecurringType::ONECLICK_RECURRING && if ($recurringType === \Adyen\Payment\Model\RecurringType::ONECLICK_RECURRING &&
......
...@@ -907,6 +907,41 @@ class Cron ...@@ -907,6 +907,41 @@ class Cron
} }
break; break;
case Notification::OFFER_CLOSED: case Notification::OFFER_CLOSED:
$previousSuccess = $this->_order->getData('adyen_notification_event_code_success');
// Order is already Authorised
if (!empty($previousSuccess)) {
$this->_adyenLogger->addAdyenNotificationCronjob("Order is already authorised, skipping OFFER_CLOSED");
break;
}
/*
* For cards, it can be 'visa', 'maestro',...
* For alternatives, it can be 'ideal', 'directEbanking',...
*/
$notificationPaymentMethod = $this->_paymentMethod;
/*
* For cards, it can be 'VI', 'MI',...
* For alternatives, it can be 'ideal', 'directEbanking',...
*/
$orderPaymentMethod = $this->_order->getPayment()->getCcType();
$isOrderCc = strcmp($this->_paymentMethodCode(),
'adyen_cc') == 0 || strcmp($this->_paymentMethodCode(), 'adyen_oneclick') == 0;
/*
* If the order was made with an Alternative payment method,
* continue with the cancellation only if the payment method of
* the notification matches the payment method of the order.
*/
if (!$isOrderCc && strcmp($notificationPaymentMethod, $orderPaymentMethod) !== 0) {
$this->_adyenLogger->addAdyenNotificationCronjob("Order is not a credit card,
or the payment method in the notification does not match the payment method of the order,
skipping OFFER_CLOSED");
break;
}
if (!$this->_order->canCancel()) { if (!$this->_order->canCancel()) {
// Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled // Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled
$this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW); $this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW);
...@@ -1148,9 +1183,14 @@ class Cron ...@@ -1148,9 +1183,14 @@ class Cron
protected function _authorizePayment() protected function _authorizePayment()
{ {
$this->_adyenLogger->addAdyenNotificationCronjob('Authorisation of the order'); $this->_adyenLogger->addAdyenNotificationCronjob('Authorisation of the order');
// Set adyen_notification_event_code_success to true so that we ignore a possible OFFER_CLOSED
if (strcmp($this->_success, 'true') == 0) {
$this->_order->setData('adyen_notification_event_code_success', 1);
}
$fraudManualReviewStatus = $this->_getFraudManualReviewStatus(); $fraudManualReviewStatus = $this->_getFraudManualReviewStatus();
// If manual review is active and a seperate status is used then ignore the pre authorized status // If manual review is active and a separate status is used then ignore the pre authorized status
if ($this->_fraudManualReview != true || $fraudManualReviewStatus == "") { if ($this->_fraudManualReview != true || $fraudManualReviewStatus == "") {
$this->_setPrePaymentAuthorized(); $this->_setPrePaymentAuthorized();
} else { } else {
......
...@@ -134,7 +134,7 @@ class AdyenHppConfigProvider implements ConfigProviderInterface ...@@ -134,7 +134,7 @@ class AdyenHppConfigProvider implements ConfigProviderInterface
} }
} }
$config['payment']['adyenHpp']['locale'] = $this->adyenHelper->getStoreLocale($this->storeManager->getStore()->getId()); $config['payment']['adyenHpp']['locale'] = $this->adyenHelper->getCurrentLocaleCode($this->storeManager->getStore()->getId());
// add to config // add to config
$config['payment'] ['adyenHpp']['gender'] = $gender; $config['payment'] ['adyenHpp']['gender'] = $gender;
......
...@@ -46,6 +46,21 @@ class AdyenBoletoDataAssignObserver extends AbstractDataAssignObserver ...@@ -46,6 +46,21 @@ class AdyenBoletoDataAssignObserver extends AbstractDataAssignObserver
self::LASTNAME self::LASTNAME
]; ];
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* AdyenBoletoDataAssignObserver constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper
) {
$this->adyenHelper = $adyenHelper;
}
/** /**
* @param Observer $observer * @param Observer $observer
* @return void * @return void
...@@ -60,8 +75,11 @@ class AdyenBoletoDataAssignObserver extends AbstractDataAssignObserver ...@@ -60,8 +75,11 @@ class AdyenBoletoDataAssignObserver extends AbstractDataAssignObserver
} }
$paymentInfo = $this->readPaymentModelArgument($observer); $paymentInfo = $this->readPaymentModelArgument($observer);
if (!empty($additionalData[self::BOLETO_TYPE])) {
$paymentInfo->setCcType('boleto'); $paymentInfo->setCcType($additionalData[self::BOLETO_TYPE]);
} else {
$paymentInfo->setCcType($this->adyenHelper->getAdyenBoletoConfigData('boletotypes'));
}
foreach ($this->additionalInformationList as $additionalInformationKey) { foreach ($this->additionalInformationList as $additionalInformationKey) {
if (isset($additionalData[$additionalInformationKey])) { if (isset($additionalData[$additionalInformationKey])) {
......
...@@ -40,6 +40,12 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver ...@@ -40,6 +40,12 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
const ENCRYPTED_EXPIRY_YEAR = 'expiryYear'; const ENCRYPTED_EXPIRY_YEAR = 'expiryYear';
const HOLDER_NAME = 'holderName'; const HOLDER_NAME = 'holderName';
const VARIANT = 'variant'; const VARIANT = 'variant';
const JAVA_ENABLED = 'java_enabled';
const SCREEN_COLOR_DEPTH = 'screen_color_depth';
const SCREEN_WIDTH = 'screen_width';
const SCREEN_HEIGHT = 'screen_height';
const TIMEZONE_OFFSET = 'timezone_offset';
const LANGUAGE = 'language';
/** /**
* @var array * @var array
...@@ -53,7 +59,13 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver ...@@ -53,7 +59,13 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
self::ENCRYPTED_EXPIRY_MONTH, self::ENCRYPTED_EXPIRY_MONTH,
self::ENCRYPTED_EXPIRY_YEAR, self::ENCRYPTED_EXPIRY_YEAR,
self::HOLDER_NAME, self::HOLDER_NAME,
self::VARIANT self::VARIANT,
self::JAVA_ENABLED,
self::SCREEN_COLOR_DEPTH,
self::SCREEN_WIDTH,
self::SCREEN_HEIGHT,
self::TIMEZONE_OFFSET,
self::LANGUAGE
]; ];
/** /**
......
...@@ -35,6 +35,12 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver ...@@ -35,6 +35,12 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
const ENCRYPTED_SECURITY_CODE = 'cvc'; const ENCRYPTED_SECURITY_CODE = 'cvc';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments'; const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
const VARIANT = 'variant'; const VARIANT = 'variant';
const JAVA_ENABLED = 'java_enabled';
const SCREEN_COLOR_DEPTH = 'screen_color_depth';
const SCREEN_WIDTH = 'screen_width';
const SCREEN_HEIGHT = 'screen_height';
const TIMEZONE_OFFSET = 'timezone_offset';
const LANGUAGE = 'language';
/** /**
* @var array * @var array
...@@ -43,7 +49,13 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver ...@@ -43,7 +49,13 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
self::RECURRING_DETAIL_REFERENCE, self::RECURRING_DETAIL_REFERENCE,
self::ENCRYPTED_SECURITY_CODE, self::ENCRYPTED_SECURITY_CODE,
self::NUMBER_OF_INSTALLMENTS, self::NUMBER_OF_INSTALLMENTS,
self::VARIANT self::VARIANT,
self::JAVA_ENABLED,
self::SCREEN_COLOR_DEPTH,
self::SCREEN_WIDTH,
self::SCREEN_HEIGHT,
self::TIMEZONE_OFFSET,
self::LANGUAGE
]; ];
/** /**
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name": "adyen/module-payment", "name": "adyen/module-payment",
"description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.", "description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.",
"type": "magento2-module", "type": "magento2-module",
"version": "4.1.1", "version": "4.2.0",
"license": [ "license": [
"OSL-3.0", "OSL-3.0",
"AFL-3.0" "AFL-3.0"
......
<?xml version="1.0"?> <?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Authorization Request -->
<virtualType name="AdyenPaymentCcAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite">
<arguments>
<argument name="builders" xsi:type="array">
<item name="merchantaccount" xsi:type="string">Adyen\Payment\Gateway\Request\MerchantAccountDataBuilder</item>
<item name="customer" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerDataBuilder</item>
<item name="customerip" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerIpDataBuilder</item>
<item name="address" xsi:type="string">Adyen\Payment\Gateway\Request\AddressDataBuilder</item>
<item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</item>
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcBackendAuthorizationDataBuilder</item>
<item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item>
</argument>
</arguments>
</virtualType>
<type name="Magento\Framework\Notification\MessageList"> <type name="Magento\Framework\Notification\MessageList">
<arguments> <arguments>
<argument name="messages" xsi:type="array"> <argument name="messages" xsi:type="array">
......
...@@ -59,6 +59,12 @@ ...@@ -59,6 +59,12 @@
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_cc_vault/active</config_path> <config_path>payment/adyen_cc_vault/active</config_path>
</field> </field>
<field id="adyen_cc_threeds2" translate="label" type="select" sortOrder="70" showInDefault="1" showInWebsite="1"
showInStore="1">
<label>3DS2.0 Enabled</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_cc_threeds2/active</config_path>
</field>
<group id="adyen_cc_advanced_settings" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" <group id="adyen_cc_advanced_settings" translate="label" showInDefault="1" showInWebsite="1" showInStore="1"
sortOrder="150"> sortOrder="150">
......
...@@ -489,16 +489,8 @@ ...@@ -489,16 +489,8 @@
<virtualType name="AdyenPaymentCcAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite"> <virtualType name="AdyenPaymentCcAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite">
<arguments> <arguments>
<argument name="builders" xsi:type="array"> <argument name="builders" xsi:type="array">
<item name="merchantaccount" xsi:type="string">Adyen\Payment\Gateway\Request\MerchantAccountDataBuilder</item>
<item name="customer" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerDataBuilder</item>
<item name="customerip" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerIpDataBuilder</item>
<item name="address" xsi:type="string">Adyen\Payment\Gateway\Request\AddressDataBuilder</item>
<item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</item>
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder <item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder
</item> </item>
<item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item>
</argument> </argument>
</arguments> </arguments>
</virtualType> </virtualType>
...@@ -536,15 +528,7 @@ ...@@ -536,15 +528,7 @@
<virtualType name="AdyenPaymentOneclickAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite"> <virtualType name="AdyenPaymentOneclickAuthorizeRequest" type="Magento\Payment\Gateway\Request\BuilderComposite">
<arguments> <arguments>
<argument name="builders" xsi:type="array"> <argument name="builders" xsi:type="array">
<item name="merchantaccount" xsi:type="string">Adyen\Payment\Gateway\Request\MerchantAccountDataBuilder</item>
<item name="customer" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerDataBuilder</item>
<item name="customerip" xsi:type="string">Adyen\Payment\Gateway\Request\CustomerIpDataBuilder</item>
<item name="address" xsi:type="string">Adyen\Payment\Gateway\Request\AddressDataBuilder</item>
<item name="payment" xsi:type="string">Adyen\Payment\Gateway\Request\PaymentDataBuilder</item>
<item name="browserinfo" xsi:type="string">Adyen\Payment\Gateway\Request\BrowserInfoDataBuilder</item>
<item name="recurring" xsi:type="string">Adyen\Payment\Gateway\Request\RecurringDataBuilder</item>
<item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder</item> <item name="transaction" xsi:type="string">Adyen\Payment\Gateway\Request\CcAuthorizationDataBuilder</item>
<item name="oneclick" xsi:type="string">Adyen\Payment\Gateway\Request\OneclickAuthorizationDataBuilder</item>
</argument> </argument>
</arguments> </arguments>
</virtualType> </virtualType>
...@@ -644,6 +628,7 @@ ...@@ -644,6 +628,7 @@
<arguments> <arguments>
<argument name="handlers" xsi:type="array"> <argument name="handlers" xsi:type="array">
<item name="payment_details" xsi:type="string">Adyen\Payment\Gateway\Response\CheckoutPaymentsDetailsHandler</item> <item name="payment_details" xsi:type="string">Adyen\Payment\Gateway\Response\CheckoutPaymentsDetailsHandler</item>
<item name="vault_details" xsi:type="string">Adyen\Payment\Gateway\Response\VaultDetailsHandler</item>
<item name="payment_comments" xsi:type="string">Adyen\Payment\Gateway\Response\CheckoutPaymentCommentHistoryHandler</item> <item name="payment_comments" xsi:type="string">Adyen\Payment\Gateway\Response\CheckoutPaymentCommentHistoryHandler</item>
</argument> </argument>
</arguments> </arguments>
...@@ -885,8 +870,10 @@ ...@@ -885,8 +870,10 @@
type="Adyen\Payment\Model\AdyenRequestMerchantSession"/> type="Adyen\Payment\Model\AdyenRequestMerchantSession"/>
<preference for="Adyen\Payment\Api\AdyenInitiateTerminalApiInterface" <preference for="Adyen\Payment\Api\AdyenInitiateTerminalApiInterface"
type="Adyen\Payment\Model\AdyenInitiateTerminalApi"/> type="Adyen\Payment\Model\AdyenInitiateTerminalApi"/>
<preference for="Magento\Checkout\Api\PaymentInformationManagementInterface" <preference for="Adyen\Payment\Api\AdyenPaymentProcessInterface"
type="Adyen\Payment\Model\AdyenPaymentInformationManagement"/> type="Adyen\Payment\Model\AdyenPaymentProcess"/>
<preference for="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface"
type="Adyen\Payment\Model\AdyenThreeDS2Process"/>
<type name="Magento\Vault\Api\PaymentTokenRepositoryInterface"> <type name="Magento\Vault\Api\PaymentTokenRepositoryInterface">
<plugin name="AdyenPaymentVaultDeleteToken" type="Adyen\Payment\Plugin\PaymentVaultDeleteToken" sortOrder="10"/> <plugin name="AdyenPaymentVaultDeleteToken" type="Adyen\Payment\Plugin\PaymentVaultDeleteToken" sortOrder="10"/>
</type> </type>
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
--> -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Adyen_Payment" setup_version="4.1.1"> <module name="Adyen_Payment" setup_version="4.2.0">
<sequence> <sequence>
<module name="Magento_Sales"/> <module name="Magento_Sales"/>
<module name="Magento_Quote"/> <module name="Magento_Quote"/>
......
...@@ -57,4 +57,18 @@ ...@@ -57,4 +57,18 @@
<resource ref="anonymous"/> <resource ref="anonymous"/>
</resources> </resources>
</route> </route>
<route url="/V1/adyen/payment" method="POST">
<service class="Adyen\Payment\Api\AdyenPaymentProcessInterface" method="initiate"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
<route url="/V1/adyen/threeDS2Process" method="POST">
<service class="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface" method="initiate"/>
<resources>
<resource ref="anonymous"/>
</resources>
</route>
</routes> </routes>
\ No newline at end of file
...@@ -104,7 +104,10 @@ echo $code; ?>" style="display:none"> ...@@ -104,7 +104,10 @@ echo $code; ?>" style="display:none">
var cardNode = document.getElementById("cardContainer-<?php /* @noEscape */ echo $code; ?>"); var cardNode = document.getElementById("cardContainer-<?php /* @noEscape */ echo $code; ?>");
var checkout = new AdyenCheckout({ var checkout = new AdyenCheckout({
locale: "<?php echo $block->getLocale(); ?>" locale: "<?php echo $block->getLocale(); ?>",
risk: {
enabled: false
}
}); });
var hideCVC = "<?php echo !$block->hasVerification(); ?>"; var hideCVC = "<?php echo !$block->hasVerification(); ?>";
......
...@@ -25,9 +25,17 @@ ...@@ -25,9 +25,17 @@
} }
.checkout-payment-method .ccard .changable-card-expiry { display:none; } .checkout-payment-method .ccard .changable-card-expiry {
.checkout-payment-method .ccard .changable-card-expiry._active { display:block; } display: none;
.checkout-payment-method .ccard .expire-update._disable { display:none; } }
.checkout-payment-method .ccard .changable-card-expiry._active {
display: block;
}
.checkout-payment-method .ccard .expire-update._disable {
display: none;
}
.checkout-payment-method .ccard .holdername .input-text { .checkout-payment-method .ccard .holdername .input-text {
width: 225px; width: 225px;
...@@ -44,8 +52,7 @@ ...@@ -44,8 +52,7 @@
} }
.checkout-payment-method .ccard .holdername .input-text::placeholder, .checkout-payment-method .ccard .holdername .input-text::placeholder,
.checkout-payment-method .ccard .holdername .input-text:placeholder-shown .checkout-payment-method .ccard .holdername .input-text:placeholder-shown {
{
color: rgb(144, 162, 189); color: rgb(144, 162, 189);
font-weight: 200; font-weight: 200;
} }
...@@ -58,20 +65,21 @@ ...@@ -58,20 +65,21 @@
} }
.checkout-payment-method .payment-method-title label img, .checkout-payment-method .payment-method-title label img,
.checkout-payment-method .payment-method-title label div { padding-right:10px;} .checkout-payment-method .payment-method-title label div {
padding-right: 10px;
}
.checkout-payment-method .payment-method-title label div.adyen-sprite { .checkout-payment-method .payment-method-title label div.adyen-sprite {
background:url(../images/logos/pm_gloss.png) no-repeat; background: url(../images/logos/pm_gloss.png) no-repeat;
background-position: 0 -272px; background-position: 0 -272px;
width:65px; width: 65px;
height:42px; height: 42px;
display: inline-block; display: inline-block;
} }
.checkout-payment-method .payment-method-title label div.adyen-sprite.adyen_cc { .checkout-payment-method .payment-method-title label div.adyen-sprite.adyen_cc {
background:url(../images/logos/cc_border.png) no-repeat; background: url(../images/logos/cc_border.png) no-repeat;
} }
.checkout-payment-method .payment-method-title label div.adyen-sprite.adyen_pos { .checkout-payment-method .payment-method-title label div.adyen-sprite.adyen_pos {
...@@ -91,13 +99,13 @@ ...@@ -91,13 +99,13 @@
} }
.checkout-payment-method .payment-method-title label div.adyen-sprite.adyen_apple_pay { .checkout-payment-method .payment-method-title label div.adyen-sprite.adyen_apple_pay {
background:url(../images/logos/apple_pay.png) no-repeat; background: url(../images/logos/apple_pay.png) no-repeat;
height:43px; height: 43px;
} }
.checkout-payment-method .input-text._has-datepicker { .checkout-payment-method .input-text._has-datepicker {
width:20%; width: 20%;
margin-right:10px; margin-right: 10px;
} }
.apple-pay-button-with-text { .apple-pay-button-with-text {
...@@ -109,37 +117,44 @@ ...@@ -109,37 +117,44 @@
padding: 0px; padding: 0px;
box-sizing: border-box; box-sizing: border-box;
/*min-width: 200px;*/ /*min-width: 200px;*/
width:100%; width: 100%;
min-height: 32px; min-height: 32px;
max-height: 64px; max-height: 64px;
margin-bottom: 10px; margin-bottom: 10px;
cursor: pointer; cursor: pointer;
} }
.apple-pay-button-black-with-text { .apple-pay-button-black-with-text {
background-color: black; background-color: black;
color: white; color: white;
} }
.apple-pay-button-white-with-text { .apple-pay-button-white-with-text {
background-color: white; background-color: white;
color: black; color: black;
} }
.apple-pay-button-white-with-line-with-text { .apple-pay-button-white-with-line-with-text {
background-color: white; background-color: white;
color: black; color: black;
border: .5px solid black; border: .5px solid black;
} }
.apple-pay-button-with-text.apple-pay-button-black-with-text > .logo { .apple-pay-button-with-text.apple-pay-button-black-with-text > .logo {
background-image: -webkit-named-image(apple-pay-logo-white); background-image: -webkit-named-image(apple-pay-logo-white);
background-color: black; background-color: black;
} }
.apple-pay-button-with-text.apple-pay-button-white-with-text > .logo { .apple-pay-button-with-text.apple-pay-button-white-with-text > .logo {
background-image: -webkit-named-image(apple-pay-logo-black); background-image: -webkit-named-image(apple-pay-logo-black);
background-color: white; background-color: white;
} }
.apple-pay-button-with-text.apple-pay-button-white-with-line-with-text > .logo { .apple-pay-button-with-text.apple-pay-button-white-with-line-with-text > .logo {
background-image: -webkit-named-image(apple-pay-logo-black); background-image: -webkit-named-image(apple-pay-logo-black);
background-color: white; background-color: white;
} }
.apple-pay-button-with-text > .text { .apple-pay-button-with-text > .text {
font-family: -apple-system; font-family: -apple-system;
font-size: calc(1em * var(--apple-pay-scale)); font-size: calc(1em * var(--apple-pay-scale));
...@@ -148,6 +163,7 @@ ...@@ -148,6 +163,7 @@
margin-right: calc(2px * var(--apple-pay-scale)); margin-right: calc(2px * var(--apple-pay-scale));
} }
.apple-pay-button-with-text > .logo { .apple-pay-button-with-text > .logo {
width: calc(35px * var(--apple-pay-scale)); width: calc(35px * var(--apple-pay-scale));
height: 100%; height: 100%;
...@@ -164,706 +180,803 @@ ...@@ -164,706 +180,803 @@
Custom style for ideal component Custom style for ideal component
*/ */
#iDealContainer .adyen-checkout__dropdown__button{ #iDealContainer .adyen-checkout__dropdown__button {
padding: 0 0 0 8px; padding: 0 0 0 8px;
max-width: 290px; max-width: 290px;
} }
#iDealContainer .adyen-checkout__dropdown--large{ #iDealContainer .adyen-checkout__dropdown--large {
margin-left: 21px; margin-left: 21px;
} }
#iDealContainer .adyen-checkout__dropdown__element{ #iDealContainer .adyen-checkout__dropdown__element {
margin-bottom: 0; margin-bottom: 0;
} }
/* General styling for checkout */ /* General styling for checkout */
.payment-method-content .field input, .payment-method-content .field select{ .payment-method-content .field input, .payment-method-content .field select {
max-width: 168px; max-width: 168px;
} }
.adyen-checkout__link adyen-checkout__link--more-information{ .adyen-checkout__link adyen-checkout__link--more-information {
margin-bottom: 10px; margin-bottom: 10px;
} }
.message.error.hpp-message{ .message.error.hpp-message {
margin-top: 10px; margin-top: 10px;
display: none; display: none;
} }
/* Checkout component Adyen styling start */ /* Checkout component Adyen styling start */
.adyen-checkout__spinner__wrapper{ .adyen-checkout__spinner__wrapper {
align-items:center; align-items: center;
display:flex; display: flex;
height:100%; height: 100%;
justify-content:center justify-content: center
}
.adyen-checkout__spinner__wrapper--inline{
display:inline-block;
height:auto;
margin-right:8px
}
.adyen-checkout__spinner{
-webkit-animation:rotateSpinner 2s infinite linear;
animation:rotateSpinner 2s infinite linear;
border:2px solid #00a3ff;
border-radius:50%;
border-top-color:transparent;
height:43px;
width:43px
}
.adyen-checkout__spinner--large{
height:43px;
width:43px
}
.adyen-checkout__spinner--small{
height:16px;
width:16px
}
.adyen-checkout__spinner--medium{
height:28px;
width:28px
}
@-webkit-keyframes rotateSpinner{
0%{
-webkit-transform:rotate(0deg);
transform:rotate(0deg)
}
to{
-webkit-transform:rotate(1turn);
transform:rotate(1turn)
}
} }
@keyframes rotateSpinner{
0%{ .adyen-checkout__spinner__wrapper--inline {
-webkit-transform:rotate(0deg); display: inline-block;
transform:rotate(0deg) height: auto;
} margin-right: 8px
to{ }
-webkit-transform:rotate(1turn);
transform:rotate(1turn) .adyen-checkout__spinner {
} -webkit-animation: rotateSpinner 2s infinite linear;
animation: rotateSpinner 2s infinite linear;
border: 2px solid #00a3ff;
border-radius: 50%;
border-top-color: transparent;
height: 43px;
width: 43px
}
.adyen-checkout__spinner--large {
height: 43px;
width: 43px
} }
.adyen-checkout__pay-button{ .adyen-checkout__spinner--small {
background:#001b2b; height: 16px;
border:0; width: 16px
border-radius:3px; }
box-shadow:0 3px 4px rgba(0,15,45,.2);
color:#fff; .adyen-checkout__spinner--medium {
cursor:pointer; height: 28px;
font-size:1em; width: 28px
font-weight:700; }
height:48px;
padding:15px; @-webkit-keyframes rotateSpinner {
transition:background .3s ease-out; 0% {
width:100% -webkit-transform: rotate(0deg);
} transform: rotate(0deg)
.adyen-checkout__pay-button:disabled{
-moz-user-select:all;
-ms-user-select:all;
-webkit-user-select:all;
background:#e6e9eb;
box-shadow:none;
cursor:not-allowed;
user-select:all
}
.adyen-checkout__pay-button--loading{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
background:#4c5f6b;
box-shadow:none;
outline:0;
pointer-events:none;
user-select:none
}
.adyen-checkout__pay-button .adyen-checkout__spinner{
border-color:transparent #fff #fff;
border-width:3px
}
.adyen-checkout__pay-button__content{
align-items:center;
display:flex;
justify-content:center
}
.adyen-checkout__payment-method{
background:#fff;
border:1px solid #edf0f3;
cursor:pointer;
margin-top:-1px;
position:relative;
transition:opacity .3s ease-out;
width:100%
}
.adyen-checkout__payment-method:focus{
outline:0
}
.adyen-checkout__payment-method--selected+.adyen-checkout__payment-method,.adyen-checkout__payment-method:first-child{
border-top-left-radius:3px;
border-top-right-radius:3px;
margin-top:0
}
.adyen-checkout__payment-method--next-selected{
border-bottom-left-radius:3px;
border-bottom-right-radius:3px
}
.adyen-checkout__payment-method--loading{
opacity:.2
}
.adyen-checkout__payment-method--selected.adyen-checkout__payment-method--loading{
opacity:.9
}
.adyen-checkout__payment-method--disabling{
opacity:.5
}
.adyen-checkout__payment-method__header{
align-items:center;
color:#00202e;
display:flex;
font-size:16px;
font-weight:400;
padding:16px;
position:relative;
transition:background .1s ease-out;
width:100%
}
.adyen-checkout__payment-method__surcharge{
color:#687282;
margin-left:5px
}
.adyen-checkout__payment-method--selected{
background:#f7f8f9;
border:1px solid #d4d9db;
border-radius:3px;
cursor:default;
margin:8px 0;
transition:margin .15s cubic-bezier(.4,0,.2,1) 0ms,opacity .3s ease-out
}
.adyen-checkout__payment-method--selected .adyen-checkout__payment-method__header{
font-weight:500
}
.adyen-checkout__payment-method__details{
padding:0 16px 16px
}
.adyen-checkout__payment-method__details__content{
padding:6px 0 24px
}
.adyen-checkout__payment-method__image__wrapper{
height:26px;
position:relative
}
.adyen-checkout__payment-method__image__wrapper:after{
border:1px solid rgba(0,27,43,.17);
border-radius:3px;
content:"";
height:100%;
left:0;
position:absolute;
top:0;
width:100%
}
.adyen-checkout__payment-method__image{
border-radius:3px
}
.adyen-checkout__payment-method__disable_oneclick{
background-color:transparent;
border:none;
color:#687282;
cursor:pointer;
display:block;
font-size:13px;
padding:0;
position:absolute;
right:70px;
text-decoration:underline
}
.adyen-checkout__payment-method__disable_oneclick:focus{
color:#00a3ff;
outline:0
}
.adyen-checkout__payment-method__disable-confirmation{
align-items:center;
background:#e6e9eb;
color:#001b2b;
display:flex;
font-size:15px;
justify-content:space-between;
margin-bottom:10px;
padding:8px 16px
}
.adyen-checkout__payment-method__disable-confirmation__buttons{
display:flex
}
.adyen-checkout__payment-method__disable-confirmation__button{
border:1px solid transparent;
border-radius:3px;
cursor:pointer;
font-size:13px;
line-height:15px;
margin:0 0 0 8px;
padding:8px
}
.adyen-checkout__payment-method__disable-confirmation__button--remove{
background:#d10244;
border-color:#d10244;
color:#fff
}
.adyen-checkout__payment-method__disable-confirmation__button--cancel{
background:transparent;
border-color:#001b2b;
color:#001b2b
}
.adyen-checkout__payment-method__radio{
background-color:#fff;
border:1px solid #b9c4c9;
border-radius:50%;
box-shadow:inset 0 1px 3px rgba(0,27,43,.15);
height:18px;
position:absolute;
right:20px;
transition:border-color .3s ease-out;
width:18px
}
.adyen-checkout__payment-method__radio:after{
-webkit-transform:translateY(-50%) scale(0);
background-color:#fff;
border-radius:50%;
box-shadow:0 1px 1px rgba(0,15,45,.25);
content:"";
display:block;
height:6px;
left:0;
margin:0 auto;
position:absolute;
right:0;
top:50%;
transform:translateY(-50%) scale(0);
transition:-webkit-transform .3s ease-out;
transition:transform .3s ease-out;
transition:transform .3s ease-out,-webkit-transform .3s ease-out;
width:6px
}
.adyen-checkout__payment-method__radio:hover{
border-color:#00a3ff;
cursor:pointer
}
.adyen-checkout__payment-method__radio--selected{
background-color:#00a3ff;
border:0 solid transparent;
box-shadow:inset 0 1px 2px rgba(0,0,0,.26);
transition:all .3s ease-out
}
.adyen-checkout__payment-method__radio--selected:after{
-webkit-transform:translateY(-50%) scale(1);
transform:translateY(-50%) scale(1)
}
.adyen-checkout__field{
display:block;
margin-bottom:16px
}
.adyen-checkout__field--error input{
border-color:#d81b4a;
color:#d81b4a
}
.adyen-checkout__field:last-child{
margin-bottom:0
}
.adyen-checkout__helper-text,.adyen-checkout__label__text{
color:#001b2b;
display:block;
font-size:13px;
font-weight:400;
line-height:13px;
padding-bottom:8px
}
.adyen-checkout__helper-text{
color:#687282
}
.adyen-checkout__label__text{
transition:color .2s ease-out
}
.adyen-checkout__label--focused .adyen-checkout__label__text{
color:#07b
}
.adyen-checkout__error-text,.adyen-checkout__label__text--error{
align-items:center;
color:#d0021b;
display:flex;
font-size:12px;
font-weight:400;
margin-top:4px
}
.adyen-checkout__icon svg{
fill:currentColor
}
.adyen-checkout__open-invoice .adyen-checkout__input--wrapper--socialSecurityNumber+.adyen-checkout__error-text{
max-width:380px
}
.adyen-checkout__radio_group+.adyen-checkout-input__inline-validation{
display:none
}
.adyen-checkout__radio_group__input{
opacity:0;
position:absolute
}
.adyen-checkout__radio_group__label{
display:block;
font-size:13px;
font-weight:400;
line-height:16px;
margin-bottom:8px;
padding-bottom:0;
padding-left:24px;
position:relative
}
.adyen-checkout__radio_group__label:before{
background-color:#fff;
border:1px solid #b9c4c9;
border-radius:50%;
content:"";
height:16px;
left:0;
position:absolute;
top:0;
transition:border-color .3s ease-out;
width:16px
}
.adyen-checkout__radio_group__label:after{
-webkit-transform:scale(0);
background-color:#fff;
border-radius:50%;
box-shadow:0 1px 1px rgba(0,15,45,.25);
content:"";
display:block;
height:6px;
left:5px;
margin:0 auto;
position:absolute;
top:5px;
transform:scale(0);
transition:-webkit-transform .3s ease-out;
transition:transform .3s ease-out;
transition:transform .3s ease-out,-webkit-transform .3s ease-out;
width:6px
}
.adyen-checkout__radio_group__label:hover{
border-color:#00a3ff;
cursor:pointer
}
.adyen-checkout__radio_group__input:checked+.adyen-checkout__radio_group__label:before,.adyen-checkout__radio_group__label--selected{
background-color:#00a3ff;
border:0 solid transparent;
box-shadow:inset 0 1px 2px rgba(0,0,0,.26);
transition:all .3s ease-out
}
.adyen-checkout__radio_group__input:checked+.adyen-checkout__radio_group__label:after{
-webkit-transform:scale(1);
transform:scale(1)
}
.adyen-checkout__radio_group__label.adyen-checkout__radio_group__label--invalid:before{
border:1px solid #d10244
}
.adyen-checkout__checkbox{
display:block
}
.adyen-checkout__checkbox>input[type=checkbox]{
opacity:0;
pointer-events:none;
position:absolute
}
.adyen-checkout__checkbox__label{
-moz-user-select:none;
-ms-user-select:none;
-webkit-user-select:none;
color:#001b2b;
cursor:pointer;
display:inline-block;
font-size:13px;
font-weight:400;
line-height:16px;
padding-left:24px;
position:relative;
user-select:none
}
.adyen-checkout__checkbox__input+span:before{
-webkit-transform:rotate(37deg);
-webkit-transform-origin:100% 100%;
border-color:transparent #fff #fff transparent;
border-radius:0 2px 1px 2px;
border-style:solid;
border-width:1px 2px 2px 1px;
content:"";
height:11px;
left:1px;
opacity:0;
position:absolute;
top:2px;
transform:rotate(37deg);
transform-origin:100% 100%;
transition:opacity .2s ease-out;
width:6px;
z-index:1
}
.adyen-checkout__checkbox__input:checked+.adyen-checkout__checkbox__label:before{
opacity:1
}
.adyen-checkout__checkbox__input+.adyen-checkout__checkbox__label:after{
background-color:#fff;
border:1px solid #b9c4c9;
border-radius:3px;
content:"";
height:16px;
left:0;
position:absolute;
top:0;
transition:background .15s ease-out,border .05s ease-out,box-shadow .1s ease-out;
width:16px;
z-index:0
}
.adyen-checkout__checkbox__input:checked+.adyen-checkout__checkbox__label:after{
background-color:#00a3ff;
border:1px solid #00a3ff
}
.adyen-checkout__checkbox__input:focus+span:after{
border:1px solid #00a3ff;
box-shadow:0 0 0 2px #91d7ff
}
.adyen-checkout__checkbox__input.adyen-checkout__checkbox__input--invalid+.adyen-checkout__checkbox__label:after{
border:1px solid #d10244
}
.adyen-checkout__dropdown{
font-size:16px;
max-width:100%;
width:200px
}
.adyen-checkout__dropdown--small{
width:130px
}
.adyen-checkout__dropdown--large{
width:300px
}
.adyen-checkout__dropdown__button{
background:#fff;
border:1px solid #b9c4c9;
border-radius:3px;
font-size:16px;
height:40px;
line-height:20px;
outline:0;
padding:9px 20px 9px 8px;
transition:border .2s ease-out,box-shadow .2s ease-out;
width:100%
}
.adyen-checkout__dropdown__button__icon{
margin-right:8px;
max-height:20px;
max-width:32px
}
.adyen-checkout__dropdown__button--active,.adyen-checkout__dropdown__button:active,.adyen-checkout__dropdown__button:focus{
border-color:#00a3ff;
box-shadow:0 0 0 2px #91d7ff
}
.adyen-checkout__dropdown__button--readonly,.adyen-checkout__dropdown__button--readonly.adyen-checkout__dropdown__button--active{
background:#e6e9eb;
color:#001b2b;
cursor:not-allowed
}
.adyen-checkout__dropdown__button--invalid{
border-color:#d10244
}
.adyen-checkout__dropdown__button__text{
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap
}
.adyen-checkout__dropdown__list{
border-radius:3px;
box-shadow:0 2px 7px rgba(0,15,45,.3);
margin-top:2px;
z-index:2
}
.adyen-checkout__dropdown__list.adyen-checkout__dropdown__list--active{
-webkit-animation:expand .1s ease-out;
animation:expand .1s ease-out
}
.adyen-checkout__dropdown__element{
-ms-hyphens:auto;
-webkit-hyphens:auto;
border:1px solid transparent;
border-bottom-color:#e6e9eb;
cursor:pointer;
hyphens:auto;
line-height:20px;
outline:0;
padding:8px;
transition:background .2s ease-out,border-color .2s ease-out;
word-break:break-word
}
.adyen-checkout__dropdown__element:last-child{
border-bottom:0
}
.adyen-checkout__dropdown__element:active,.adyen-checkout__dropdown__element:focus,.adyen-checkout__dropdown__element:hover{
background:#f0f2f4
}
.adyen-checkout__dropdown__element:active,.adyen-checkout__dropdown__element:focus{
border-bottom-color:#00a3ff;
border-top-color:#00a3ff
}
.adyen-checkout__dropdown__element__icon{
margin-right:8px;
max-height:20px;
max-width:32px
}
@-webkit-keyframes expand{
0%{
-webkit-transform:scaleY(0);
transform:scaleY(0)
} }
to{ to {
-webkit-transform:scaleX(1); -webkit-transform: rotate(1turn);
transform:scaleX(1) transform: rotate(1turn)
} }
} }
@keyframes expand{
0%{ @keyframes rotateSpinner {
-webkit-transform:scaleY(0); 0% {
transform:scaleY(0) -webkit-transform: rotate(0deg);
transform: rotate(0deg)
} }
to{ to {
-webkit-transform:scaleX(1); -webkit-transform: rotate(1turn);
transform:scaleX(1) transform: rotate(1turn)
} }
} }
.adyen-checkout__dropdown+.adyen-checkout-input__inline-validation{ .adyen-checkout__pay-button {
right:32px background: #001b2b;
} border: 0;
.adyen-checkout__select-list{ border-radius: 3px;
margin:0; box-shadow: 0 3px 4px rgba(0, 15, 45, .2);
padding:0 color: #fff;
} cursor: pointer;
.adyen-checkout__select-list__item{ font-size: 1em;
background:#fff; font-weight: 700;
border-top:1px solid #b9c4c9; height: 48px;
cursor:pointer; padding: 15px;
display:inline-block; transition: background .3s ease-out;
font-size:16px; width: 100%
line-height:20px; }
outline:0;
padding:9px; .adyen-checkout__pay-button:disabled {
width:100% -moz-user-select: all;
} -ms-user-select: all;
.adyen-checkout__select-list__item:first-child{ -webkit-user-select: all;
border-top:0 background: #e6e9eb;
} box-shadow: none;
.adyen-checkout__select-list__item:active,.adyen-checkout__select-list__item:focus,.adyen-checkout__select-list__item:hover{ cursor: not-allowed;
background:rgba(145,215,255,.5) user-select: all
} }
.adyen-checkout__select-list__item--selected{
background:rgba(145,215,255,.5); .adyen-checkout__pay-button--loading {
font-weight:700 -moz-user-select: none;
} -ms-user-select: none;
.adyen-checkout__input{ -webkit-user-select: none;
background:#fff; background: #4c5f6b;
border:1px solid #b9c4c9; box-shadow: none;
border-radius:3px; outline: 0;
color:#001b2b; pointer-events: none;
display:block; user-select: none
font-family:inherit; }
font-size:16px;
height:40px; .adyen-checkout__pay-button .adyen-checkout__spinner {
outline:none; border-color: transparent #fff #fff;
padding:5px 8px; border-width: 3px
position:relative; }
transition:border .2s ease-out,box-shadow .2s ease-out;
width:200px .adyen-checkout__pay-button__content {
} align-items: center;
.adyen-checkout__input:required{ display: flex;
box-shadow:none justify-content: center
} }
.adyen-checkout__input--wrapper{
display:inline-block; .adyen-checkout__payment-method {
position:relative background: #fff;
} border: 1px solid #edf0f3;
.adyen-checkout__input--wrapper--block{ cursor: pointer;
display:block margin-top: -1px;
} position: relative;
.adyen-checkout-input__inline-validation{ transition: opacity .3s ease-out;
-webkit-transform:translateY(-50%); width: 100%
height:16px; }
position:absolute;
right:14px; .adyen-checkout__payment-method:focus {
top:50%; outline: 0
transform:translateY(-50%); }
width:16px
} .adyen-checkout__payment-method--selected + .adyen-checkout__payment-method, .adyen-checkout__payment-method:first-child {
.adyen-checkout-input__inline-validation--valid{ border-top-left-radius: 3px;
color:#039450 border-top-right-radius: 3px;
} margin-top: 0
.adyen-checkout-input__inline-validation--invalid{ }
color:#d10244
} .adyen-checkout__payment-method--next-selected {
.adyen-checkout__input.adyen-checkout__input--small{ border-bottom-left-radius: 3px;
width:130px border-bottom-right-radius: 3px
} }
.adyen-checkout__input.adyen-checkout__input--large{
width:300px .adyen-checkout__payment-method--loading {
} opacity: .2
.adyen-checkout__input.adyen-checkout__input--invalid{ }
border-color:#d10244
} .adyen-checkout__payment-method--selected.adyen-checkout__payment-method--loading {
.adyen-checkout__input.adyen-checkout__input--valid{ opacity: .9
border-bottom-color:#04ba65 }
}
.adyen-checkout__input--error{ .adyen-checkout__payment-method--disabling {
border-color:#d0021b opacity: .5
} }
.adyen-checkout__input::-webkit-input-placeholder{
color:#90a2bd; .adyen-checkout__payment-method__header {
font-weight:200 align-items: center;
} color: #00202e;
.adyen-checkout__input::-ms-input-placeholder{ display: flex;
color:#90a2bd; font-size: 16px;
font-weight:200 font-weight: 400;
} padding: 16px;
.adyen-checkout__input::placeholder{ position: relative;
color:#90a2bd; transition: background .1s ease-out;
font-weight:200 width: 100%
} }
.adyen-checkout__input--active,.adyen-checkout__input:active,.adyen-checkout__input:focus{
border:1px solid #00a3ff; .adyen-checkout__payment-method__surcharge {
box-shadow:0 0 0 2px #91d7ff color: #687282;
} margin-left: 5px
.adyen-checkout__input[readonly]{ }
background-color:#e6e9eb;
border-color:transparent; .adyen-checkout__payment-method--selected {
color:#687282; background: #f7f8f9;
cursor:default border: 1px solid #d4d9db;
} border-radius: 3px;
.adyen-checkout__fieldset{ cursor: default;
color:#687282; margin: 8px 0;
display:block; transition: margin .15s cubic-bezier(.4, 0, .2, 1) 0ms, opacity .3s ease-out
padding-bottom:30px; }
width:100%
} .adyen-checkout__payment-method--selected .adyen-checkout__payment-method__header {
.adyen-checkout__fieldset__title{ font-weight: 500
color:#687282; }
display:block;
font-size:11px; .adyen-checkout__payment-method__details {
font-weight:700; padding: 0 16px 16px
letter-spacing:1px; }
margin:0;
padding:0 0 20px; .adyen-checkout__payment-method__details__content {
text-transform:uppercase padding: 6px 0 24px
} }
.adyen-checkout__fieldset--readonly{
color:#001b2b; .adyen-checkout__payment-method__image__wrapper {
font-size:13px; height: 26px;
line-height:19px; position: relative
margin:0 }
.adyen-checkout__payment-method__image__wrapper:after {
border: 1px solid rgba(0, 27, 43, .17);
border-radius: 3px;
content: "";
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%
}
.adyen-checkout__payment-method__image {
border-radius: 3px
}
.adyen-checkout__payment-method__disable_oneclick {
background-color: transparent;
border: none;
color: #687282;
cursor: pointer;
display: block;
font-size: 13px;
padding: 0;
position: absolute;
right: 70px;
text-decoration: underline
}
.adyen-checkout__payment-method__disable_oneclick:focus {
color: #00a3ff;
outline: 0
}
.adyen-checkout__payment-method__disable-confirmation {
align-items: center;
background: #e6e9eb;
color: #001b2b;
display: flex;
font-size: 15px;
justify-content: space-between;
margin-bottom: 10px;
padding: 8px 16px
}
.adyen-checkout__payment-method__disable-confirmation__buttons {
display: flex
}
.adyen-checkout__payment-method__disable-confirmation__button {
border: 1px solid transparent;
border-radius: 3px;
cursor: pointer;
font-size: 13px;
line-height: 15px;
margin: 0 0 0 8px;
padding: 8px
}
.adyen-checkout__payment-method__disable-confirmation__button--remove {
background: #d10244;
border-color: #d10244;
color: #fff
}
.adyen-checkout__payment-method__disable-confirmation__button--cancel {
background: transparent;
border-color: #001b2b;
color: #001b2b
}
.adyen-checkout__payment-method__radio {
background-color: #fff;
border: 1px solid #b9c4c9;
border-radius: 50%;
box-shadow: inset 0 1px 3px rgba(0, 27, 43, .15);
height: 18px;
position: absolute;
right: 20px;
transition: border-color .3s ease-out;
width: 18px
}
.adyen-checkout__payment-method__radio:after {
-webkit-transform: translateY(-50%) scale(0);
background-color: #fff;
border-radius: 50%;
box-shadow: 0 1px 1px rgba(0, 15, 45, .25);
content: "";
display: block;
height: 6px;
left: 0;
margin: 0 auto;
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%) scale(0);
transition: -webkit-transform .3s ease-out;
transition: transform .3s ease-out;
transition: transform .3s ease-out, -webkit-transform .3s ease-out;
width: 6px
}
.adyen-checkout__payment-method__radio:hover {
border-color: #00a3ff;
cursor: pointer
}
.adyen-checkout__payment-method__radio--selected {
background-color: #00a3ff;
border: 0 solid transparent;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .26);
transition: all .3s ease-out
}
.adyen-checkout__payment-method__radio--selected:after {
-webkit-transform: translateY(-50%) scale(1);
transform: translateY(-50%) scale(1)
}
.adyen-checkout__field {
display: block;
margin-bottom: 16px
}
.adyen-checkout__field--error input {
border-color: #d81b4a;
color: #d81b4a
}
.adyen-checkout__field:last-child {
margin-bottom: 0
}
.adyen-checkout__helper-text, .adyen-checkout__label__text {
color: #001b2b;
display: block;
font-size: 13px;
font-weight: 400;
line-height: 13px;
padding-bottom: 8px
}
.adyen-checkout__helper-text {
color: #687282
}
.adyen-checkout__label__text {
transition: color .2s ease-out
}
.adyen-checkout__label--focused .adyen-checkout__label__text {
color: #07b
}
.adyen-checkout__error-text, .adyen-checkout__label__text--error {
align-items: center;
color: #d0021b;
display: flex;
font-size: 12px;
font-weight: 400;
margin-top: 4px
}
.adyen-checkout__icon svg {
fill: currentColor
}
.adyen-checkout__open-invoice .adyen-checkout__input-wrapper--socialSecurityNumber + .adyen-checkout__error-text {
max-width: 380px
}
.adyen-checkout__radio_group + .adyen-checkout-input__inline-validation {
display: none
}
.adyen-checkout__radio_group__input {
opacity: 0;
position: absolute
}
.adyen-checkout__radio_group__label {
display: block;
font-size: 13px;
font-weight: 400;
line-height: 16px;
margin-bottom: 8px;
padding-bottom: 0;
padding-left: 24px;
position: relative
}
.adyen-checkout__radio_group__label:before {
background-color: #fff;
border: 1px solid #b9c4c9;
border-radius: 50%;
content: "";
height: 16px;
left: 0;
position: absolute;
top: 0;
transition: border-color .3s ease-out;
width: 16px
}
.adyen-checkout__radio_group__label:after {
-webkit-transform: scale(0);
background-color: #fff;
border-radius: 50%;
box-shadow: 0 1px 1px rgba(0, 15, 45, .25);
content: "";
display: block;
height: 6px;
left: 5px;
margin: 0 auto;
position: absolute;
top: 5px;
transform: scale(0);
transition: -webkit-transform .3s ease-out;
transition: transform .3s ease-out;
transition: transform .3s ease-out, -webkit-transform .3s ease-out;
width: 6px
}
.adyen-checkout__radio_group__label:hover {
border-color: #00a3ff;
cursor: pointer
}
.adyen-checkout__radio_group__input:checked + .adyen-checkout__radio_group__label:before, .adyen-checkout__radio_group__label--selected {
background-color: #00a3ff;
border: 0 solid transparent;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .26);
transition: all .3s ease-out
}
.adyen-checkout__radio_group__input:checked + .adyen-checkout__radio_group__label:after {
-webkit-transform: scale(1);
transform: scale(1)
}
.adyen-checkout__radio_group__label.adyen-checkout__radio_group__label--invalid:before {
border: 1px solid #d10244
}
.adyen-checkout__checkbox {
display: block
}
.adyen-checkout__checkbox > input[type=checkbox] {
opacity: 0;
pointer-events: none;
position: absolute
}
.adyen-checkout__checkbox__label {
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
color: #001b2b;
cursor: pointer;
display: inline-block;
font-size: 13px;
font-weight: 400;
line-height: 16px;
padding-left: 24px;
position: relative;
user-select: none
}
.adyen-checkout__checkbox__input + span:before {
-webkit-transform: rotate(37deg);
-webkit-transform-origin: 100% 100%;
border-color: transparent #fff #fff transparent;
border-radius: 0 2px 1px 2px;
border-style: solid;
border-width: 1px 2px 2px 1px;
content: "";
height: 11px;
left: 1px;
opacity: 0;
position: absolute;
top: 2px;
transform: rotate(37deg);
transform-origin: 100% 100%;
transition: opacity .2s ease-out;
width: 6px;
z-index: 1
}
.adyen-checkout__checkbox__input:checked + .adyen-checkout__checkbox__label:before {
opacity: 1
}
.adyen-checkout__checkbox__input + .adyen-checkout__checkbox__label:after {
background-color: #fff;
border: 1px solid #b9c4c9;
border-radius: 3px;
content: "";
height: 16px;
left: 0;
position: absolute;
top: 0;
transition: background .15s ease-out, border .05s ease-out, box-shadow .1s ease-out;
width: 16px;
z-index: 0
}
.adyen-checkout__checkbox__input:checked + .adyen-checkout__checkbox__label:after {
background-color: #00a3ff;
border: 1px solid #00a3ff
}
.adyen-checkout__checkbox__input:focus + span:after {
border: 1px solid #00a3ff;
box-shadow: 0 0 0 2px #91d7ff
}
.adyen-checkout__checkbox__input.adyen-checkout__checkbox__input--invalid + .adyen-checkout__checkbox__label:after {
border: 1px solid #d10244
}
.adyen-checkout__dropdown {
font-size: 16px;
max-width: 100%;
width: 200px
}
.adyen-checkout__dropdown--small {
width: 130px
}
.adyen-checkout__dropdown--large {
width: 300px
}
.adyen-checkout__dropdown__button {
background: #fff;
border: 1px solid #b9c4c9;
border-radius: 3px;
font-size: 16px;
height: 40px;
line-height: 20px;
outline: 0;
padding: 9px 20px 9px 8px;
transition: border .2s ease-out, box-shadow .2s ease-out;
width: 100%
}
.adyen-checkout__dropdown__button__icon {
margin-right: 8px;
max-height: 20px;
max-width: 32px
}
.adyen-checkout__dropdown__button--active, .adyen-checkout__dropdown__button:active, .adyen-checkout__dropdown__button:focus {
border-color: #00a3ff;
box-shadow: 0 0 0 2px #91d7ff
}
.adyen-checkout__dropdown__button--readonly, .adyen-checkout__dropdown__button--readonly.adyen-checkout__dropdown__button--active {
background: #e6e9eb;
color: #001b2b;
cursor: not-allowed
}
.adyen-checkout__dropdown__button--invalid {
border-color: #d10244
}
.adyen-checkout__dropdown__button__text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
.adyen-checkout__dropdown__list {
border-radius: 3px;
box-shadow: 0 2px 7px rgba(0, 15, 45, .3);
margin-top: 2px;
max-height: 360px;
z-index: 2
}
.adyen-checkout__dropdown__element {
-ms-hyphens: auto;
-webkit-hyphens: auto;
border: 1px solid transparent;
border-bottom-color: #e6e9eb;
cursor: pointer;
hyphens: auto;
line-height: 20px;
outline: 0;
padding: 8px;
transition: background .2s ease-out, border-color .2s ease-out;
word-break: break-word
}
.adyen-checkout__dropdown__element:last-child {
border-bottom: 0
}
.adyen-checkout__dropdown__element:active, .adyen-checkout__dropdown__element:focus, .adyen-checkout__dropdown__element:hover {
background: #f0f2f4
}
.adyen-checkout__dropdown__element:active, .adyen-checkout__dropdown__element:focus {
border-bottom-color: #00a3ff;
border-top-color: #00a3ff
}
.adyen-checkout__dropdown__element__icon {
margin-right: 8px;
max-height: 20px;
max-width: 32px
}
.adyen-checkout__dropdown + .adyen-checkout-input__inline-validation {
right: 32px
}
.adyen-checkout__select-list {
margin: 0;
padding: 0
}
.adyen-checkout__select-list__item {
background: #fff;
border-top: 1px solid #b9c4c9;
cursor: pointer;
display: inline-block;
font-size: 16px;
line-height: 20px;
outline: 0;
padding: 9px;
width: 100%
}
.adyen-checkout__select-list__item:first-child {
border-top: 0
}
.adyen-checkout__select-list__item:active, .adyen-checkout__select-list__item:focus, .adyen-checkout__select-list__item:hover {
background: rgba(145, 215, 255, .5)
}
.adyen-checkout__select-list__item--selected {
background: rgba(145, 215, 255, .5);
font-weight: 700
}
.adyen-checkout__input {
background: #fff;
border: 1px solid #b9c4c9;
border-radius: 3px;
color: #001b2b;
display: block;
font-family: inherit;
font-size: 16px;
height: 40px;
outline: none;
padding: 5px 8px;
position: relative;
transition: border .2s ease-out, box-shadow .2s ease-out;
width: 200px
}
.adyen-checkout__input:required {
box-shadow: none
}
.adyen-checkout__input-wrapper {
display: inline-block;
position: relative
}
.adyen-checkout__input-wrapper--block {
display: block
}
.adyen-checkout-input__inline-validation {
-webkit-transform: translateY(-50%);
height: 16px;
position: absolute;
right: 14px;
top: 50%;
transform: translateY(-50%);
width: 16px
}
.adyen-checkout-input__inline-validation--valid {
color: #039450
}
.adyen-checkout-input__inline-validation--invalid {
color: #d10244
}
.adyen-checkout__input.adyen-checkout__input--small {
width: 130px
}
.adyen-checkout__input.adyen-checkout__input--large {
width: 300px
}
.adyen-checkout__input.adyen-checkout__input--invalid {
border-color: #d10244
}
.adyen-checkout__input.adyen-checkout__input--valid {
border-bottom-color: #04ba65
}
.adyen-checkout__input--error {
border-color: #d0021b
}
.adyen-checkout__input::-webkit-input-placeholder {
color: #90a2bd;
font-weight: 200
}
.adyen-checkout__input:-ms-input-placeholder {
color: #90a2bd;
font-weight: 200
}
.adyen-checkout__input::-ms-input-placeholder {
color: #90a2bd;
font-weight: 200
}
.adyen-checkout__input::placeholder {
color: #90a2bd;
font-weight: 200
}
.adyen-checkout__input--active, .adyen-checkout__input:active, .adyen-checkout__input:focus {
border: 1px solid #00a3ff;
box-shadow: 0 0 0 2px #91d7ff
}
.adyen-checkout__input[readonly] {
background-color: #e6e9eb;
border-color: transparent;
color: #687282;
cursor: default
}
.adyen-checkout__fieldset {
color: #687282;
display: block;
padding-bottom: 30px;
width: 100%
}
.adyen-checkout__fieldset__title {
color: #687282;
display: block;
font-size: 11px;
font-weight: 700;
letter-spacing: 1px;
margin: 0;
padding: 0 0 20px;
text-transform: uppercase
}
.adyen-checkout__fieldset--readonly {
color: #001b2b;
font-size: 13px;
line-height: 19px;
margin: 0
}
.adyen-checkout__open-invoice .adyen-checkout__checkbox--consent-checkbox {
max-width: 540px
}
.adyen-checkout__open-invoice .adyen-checkout__checkbox + .adyen-checkout__open-invoice .adyen-checkout__fieldset {
padding-top: 30px
} }
.adyen-checkout__open-invoice .adyen-checkout__checkbox--consent-checkbox{ .adyen-checkout__open-invoice .adyen-checkout__checkbox--consent-checkbox{
max-width:540px max-width:540px
...@@ -874,164 +987,234 @@ ...@@ -874,164 +987,234 @@
.adyen-checkout__open-invoice .adyen-checkout__checkbox{ .adyen-checkout__open-invoice .adyen-checkout__checkbox{
margin:0 0 20px margin:0 0 20px
} }
.adyen-checkout__applepay__button{
height:40px; .adyen-checkout__applepay__button {
width:240px height: 40px;
} width: 240px
.adyen-checkout__card-input__form{ }
transition:opacity .25s ease-out
} .adyen-checkout__card-input__form {
.adyen-checkout__card__exp-cvc{ transition: opacity .25s ease-out
display:flex }
}
.adyen-checkout__card__cardNumber{ .adyen-checkout__card__exp-cvc {
max-width:400px display: flex
} }
.adyen-checkout__card__cardNumber__input{
padding:5px 8px 5px 57px .adyen-checkout__card__cardNumber {
} max-width: 400px
.adyen-checkout__card__exp-date__input--oneclick{ }
font-weight:400;
height:40px; .adyen-checkout__card__cardNumber__input {
line-height:40px padding: 5px 8px 5px 57px
} }
.adyen-checkout__card__exp-cvc .adyen-checkout__field{
margin-bottom:0; .adyen-checkout__card__exp-date__input--oneclick {
margin-right:24px font-weight: 400;
} height: 40px;
.adyen-checkout__card-input .adyen-checkout__store-details{ line-height: 40px
margin-top:16px }
}
.adyen-checkout__giropay__results{ .adyen-checkout__card__exp-cvc .adyen-checkout__field {
background:#fff; margin-bottom: 0;
border:1px solid #b9c4c9; margin-right: 24px
border-radius:4px; }
max-height:140px;
min-height:100px; .adyen-checkout__card-input .adyen-checkout__store-details {
overflow-y:scroll; margin-top: 16px
width:100% }
}
.adyen-checkout__giropay__no-results{ .adyen-checkout__giropay__results {
color:#687282; background: #fff;
display:block; border: 1px solid #b9c4c9;
font-size:13px; border-radius: 4px;
padding:0 0 0 2px max-height: 140px;
} min-height: 100px;
.adyen-checkout__giropay__placeholder{ overflow-y: scroll;
color:#90a2bd; width: 100%
display:block; }
font-weight:200;
padding:0 0 0 2px .adyen-checkout__giropay__no-results {
} color: #687282;
.adyen-checkout__giropay__loading{ display: block;
display:block; font-size: 13px;
min-height:100px padding: 0 0 0 2px
} }
.adyen-checkout__giropay__loading .adyen-checkout__spinner__wrapper{
display:inline-block; .adyen-checkout__giropay__placeholder {
vertical-align:middle color: #90a2bd;
} display: block;
.adyen-checkout__giropay__loading-text{ font-weight: 200;
color:#687282; padding: 0 0 0 2px
font-size:13px; }
line-height:16px;
vertical-align:middle .adyen-checkout__giropay__loading {
} display: block;
.adyen-checkout__giropay__error{ min-height: 100px
color:#d0021b; }
font-size:13px
} .adyen-checkout__giropay__loading .adyen-checkout__spinner__wrapper {
.adyen-checkout__phone-input{ display: inline-block;
display:flex vertical-align: middle
} }
.adyen-checkout__phone-input__prefix{
margin-right:.5em .adyen-checkout__giropay__loading-text {
} color: #687282;
.adyen-checkout__phone-input .adyen-checkout__field{ font-size: 13px;
margin-bottom:0 line-height: 16px;
} vertical-align: middle
.adyen-checkout__iban-input__number{ }
padding:5px 36px 5px 8px;
text-transform:uppercase .adyen-checkout__giropay__error {
} color: #d0021b;
.adyen-checkout__wechatpay{ font-size: 13px
background:#fff; }
border:1px solid #dde1e3;
border-radius:3px; .adyen-checkout__phone-input {
min-height:443px; display: flex
padding:40px; }
text-align:center
} .adyen-checkout__phone-input__prefix {
.adyen-checkout__wechatpay__brand-logo{ margin-right: .5em
height:20px; }
width:109px
} .adyen-checkout__phone-input .adyen-checkout__field {
.adyen-checkout__wechatpay__subtitle{ margin-bottom: 0
margin-top:32px }
}
.adyen-checkout__wechatpay__payment_amount,.adyen-checkout__wechatpay__subtitle{ .adyen-checkout__iban-input__number {
color:#001b2b; padding: 5px 36px 5px 8px;
font-size:16px; text-transform: uppercase
line-height:19px }
}
.adyen-checkout__wechatpay__progress{ .adyen-checkout__threeds2__challenge-container {
background:#d4d9db; background-color: transparent;
border-radius:25px; box-sizing: border-box;
height:4px; display: block;
margin:32px auto 12px; overflow: auto;
padding-right:3%; width: 100%
width:152px }
}
.adyen-checkout__wechatpay__progress>span{ .adyen-checkout__threeds2__challenge-container--01 {
background:#00a3ff; height: 400px;
border-radius:25px; width: 250px
display:block; }
height:100%
} .adyen-checkout__threeds2__challenge-container--02 {
.adyen-checkout__wechatpay__countdown{ height: 400px;
color:#687282; width: 390px
font-size:13px }
}
.adyen-checkout__wechatpay .adyen-checkout__spinner__wrapper{ .adyen-checkout__threeds2__challenge-container--03 {
margin:60px 0 height: 600px;
} width: 500px
.adyen-checkout__alert{ }
align-items:flex-start;
background-color:#00a3ff; .adyen-checkout__threeds2__challenge-container--04 {
border-radius:3px; height: 400px;
color:#fff; width: 600px
display:flex; }
justify-content:space-between;
line-height:1; .adyen-checkout__threeds2_challenge-container--05 {
margin:0; height: 100%;
padding:12px width: 100%
} }
.adyen-checkout__alert--error{
background-color:#d81b4a .adyen-checkout__wechatpay {
} background: #fff;
.adyen-checkout__alert--success{ border: 1px solid #dde1e3;
background-color:#0abf53 border-radius: 3px;
} min-height: 443px;
.adyen-checkout__alert--info{ padding: 40px;
background-color:#00a3ff text-align: center
} }
.adyen-checkout__sdk,.adyen-checkout__sdk *,.adyen-checkout__sdk * :before,.adyen-checkout__sdk :after{
box-sizing:border-box .adyen-checkout__wechatpay__brand-logo {
} height: 20px;
.adyen-checkout__payment-methods-list{ width: 109px
border-radius:3px }
}
.adyen-checkout__payment-methods-list--loading{ .adyen-checkout__wechatpay__subtitle {
-moz-user-select:none; margin-top: 32px
-ms-user-select:none; }
-webkit-user-select:none;
pointer-events:none; .adyen-checkout__wechatpay__payment_amount, .adyen-checkout__wechatpay__subtitle {
user-select:none color: #001b2b;
} font-size: 16px;
.adyen-checkout__link{ line-height: 19px
color:#687282; }
font-size:13px;
text-decoration:underline .adyen-checkout__wechatpay__progress {
background: #d4d9db;
border-radius: 25px;
height: 4px;
margin: 32px auto 12px;
padding-right: 3%;
width: 152px
}
.adyen-checkout__wechatpay__progress > span {
background: #00a3ff;
border-radius: 25px;
display: block;
height: 100%
}
.adyen-checkout__wechatpay__countdown {
color: #687282;
font-size: 13px
}
.adyen-checkout__wechatpay .adyen-checkout__spinner__wrapper {
margin: 60px 0
}
.adyen-checkout__alert {
align-items: flex-start;
background-color: #00a3ff;
border-radius: 3px;
color: #fff;
display: flex;
justify-content: space-between;
line-height: 1;
margin: 0;
padding: 12px
} }
.adyen-checkout__alert--error {
background-color: #d81b4a
}
.adyen-checkout__alert--success {
background-color: #0abf53
}
.adyen-checkout__alert--info {
background-color: #00a3ff
}
.adyen-checkout__sdk, .adyen-checkout__sdk *, .adyen-checkout__sdk * :before, .adyen-checkout__sdk :after {
box-sizing: border-box
}
.adyen-checkout__payment-methods-list {
border-radius: 3px
}
.adyen-checkout__payment-methods-list--loading {
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
pointer-events: none;
user-select: none
}
.adyen-checkout__link {
color: #687282;
font-size: 13px;
text-decoration: underline
}
/* never show the close button as this will result in errors */
.threeDS2Modal .action-close {display:none; }
/* Checkout component Adyen styling end */ /* Checkout component Adyen styling end */
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
define(
[
'Magento_Checkout/js/model/url-builder',
'mage/storage'
],
function (urlBuilder, storage) {
'use strict';
return {
/**
* Create a Payment to define if 3DS 2.0 flow needs to be activated
* @param response
*/
processPayment: function (data) {
var payload = {
"payload": JSON.stringify(data)
};
var serviceUrl = urlBuilder.createUrl('/adyen/payment', {});
return storage.post(
serviceUrl,
JSON.stringify(payload),
true
);
},
/**
* The results that the 3DS2 components returns in the onComplete callback needs to be sent to the
* backend to the /adyen/threeDS2Process endpoint and based on the response render a new threeDS2
* component or place the order (validateThreeDS2OrPlaceOrder)
* @param response
*/
processThreeDS2: function (data) {
var payload = {
"payload": JSON.stringify(data)
};
var serviceUrl = urlBuilder.createUrl('/adyen/threeDS2Process', {});
return storage.post(
serviceUrl,
JSON.stringify(payload),
true
);
}
};
}
);
!function(e,n){"object"===typeof exports&&"object"===typeof module?module.exports=n():"function"===typeof define&&define.amd?define([],n):"object"===typeof exports?exports.ThreedDS2Utils=n():e.ThreedDS2Utils=n()}(this,function(){return function(e){var n={};function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:r})},t.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var o in e)t.d(r,o,function(n){return e[n]}.bind(null,o));return r},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){"use strict";t.r(n);var r={container:void 0},o={"01":["250px","400px"],"02":["390px","400px"],"03":["500px","600px"],"04":["600px","400px"],"05":["100%","100%"]};function a(e){return o.hasOwnProperty(e)?e:"01"}var i={createIframe:function(e,n){var t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"0",o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"0",a=arguments.length>4?arguments[4]:void 0;if(!n||0===n.length)throw new Error("Name parameter missing for iframe");e instanceof HTMLElement?r.container=e:r.container=document.body;var i=document.createElement("iframe");i.classList.add(n+"Class"),i.width=t,i.height=o,i.name=n,i.setAttribute("frameborder","0"),i.setAttribute("border","0");var d=document.createTextNode("<p>Your browser does not support iframes.</p>");return i.appendChild(d),r.container.appendChild(i),function(e,n){e.attachEvent?e.attachEvent("onload",function(){n&&"function"===typeof n&&n(e.contentWindow)}):e.onload=function(){n&&"function"===typeof n&&n(e.contentWindow)}}(i,a),i},createForm:function(e,n,t,r,o){if(!e||!n||!t||!r||!o)throw new Error("Not all required parameters provided for form creation");if(0===e.length||0===n.length||0===t.length||0===r.length||0===o.length)throw new Error("Not all required parameters have suitable values");var a=document.createElement("form");a.style.display="none",a.name=e,a.action=n,a.method="POST",a.target=t;var i=document.createElement("input");return i.name=r,i.value=o,a.appendChild(i),a},getBrowserInfo:function(){var e=window&&window.screen?window.screen.width:"",n=window&&window.screen?window.screen.height:"",t=window&&window.screen?window.screen.colorDepth:"",r=window&&window.navigator?window.navigator.userAgent:"",o=!(!window||!window.navigator)&&navigator.javaEnabled(),a="";return window&&window.navigator&&(a=window.navigator.language?window.navigator.language:window.navigator.browserLanguage),{screenWidth:e,screenHeight:n,colorDepth:t,userAgent:r,timeZoneOffset:(new Date).getTimezoneOffset(),language:a,javaEnabled:o}},base64Url:{encode:function(e){var n=window.btoa(e).split("=")[0];return n=(n=n.replace("/+/g","-")).replace("///g","_")},decode:function(e){var n=e;switch((n=(n=n.replace("/-/g","+")).replace("/_/g","/")).length%4){case 0:break;case 2:n+="==";break;case 3:n+="=";break;default:window.console&&window.console.log&&window.console.log("### base64url::decodeBase64URL:: Illegal base64url string!")}try{return window.atob(n)}catch(e){throw new Error(e)}}},config:{challengeWindowSizes:o,validateChallengeWindowSize:a,getChallengeWindowSize:function(e){return o[a(e)]},THREEDS_METHOD_TIMEOUT:1e4,CHALLENGE_TIMEOUT:6e5}};n.default=i}]).default});
\ No newline at end of file
...@@ -30,9 +30,16 @@ define( ...@@ -30,9 +30,16 @@ define(
'Magento_Checkout/js/model/quote', 'Magento_Checkout/js/model/quote',
'Adyen_Payment/js/model/installments', 'Adyen_Payment/js/model/installments',
'mage/url', 'mage/url',
'Magento_Vault/js/view/payment/vault-enabler' 'Magento_Vault/js/view/payment/vault-enabler',
'Magento_Checkout/js/model/url-builder',
'mage/storage',
'Magento_Checkout/js/model/full-screen-loader',
'Magento_Paypal/js/action/set-payment-method',
'Magento_Checkout/js/action/select-payment-method',
'Adyen_Payment/js/threeds2-js-utils',
'Adyen_Payment/js/model/threeds2'
], ],
function ($, ko, Component, customer, creditCardData, additionalValidators, quote, installments, url, VaultEnabler) { function ($, ko, Component, customer, creditCardData, additionalValidators, quote, installments, url, VaultEnabler, urlBuilder, storage, fullScreenLoader, setPaymentMethodAction, selectPaymentMethodAction, threeDS2Utils, threeds2) {
'use strict'; 'use strict';
...@@ -43,7 +50,7 @@ define( ...@@ -43,7 +50,7 @@ define(
defaults: { defaults: {
template: 'Adyen_Payment/payment/cc-form', template: 'Adyen_Payment/payment/cc-form',
creditCardOwner: '', creditCardOwner: '',
setStoreCc: false, storeCc: false,
installment: '', installment: '',
creditCardDetailsValid: false creditCardDetailsValid: false
}, },
...@@ -56,6 +63,14 @@ define( ...@@ -56,6 +63,14 @@ define(
this.vaultEnabler.setPaymentCode(this.getVaultCode()); this.vaultEnabler.setPaymentCode(this.getVaultCode());
this.vaultEnabler.isActivePaymentTokenEnabler(false); this.vaultEnabler.isActivePaymentTokenEnabler(false);
// initialize adyen component for general use
this.checkout = new AdyenCheckout({
locale: this.getLocale(),
risk: {
enabled: false
}
});
return this; return this;
}, },
initObservable: function () { initObservable: function () {
...@@ -67,7 +82,6 @@ define( ...@@ -67,7 +82,6 @@ define(
'securityCode', 'securityCode',
'expiryMonth', 'expiryMonth',
'expiryYear', 'expiryYear',
'setStoreCc',
'installment', 'installment',
'creditCardDetailsValid', 'creditCardDetailsValid',
'variant', 'variant',
...@@ -77,6 +91,13 @@ define( ...@@ -77,6 +91,13 @@ define(
return this; return this;
}, },
getInstallments: installments.getInstallments(), getInstallments: installments.getInstallments(),
/**
* Returns true if card details can be stored
* @returns {*|boolean}
*/
getEnableStoreDetails: function () {
return this.canCreateBillingAgreement() && !this.isVaultEnabled();
},
/** /**
* Renders the secure fields, * Renders the secure fields,
* creates the card component, * creates the card component,
...@@ -85,6 +106,7 @@ define( ...@@ -85,6 +106,7 @@ define(
*/ */
renderSecureFields: function () { renderSecureFields: function () {
var self = this; var self = this;
if (!self.getOriginKey()) { if (!self.getOriginKey()) {
return; return;
} }
...@@ -95,20 +117,18 @@ define( ...@@ -95,20 +117,18 @@ define(
var allInstallments = self.getAllInstallments(); var allInstallments = self.getAllInstallments();
var cardNode = document.getElementById('cardContainer'); var cardNode = document.getElementById('cardContainer');
var checkout = new AdyenCheckout({ self.cardComponent = self.checkout.create('card', {
locale: self.getLocale()
});
var card = checkout.create('card', {
originKey: self.getOriginKey(), originKey: self.getOriginKey(),
loadingContext: self.getLoadingContext(), loadingContext: self.getLoadingContext(),
type: 'card', type: 'card',
hasHolderName: true, hasHolderName: true,
holderNameRequired: true, holderNameRequired: true,
enableStoreDetails: self.getEnableStoreDetails(),
groupTypes: self.getAvailableCardTypeAltCodes(), groupTypes: self.getAvailableCardTypeAltCodes(),
onChange: function (state, component) { onChange: function (state, component) {
if (!!state.isValid && !component.state.errors.encryptedSecurityCode) { if (!!state.isValid && !component.state.errors.encryptedSecurityCode) {
self.storeCc = !!state.data.storeDetails;
self.variant(state.brand); self.variant(state.brand);
self.creditCardNumber(state.data.encryptedCardNumber); self.creditCardNumber(state.data.encryptedCardNumber);
self.expiryMonth(state.data.encryptedExpiryMonth); self.expiryMonth(state.data.encryptedExpiryMonth);
...@@ -173,16 +193,87 @@ define( ...@@ -173,16 +193,87 @@ define(
installments.setInstallments(0); installments.setInstallments(0);
} }
} }
}).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) {
var self = this;
var threeDS2Node = document.getElementById('threeDS2Container');
if (type == "IdentifyShopper") {
self.threeDS2IdentifyComponent = self.checkout
.create('threeDS2DeviceFingerprint', {
fingerprintToken: token,
onComplete: function (result) {
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
}).error(function () {
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
}
}); });
card.mount(cardNode); self.threeDS2IdentifyComponent.mount(threeDS2Node);
} else if (type == "ChallengeShopper") {
fullScreenLoader.stopLoader();
var popupModal = $('#threeDS2Modal').modal({
// disable user to hide popup
clickableOverlay: false,
// empty buttons, we don't need that
buttons: [],
modalClass: 'threeDS2Modal'
});
popupModal.modal("openModal");
self.threeDS2ChallengeComponent = self.checkout
.create('threeDS2Challenge', {
challengeToken: token,
onComplete: function (result) {
popupModal.modal("closeModal");
fullScreenLoader.startLoader();
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON);
}).error(function () {
popupModal.modal("closeModal");
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
}
});
self.threeDS2ChallengeComponent.mount(threeDS2Node);
}
}, },
/** /**
* Builds the payment details part of the payment information reqeust * Builds the payment details part of the payment information reqeust
* *
* @returns {{method: *, additional_data: {cc_type: *, number: *, cvc, expiryMonth: *, expiryYear: *, holderName: *, store_cc: *, number_of_installments: *}}} * @returns {{method: *, additional_data: {card_brand: *, cc_type: *, number: *, cvc: *, expiryMonth: *, expiryYear: *, holderName: *, store_cc: (boolean|*), number_of_installments: *, java_enabled: boolean, screen_color_depth: number, screen_width, screen_height, timezone_offset: *}}}
*/ */
getData: function () { getCcData: function () {
const browserInfo = threeDS2Utils.getBrowserInfo();
var data = { var data = {
'method': this.item.method, 'method': this.item.method,
additional_data: { additional_data: {
...@@ -193,13 +284,35 @@ define( ...@@ -193,13 +284,35 @@ define(
'expiryMonth': this.expiryMonth(), 'expiryMonth': this.expiryMonth(),
'expiryYear': this.expiryYear(), 'expiryYear': this.expiryYear(),
'holderName': this.creditCardOwner(), 'holderName': this.creditCardOwner(),
'store_cc': this.setStoreCc(), 'store_cc': this.storeCc,
'number_of_installments': this.installment() 'number_of_installments': this.installment(),
'java_enabled': browserInfo.javaEnabled,
'screen_color_depth': browserInfo.colorDepth,
'screen_width': browserInfo.screenWidth,
'screen_height': browserInfo.screenHeight,
'timezone_offset': browserInfo.timeZoneOffset,
'language': browserInfo.language
} }
}; };
this.vaultEnabler.visitAdditionalData(data); this.vaultEnabler.visitAdditionalData(data);
return data; return data;
}, },
/**
* Get data for place order
* @returns {{method: *}}
*/
getData: function () {
return {
'method': this.item.method,
additional_data: {
'card_brand': this.variant(),
'cc_type': this.creditCardType(),
'store_cc': this.storeCc,
'number_of_installments': this.installment()
}
};
},
/** /**
* Returns state of place order button * Returns state of place order button
* @returns {boolean} * @returns {boolean}
...@@ -224,11 +337,34 @@ define( ...@@ -224,11 +337,34 @@ define(
} }
if (this.validate() && additionalValidators.validate()) { if (this.validate() && additionalValidators.validate()) {
this.isPlaceOrderActionAllowed(false); fullScreenLoader.startLoader();
self.isPlaceOrderActionAllowed(false);
this.getPlaceOrderDeferredObject() threeds2.processPayment(this.getCcData()).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON);
}).error(function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true);
});
}
},
/**
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
validateThreeDS2OrPlaceOrder: function (responseJSON) {
var self = this;
var response = JSON.parse(responseJSON);
if (!!response.threeDS2) {
// render component
self.renderThreeDS2Component(response.type, response.token);
} else {
self.getPlaceOrderDeferredObject()
.fail( .fail(
function () { function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true); self.isPlaceOrderActionAllowed(true);
} }
).done( ).done(
...@@ -241,11 +377,7 @@ define( ...@@ -241,11 +377,7 @@ define(
} }
} }
); );
return true;
} }
return false;
}, },
/** /**
* Validates the payment date when clicking the pay button * Validates the payment date when clicking the pay button
......
...@@ -81,7 +81,10 @@ define( ...@@ -81,7 +81,10 @@ define(
* @type {AdyenCheckout} * @type {AdyenCheckout}
*/ */
self.checkoutComponent = new AdyenCheckout({ self.checkoutComponent = new AdyenCheckout({
locale: self.getLocale() locale: self.getLocale(),
risk: {
enabled: false
}
}); });
// reset variable: // reset variable:
......
...@@ -32,10 +32,16 @@ define( ...@@ -32,10 +32,16 @@ define(
'Magento_Checkout/js/action/redirect-on-success', 'Magento_Checkout/js/action/redirect-on-success',
'uiLayout', 'uiLayout',
'Magento_Ui/js/model/messages', 'Magento_Ui/js/model/messages',
'mage/url',
'Adyen_Payment/js/threeds2-js-utils',
'Magento_Checkout/js/model/full-screen-loader',
'Magento_Paypal/js/action/set-payment-method',
'Magento_Checkout/js/model/url-builder',
'mage/storage',
'Magento_Checkout/js/action/place-order', 'Magento_Checkout/js/action/place-order',
'mage/url' 'Adyen_Payment/js/model/threeds2'
], ],
function (ko, _, $, Component, selectPaymentMethodAction, additionalValidators, quote, checkoutData, redirectOnSuccessAction, layout, Messages, placeOrderAction, url) { function (ko, _, $, Component, selectPaymentMethodAction, additionalValidators, quote, checkoutData, redirectOnSuccessAction, layout, Messages, url, threeDS2Utils, fullScreenLoader, setPaymentMethodAction, urlBuilder, storage, placeOrderAction, threeds2) {
'use strict'; 'use strict';
...@@ -59,7 +65,7 @@ define( ...@@ -59,7 +65,7 @@ define(
.observe([ .observe([
'recurringDetailReference', 'recurringDetailReference',
'creditCardType', 'creditCardType',
'creditCardVerificationNumber', 'encryptedCreditCardVerificationNumber',
'variant', 'variant',
'numberOfInstallments' 'numberOfInstallments'
]); ]);
...@@ -104,7 +110,10 @@ define( ...@@ -104,7 +110,10 @@ define(
var checkout = new AdyenCheckout({ var checkout = new AdyenCheckout({
locale: self.getLocale(), locale: self.getLocale(),
originKey: self.getOriginKey(), originKey: self.getOriginKey(),
loadingContext: self.getLoadingContext() loadingContext: self.getLoadingContext(),
risk: {
enabled: false
}
}); });
// convert to list so you can iterate // convert to list so you can iterate
...@@ -165,7 +174,13 @@ define( ...@@ -165,7 +174,13 @@ define(
return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed(); return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed();
}, },
/** /**
* Custom place order function
*
* @override * @override
*
* @param data
* @param event
* @returns {boolean}
*/ */
placeOrder: function (data, event) { placeOrder: function (data, event) {
var self = this; var self = this;
...@@ -173,38 +188,31 @@ define( ...@@ -173,38 +188,31 @@ define(
if (event) { if (event) {
event.preventDefault(); event.preventDefault();
} }
// only use installments for cards // only use installments for cards
if (self.agreement_data.card) { if (self.agreement_data.card) {
if (self.hasVerification()) { if (self.hasVerification()) {
var options = {enableValidations: false}; var options = {enableValidations: false};
} }
// set payment method to adyen_hpp
// TODO can observer in front-end this not needed
numberOfInstallments(self.installment); numberOfInstallments(self.installment);
} }
// in different context so need custom place order logic
if (this.validate() && additionalValidators.validate()) { if (this.validate() && additionalValidators.validate()) {
fullScreenLoader.startLoader();
self.isPlaceOrderActionAllowed(false); self.isPlaceOrderActionAllowed(false);
this.getPlaceOrderDeferredObject() threeds2.processPayment(this.getCcData()).done(function (responseJSON) {
.fail( self.validateThreeDS2OrPlaceOrder(responseJSON);
function () { }).error(function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true); self.isPlaceOrderActionAllowed(true);
});
return false;
} }
).done(
function () {
self.afterPlaceOrder();
// use custom redirect Link for supporting 3D secure
window.location.replace(url.build(window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl));
}
);
return true;
}
return false; return false;
}, },
/** /**
* Renders the secure CVC field, * Renders the secure CVC field,
* creates the card component, * creates the card component,
...@@ -275,6 +283,123 @@ define( ...@@ -275,6 +283,123 @@ define(
window.adyencheckout = oneClickCard; window.adyencheckout = oneClickCard;
}, },
/**
* Builds the payment details part of the payment information reqeust
*
* @returns {{method: *, additional_data: {card_brand: *, cc_type: *, number: *, cvc: *, expiryMonth: *, expiryYear: *, holderName: *, store_cc: (boolean|*), number_of_installments: *, java_enabled: boolean, screen_color_depth: number, screen_width, screen_height, timezone_offset: *}}}
*/
getCcData: function () {
var self = this;
var browserInfo = threeDS2Utils.getBrowserInfo();
var data = {
'method': self.method,
additional_data: {
'variant': variant(),
'recurring_detail_reference': recurringDetailReference(),
'store_cc': true,
'number_of_installments': numberOfInstallments(),
'cvc': self.encryptedCreditCardVerificationNumber,
'java_enabled': browserInfo.javaEnabled,
'screen_color_depth': browserInfo.colorDepth,
'screen_width': browserInfo.screenWidth,
'screen_height': browserInfo.screenHeight,
'timezone_offset': browserInfo.timeZoneOffset,
'language': browserInfo.language
}
};
return data;
},
/**
* Based on the response we can start a 3DS2 validation or place the order
* @param responseJSON
*/
validateThreeDS2OrPlaceOrder: function (responseJSON) {
var self = this;
var response = JSON.parse(responseJSON);
if (!!response.threeDS2) {
// render component
self.renderThreeDS2Component(response.type, response.token);
} else {
this.getPlaceOrderDeferredObject()
.fail(
function () {
self.isPlaceOrderActionAllowed(true);
}
).done(
function () {
self.afterPlaceOrder();
window.location.replace(url.build(window.checkoutConfig.payment[quote.paymentMethod().method].redirectUrl));
}
);
}
},
/**
* 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) {
var self = this;
var threeDS2Node = document.getElementById('threeDS2ContainerOneClick');
if (type == "IdentifyShopper") {
self.threeDS2Component = checkout.create('threeDS2DeviceFingerprint', {
fingerprintToken: token,
onComplete: function (result) {
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
}).error(function () {
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
}
});
} else if (type == "ChallengeShopper") {
fullScreenLoader.stopLoader();
var popupModal = $('#threeDS2ModalOneClick').modal({
// disable user to hide popup
clickableOverlay: false,
// empty buttons, we don't need that
buttons: [],
modalClass: 'threeDS2Modal'
});
popupModal.modal("openModal");
self.threeDS2Component = checkout
.create('threeDS2Challenge', {
challengeToken: token,
onComplete: function (result) {
popupModal.modal("closeModal");
fullScreenLoader.startLoader();
threeds2.processThreeDS2(result.data).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON)
}).error(function () {
self.isPlaceOrderActionAllowed(true);
fullScreenLoader.stopLoader();
});
},
onError: function (error) {
console.log(JSON.stringify(error));
}
});
}
self.threeDS2Component.mount(threeDS2Node);
},
/** /**
* We use the billingAgreements to save the oneClick stored payments but we don't store the * We use the billingAgreements to save the oneClick stored payments but we don't store the
* details object that we get from the paymentMethods call. This function is a fix for BCMC. * details object that we get from the paymentMethods call. This function is a fix for BCMC.
...@@ -282,7 +407,7 @@ define( ...@@ -282,7 +407,7 @@ define(
* should be removed * should be removed
* @returns {*} * @returns {*}
*/ */
getOneclickDetails: function() { getOneclickDetails: function () {
var self = this; var self = this;
if (self.agreement_data.variant === 'bcmc') { if (self.agreement_data.variant === 'bcmc') {
...@@ -310,9 +435,7 @@ define( ...@@ -310,9 +435,7 @@ define(
variant: variant(), variant: variant(),
recurring_detail_reference: recurringDetailReference(), recurring_detail_reference: recurringDetailReference(),
number_of_installments: numberOfInstallments(), number_of_installments: numberOfInstallments(),
cvc: self.encryptedCreditCardVerificationNumber, cvc: self.encryptedCreditCardVerificationNumber
expiryMonth: self.creditCardExpMonth(),
expiryYear: self.creditCardExpYear()
} }
}; };
}, },
...@@ -345,7 +468,7 @@ define( ...@@ -345,7 +468,7 @@ define(
getMessageContainer: function () { getMessageContainer: function () {
return messageContainer; return messageContainer;
}, },
getOriginKey:function () { getOriginKey: function () {
return self.getOriginKey(); return self.getOriginKey();
}, },
isPlaceOrderActionAllowed: function () { isPlaceOrderActionAllowed: function () {
......
...@@ -77,6 +77,9 @@ ...@@ -77,6 +77,9 @@
<div afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div> <div afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div>
</div> </div>
<div id="threeDS2Modal">
<div id="threeDS2Container"></div>
</div>
<!-- ko if: (hasInstallments())--> <!-- ko if: (hasInstallments())-->
...@@ -117,23 +120,6 @@ ...@@ -117,23 +120,6 @@
</div> </div>
<!-- /ko --> <!-- /ko -->
<!-- ko if: (canCreateBillingAgreement() && !isVaultEnabled())-->
<div class="field choice">
<input type="checkbox"
name="payment[store_cc]"
autocomplete="off"
class="checkbox"
data-bind="attr: {title: $t('Remember Me')}, checked: setStoreCc"
/>
<label data-bind="attr: {for: getCode() + '_remember_details'}" class="label">
<span><!-- ko text: $t('Remember these details')--><!-- /ko --></span>
</label>
</div>
<!-- /ko -->
</fieldset> </fieldset>
</form> </form>
......
...@@ -134,6 +134,11 @@ ...@@ -134,6 +134,11 @@
</div> </div>
</div> </div>
<!-- /ko --> <!-- /ko -->
<div id="threeDS2ModalOneClick">
<div id="threeDS2ContainerOneClick"></div>
</div>
</fieldset> </fieldset>
</form> </form>
<div class="checkout-agreements-block"> <div class="checkout-agreements-block">
......
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