We will work on Apr 26th (Saturday) and will be off from Apr 30th (Wednesday) until May 2nd (Friday) for public holiday 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 @@
*
* 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.
* See the LICENSE file for more info.
*
* 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(
$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;
}
public function initiate($payload);
}
<?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
$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[]
* @throws AdyenException
......
......@@ -87,7 +87,7 @@ class Result extends \Magento\Framework\App\Action\Action
$this->_orderHistoryFactory = $orderHistoryFactory;
$this->_session = $session;
$this->_adyenLogger = $adyenLogger;
$this->storeManager = $storeManager;
$this->storeManager = $storeManager;
parent::__construct($context);
}
......@@ -306,10 +306,10 @@ class Result extends \Magento\Framework\App\Action\Action
$merchantSigNotification = $response['merchantSig'];
// do it like this because $_GET is converting dot to underscore
$queryString = $_SERVER['QUERY_STRING'];
$result = [];
$pairs = explode("&", $queryString);
// do it like this because $_GET is converting dot to underscore
$queryString = $_SERVER['QUERY_STRING'];
$result = [];
$pairs = explode("&", $queryString);
foreach ($pairs as $pair) {
$nv = explode("=", $pair);
......@@ -318,12 +318,12 @@ class Result extends \Magento\Framework\App\Action\Action
$result[$name] = $value;
}
// do not include the merchantSig in the merchantSig calculation
unset($result['merchantSig']);
// do not include the merchantSig in the merchantSig calculation
unset($result['merchantSig']);
// Sign request using secret key
$hmacKey = $this->_adyenHelper->getHmac();
$merchantSig = \Adyen\Util\Util::calculateSha256Signature($hmacKey, $result);
// Sign request using secret key
$hmacKey = $this->_adyenHelper->getHmac();
$merchantSig = \Adyen\Util\Util::calculateSha256Signature($hmacKey, $result);
if (strcmp($merchantSig, $merchantSigNotification) === 0) {
return true;
......
......@@ -55,6 +55,13 @@ class TransactionPayment implements ClientInterface
public function placeRequest(\Magento\Payment\Gateway\Http\TransferInterface $transferObject)
{
$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();
$service = new \Adyen\Service\Checkout($client);
......
......@@ -31,22 +31,22 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
class AddressDataBuilder implements BuilderInterface
{
/**
* @var \Adyen\Payment\Helper\Data
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenHelper;
private $adyenRequestsHelper;
/**
* AddressDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
public function __construct(
\Adyen\Payment\Helper\Data $adyenHelper
\Adyen\Payment\Helper\Requests $adyenRequestsHelper
)
{
$this->adyenHelper = $adyenHelper;
$this->adyenRequestsHelper = $adyenRequestsHelper;
}
/**
* Add delivery\billing details into request
*
......@@ -59,76 +59,8 @@ class AddressDataBuilder implements BuilderInterface
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$order = $paymentDataObject->getOrder();
$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();
if ($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;
return $this->adyenRequestsHelper->buildAddressData([], $billingAddress, $shippingAddress);
}
}
......@@ -29,18 +29,29 @@ use Magento\Payment\Gateway\Request\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
* @return array
*/
public function build(array $buildSubject)
{
return [
'browserInfo' =>
[
'userAgent' => $_SERVER['HTTP_USER_AGENT'],
'acceptHeader' => $_SERVER['HTTP_ACCEPT']
]
];
return $this->adyenRequestsHelper->buildBrowserData();
}
}
......@@ -102,7 +102,7 @@ class CaptureDataBuilder implements BuilderInterface
// The latest invoice will contain only the selected items(and quantities) for the (partial) capture
$latestInvoice = $invoices->getLastItem();
foreach ($latestInvoice->getItemsCollection() as $invoiceItem) {
foreach ($latestInvoice->getItems() as $invoiceItem) {
++$count;
$numberOfItems = (int)$invoiceItem->getQty();
$formFields = $this->adyenHelper->createOpenInvoiceLineItem(
......@@ -113,7 +113,7 @@ class CaptureDataBuilder implements BuilderInterface
$currency,
$invoiceItem->getTaxAmount(),
$invoiceItem->getPriceInclTax(),
$invoiceItem->getTaxPercent(),
$invoiceItem->getOrderItem()->getTaxPercent(),
$numberOfItems,
$payment,
$invoiceItem->getId()
......
......@@ -24,91 +24,30 @@
namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenCcDataAssignObserver;
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
* @return mixed
* @return array|mixed
* @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);
// 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
$payment->unsAdditionalInformation("paymentsResponse");
} else {
$errorMsg = __('Error with payment method please select different payment method.');
throw new \Magento\Framework\Exception\LocalizedException(__($errorMsg));
}
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;
}
}
......@@ -148,8 +148,8 @@ class CheckoutDataBuilder implements BuilderInterface
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
) || $this->adyenHelper->isPaymentMethodAfterpayTouchMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
) || $this->adyenHelper->isPaymentMethodOneyMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
) || $this->adyenHelper->isPaymentMethodOneyMethod(
$payment->getAdditionalInformation(AdyenHppDataAssignObserver::BRAND_CODE)
)
) {
......@@ -219,15 +219,15 @@ class CheckoutDataBuilder implements BuilderInterface
foreach ($this->quote->getAllVisibleItems() as $item) {
$numberOfItems = (int)$item->getQtyOrdered();
$numberOfItems = (int)$item->getQty();
// Summarize the discount amount item by item
$discountAmount += $item->getDiscountAmount();
$priceExcludingTax = $item->getPriceInclTax() - $item->getTaxAmount();
$formattedPriceExcludingTax = $this->adyenHelper->formatAmount($priceExcludingTax, $currency);
$formattedPriceExcludingTax = $this->adyenHelper->formatAmount($item->getPrice(), $currency);
$formattedTaxAmount = $this->adyenHelper->formatAmount($item->getTaxAmount(), $currency);
$taxAmount = $item->getPrice() * ($item->getTaxPercent() / 100);
$formattedTaxAmount = $this->adyenHelper->formatAmount($taxAmount, $currency);
$formattedTaxPercentage = $item->getTaxPercent() * 100;
$formFields['lineItems'][] = [
......@@ -236,7 +236,7 @@ class CheckoutDataBuilder implements BuilderInterface
'amountExcludingTax' => $formattedPriceExcludingTax,
'taxAmount' => $formattedTaxAmount,
'description' => $item->getName(),
'quantity' => $item->getQty(),
'quantity' => $numberOfItems,
'taxCategory' => $item->getProduct()->getAttributeText('tax_class_id'),
'taxPercentage' => $formattedTaxPercentage
];
......
......@@ -23,28 +23,27 @@
namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Adyen\Payment\Observer\AdyenHppDataAssignObserver;
/**
* Class CustomerDataBuilder
*/
class CustomerDataBuilder implements BuilderInterface
{
/**
* @var \Adyen\Payment\Helper\Data
*/
private $adyenHelper;
/**
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenRequestsHelper;
/**
* CustomerDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
*/
/**
* CustomerDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
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
*/
public function build(array $buildSubject)
{
$result = [];
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$order = $paymentDataObject->getOrder();
$payment = $paymentDataObject->getPayment();
$payment = $paymentDataObject->getPayment();
$customerId = $order->getCustomerId();
$billingAddress = $order->getBillingAddress();
$storeId = $order->getStoreId();
if ($customerId > 0) {
$result['shopperReference'] = $customerId;
}
$billingAddress = $order->getBillingAddress();
if (!empty($billingAddress)) {
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;
return $this->adyenRequestsHelper->buildCustomerData([], $customerId, $billingAddress, $storeId, $payment);
}
}
......@@ -29,6 +29,21 @@ use Magento\Payment\Gateway\Request\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
* @return array
......@@ -38,6 +53,7 @@ class CustomerIpDataBuilder implements BuilderInterface
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$order = $paymentDataObject->getOrder();
return ['shopperIP' => $order->getRemoteIp()];
return $this->adyenRequestsHelper->buildCustomerIpData([], $order->getRemoteIp());
}
}
......@@ -28,19 +28,19 @@ use Magento\Payment\Gateway\Request\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(
\Adyen\Payment\Helper\Data $adyenHelper
\Adyen\Payment\Helper\Requests $adyenRequestsHelper
) {
$this->adyenHelper = $adyenHelper;
$this->adyenRequestsHelper = $adyenRequestsHelper;
}
/**
......@@ -52,12 +52,10 @@ class MerchantAccountDataBuilder implements BuilderInterface
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$order = $paymentDataObject->getOrder();
$storeId = $order->getStoreId();
$payment = $paymentDataObject->getPayment();
$storeId = $order->getStoreId();
$method = $payment->getMethod();
$merchantAccount = $this->adyenHelper->getAdyenMerchantAccount($method, $storeId);
return ["merchantAccount" => $merchantAccount];
return $this->adyenRequestsHelper->buildMerchantAccountData([], $method, $storeId);
}
}
......@@ -29,20 +29,19 @@ use Magento\Payment\Gateway\Request\BuilderInterface;
*/
class PaymentDataBuilder implements BuilderInterface
{
/**
* @var \Adyen\Payment\Helper\Data
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenHelper;
private $adyenRequestsHelper;
/**
* 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
$currencyCode = $fullOrder->getOrderCurrencyCode();
$amount = $fullOrder->getGrandTotal();
$reference = $order->getOrderIncrementId();
$amount = ['currency' => $currencyCode,
'value' => $this->adyenHelper->formatAmount($amount, $currencyCode)];
return [
"amount" => $amount,
"reference" => $order->getOrderIncrementId(),
"fraudOffset" => "0"
];
return $this->adyenRequestsHelper->buildPaymentData([], $amount, $currencyCode, $reference);
}
}
......@@ -28,27 +28,27 @@ use Magento\Payment\Gateway\Request\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.
*
* @param \Adyen\Payment\Helper\Data $adyenHelper
* @param \Magento\Framework\Model\Context $context
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
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->adyenRequestsHelper = $adyenRequestsHelper;
}
......@@ -59,39 +59,12 @@ class RecurringDataBuilder implements BuilderInterface
*/
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 */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$storeId = null;
if ($this->appState->getAreaCode() === \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE) {
$storeId = $payment->getOrder()->getStoreId();
}
$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;
}
}
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$storeId = $payment->getOrder()->getStoreId();
$areaCode = $this->appState->getAreaCode();
return $result;
return $this->adyenRequestsHelper->buildRecurringData([], $areaCode, $storeId, $payment);
}
}
......@@ -46,4 +46,4 @@ class RecurringVaultDataBuilder implements BuilderInterface
$result['shopperInteraction'] = 'ContAuth';
return $result;
}
}
\ No newline at end of file
}
......@@ -177,7 +177,10 @@ class RefundDataBuilder implements BuilderInterface
return $result;
}
/**
* @param \Magento\Payment\Model\InfoInterface $payment
* @return array|mixed
*/
protected function getOpenInvoiceData($payment)
{
$formFields = [];
......@@ -185,11 +188,11 @@ class RefundDataBuilder implements BuilderInterface
$currency = $payment->getOrder()->getOrderCurrencyCode();
/**
* Magento\Sales\Model\Order\Creditmemo
* @var \Magento\Sales\Model\Order\Creditmemo $creditMemo
*/
$creditMemo = $payment->getCreditMemo();
foreach ($creditMemo->getAllItems() as $refundItem) {
foreach ($creditMemo->getItems() as $refundItem) {
++$count;
$numberOfItems = (int)$refundItem->getQty();
......@@ -201,7 +204,7 @@ class RefundDataBuilder implements BuilderInterface
$currency,
$refundItem->getTaxAmount(),
$refundItem->getPriceInclTax(),
$refundItem->getTaxPercent(),
$refundItem->getOrderItem()->getTaxPercent(),
$numberOfItems,
$payment,
$refundItem->getId()
......
......@@ -24,17 +24,23 @@
namespace Adyen\Payment\Gateway\Request;
use Magento\Payment\Gateway\Request\BuilderInterface;
use Magento\Vault\Model\Ui\VaultConfigProvider;
use \Magento\Payment\Gateway\Helper\SubjectReader;
class VaultDataBuilder implements BuilderInterface
{
/**
* @var \Adyen\Payment\Helper\Requests
*/
private $adyenRequestsHelper;
/**
* Recurring variable
* @var string
* VaultDataBuilder constructor.
*
* @param \Adyen\Payment\Helper\Requests $adyenRequestsHelper
*/
private static $enableRecurring = 'enableRecurring';
public function __construct(\Adyen\Payment\Helper\Requests $adyenRequestsHelper)
{
$this->adyenRequestsHelper = $adyenRequestsHelper;
}
/**
* @param array $buildSubject
......@@ -43,21 +49,11 @@ class VaultDataBuilder implements BuilderInterface
public function build(array $buildSubject)
{
// vault is enabled and shopper provided consent to store card this logic is triggered
$request = [];
$paymentDO = SubjectReader::readPayment($buildSubject);
$payment = $paymentDO->getPayment();
$data = $payment->getAdditionalInformation();
/** @var \Magento\Payment\Gateway\Data\PaymentDataObject $paymentDataObject */
$paymentDataObject = \Magento\Payment\Gateway\Helper\SubjectReader::readPayment($buildSubject);
$payment = $paymentDataObject->getPayment();
$additionalInformation = $payment->getAdditionalInformation();
if (!empty($data[VaultConfigProvider::IS_ACTIVE_CODE]) &&
$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;
return $this->adyenRequestsHelper->buildVaultData([], $additionalInformation);
}
}
\ No newline at end of file
}
......@@ -48,10 +48,9 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface
*/
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 = $payment->getPayment();
$payment = $paymentDataObject->getPayment();
// set transaction not to processing by default wait for notification
$payment->setIsTransactionPending(true);
......@@ -69,7 +68,8 @@ class CheckoutPaymentsDetailsHandler implements HandlerInterface
}
if (!empty($response['additionalData']['recurring.recurringDetailReference']) &&
!$this->adyenHelper->isCreditCardVaultEnabled()
!$this->adyenHelper->isCreditCardVaultEnabled() &&
$payment->getMethodInstance()->getCode() !== \Adyen\Payment\Model\Ui\AdyenOneclickConfigProvider::CODE
) {
$order = $payment->getOrder();
$this->adyenHelper->createAdyenBillingAgreement($order, $response['additionalData']);
......
......@@ -80,6 +80,9 @@ class CheckoutResponseValidator extends AbstractValidator
}
}
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
break;
case "Received":
$payment->setAdditionalInformation('pspReference', $response['pspReference']);
break;
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
const LIVE = 'live';
const CHECKOUT_CONTEXT_URL_LIVE = 'https://checkoutshopper-live.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_TEST = 'https://checkoutshopper-test.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.5.0/adyen.js';
/**
* @var \Magento\Framework\Encryption\EncryptorInterface
......@@ -371,7 +371,7 @@ class Data extends AbstractHelper
*/
public function getStreetFromString($streetLine)
{
$street = self::formatStreet(array($streetLine));
$street = self::formatStreet([$streetLine]);
$streetName = $street['0'];
unset($street['0']);
$streetNr = implode(' ', $street);
......@@ -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 null $storeId
* @param int|null $storeId
* @return mixed
*/
public function getAdyenCcVaultConfigDataFlag($field, $storeId = null)
......@@ -460,6 +460,18 @@ class Data extends AbstractHelper
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
*
......@@ -1110,6 +1122,15 @@ class Data extends AbstractHelper
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()
{
return [
......@@ -1348,11 +1369,15 @@ class Data extends AbstractHelper
* return the merchant account name defined in required settings.
*
* @param $paymentMethod
* @param int $storeId
* @param int|null $storeId
* @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);
$merchantAccountPos = $this->getAdyenPosCloudConfigData('pos_merchant_account', $storeId);
......@@ -1452,6 +1477,16 @@ class Data extends AbstractHelper
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
*
......@@ -1460,15 +1495,13 @@ class Data extends AbstractHelper
*/
public function getOriginKeyForBaseUrl()
{
$baseUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_WEB);
$parsed = parse_url($baseUrl);
$domain = $parsed['scheme'] . "://" . $parsed['host'];
$origin = $this->getOrigin();
$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->getOriginKeyForUrl($domain, $storeId)) {
$this->cache->save($originKey, $cacheKey, array(), 60 * 60 * 24);
if ($originKey = $this->getOriginKeyForOrigin($origin, $storeId)) {
$this->cache->save($originKey, $cacheKey, [], 60 * 60 * 24);
}
}
......@@ -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
* @return string
* @throws \Adyen\AdyenException
*/
private function getOriginKeyForUrl($url, $storeId = null)
private function getOriginKeyForOrigin($origin, $storeId = null)
{
$params = array(
"originDomains" => array(
$url
)
);
$params = [
"originDomains" => [
$origin
]
];
$client = $this->initializeAdyenClient($storeId);
......@@ -1502,8 +1535,8 @@ class Data extends AbstractHelper
$originKey = "";
if (!empty($response['originKeys'][$url])) {
$originKey = $response['originKeys'][$url];
if (!empty($response['originKeys'][$origin])) {
$originKey = $response['originKeys'][$origin];
}
return $originKey;
......@@ -1580,7 +1613,8 @@ class Data extends AbstractHelper
// Populate billing agreement data
$storeOneClick = $order->getPayment()->getAdditionalInformation('store_cc');
$billingAgreement->setCcBillingAgreement($additionalData, $storeOneClick);
$billingAgreement->setCcBillingAgreement($additionalData, $storeOneClick, $order->getStoreId());
if ($billingAgreement->isValid()) {
if (!$this->agreementResourceModel->getOrderRelation($billingAgreement->getAgreementId(),
......@@ -1658,7 +1692,6 @@ class Data extends AbstractHelper
return $icon;
}
/**
* Check if CreditCard vault is enabled
*
......@@ -1682,6 +1715,16 @@ class Data extends AbstractHelper
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
......@@ -1716,6 +1759,26 @@ class Data extends AbstractHelper
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
* @return mixed|string
......
......@@ -50,10 +50,10 @@ class PaymentMethods extends AbstractHelper
*/
protected $session;
/**
* @var \Magento\Framework\Locale\ResolverInterface
*/
protected $localeResolver;
/**
* @var \Magento\Framework\Locale\ResolverInterface
*/
protected $localeResolver;
/**
* @var \Adyen\Payment\Logger\AdyenLogger
......@@ -92,7 +92,7 @@ class PaymentMethods extends AbstractHelper
* @param \Magento\Framework\App\Config\ScopeConfigInterface $config
* @param Data $adyenHelper
* @param \Magento\Checkout\Model\Session $session
* @param \Magento\Framework\Locale\ResolverInterface $localeResolver
* @param \Magento\Framework\Locale\ResolverInterface $localeResolver
* @param \Adyen\Payment\Logger\AdyenLogger $adyenLogger
* @param \Magento\Framework\View\Asset\Repository $assetRepo
* @param \Magento\Framework\App\RequestInterface $request
......@@ -105,7 +105,7 @@ class PaymentMethods extends AbstractHelper
\Magento\Framework\App\Config\ScopeConfigInterface $config,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Checkout\Model\Session $session,
\Magento\Framework\Locale\ResolverInterface $localeResolver,
\Magento\Framework\Locale\ResolverInterface $localeResolver,
\Adyen\Payment\Logger\AdyenLogger $adyenLogger,
\Magento\Framework\View\Asset\Repository $assetRepo,
\Magento\Framework\App\RequestInterface $request,
......@@ -117,7 +117,7 @@ class PaymentMethods extends AbstractHelper
$this->config = $config;
$this->adyenHelper = $adyenHelper;
$this->session = $session;
$this->localeResolver = $localeResolver;
$this->localeResolver = $localeResolver;
$this->adyenLogger = $adyenLogger;
$this->assetRepo = $assetRepo;
$this->request = $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\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
* @param $contractDetail
* @return $this
*/
public function setCcBillingAgreement($contractDetail, $storeOneClick)
public function setCcBillingAgreement($contractDetail, $storeOneClick, $storeId)
{
$this
->setMethodCode('adyen_oneclick')
......@@ -212,9 +212,9 @@ class Agreement extends \Magento\Paypal\Model\Billing\Agreement
$expiryDate = explode('/', $contractDetail['expiryDate']);
if (!empty($contractDetail['pos_payment'])) {
$recurringType = $this->adyenHelper->getAdyenPosCloudConfigData('recurring_type');
$recurringType = $this->adyenHelper->getAdyenPosCloudConfigData('recurring_type', $storeId);
} else {
$recurringType = $this->adyenHelper->getRecurringTypeFromOneclickRecurringSetting();
$recurringType = $this->adyenHelper->getRecurringTypeFromOneclickRecurringSetting($storeId);
// for bcmc and maestro recurring is not allowed so don't set this
if ($recurringType === \Adyen\Payment\Model\RecurringType::ONECLICK_RECURRING &&
......
......@@ -907,6 +907,41 @@ class Cron
}
break;
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()) {
// Move the order from PAYMENT_REVIEW to NEW, so that can be cancelled
$this->_order->setState(\Magento\Sales\Model\Order::STATE_NEW);
......@@ -1148,9 +1183,14 @@ class Cron
protected function _authorizePayment()
{
$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();
// 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 == "") {
$this->_setPrePaymentAuthorized();
} else {
......
......@@ -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
$config['payment'] ['adyenHpp']['gender'] = $gender;
......
......@@ -46,6 +46,21 @@ class AdyenBoletoDataAssignObserver extends AbstractDataAssignObserver
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
* @return void
......@@ -60,8 +75,11 @@ class AdyenBoletoDataAssignObserver extends AbstractDataAssignObserver
}
$paymentInfo = $this->readPaymentModelArgument($observer);
$paymentInfo->setCcType('boleto');
if (!empty($additionalData[self::BOLETO_TYPE])) {
$paymentInfo->setCcType($additionalData[self::BOLETO_TYPE]);
} else {
$paymentInfo->setCcType($this->adyenHelper->getAdyenBoletoConfigData('boletotypes'));
}
foreach ($this->additionalInformationList as $additionalInformationKey) {
if (isset($additionalData[$additionalInformationKey])) {
......
......@@ -40,6 +40,12 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
const ENCRYPTED_EXPIRY_YEAR = 'expiryYear';
const HOLDER_NAME = 'holderName';
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
......@@ -53,7 +59,13 @@ class AdyenCcDataAssignObserver extends AbstractDataAssignObserver
self::ENCRYPTED_EXPIRY_MONTH,
self::ENCRYPTED_EXPIRY_YEAR,
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
const ENCRYPTED_SECURITY_CODE = 'cvc';
const NUMBER_OF_INSTALLMENTS = 'number_of_installments';
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
......@@ -43,7 +49,13 @@ class AdyenOneclickDataAssignObserver extends AbstractDataAssignObserver
self::RECURRING_DETAIL_REFERENCE,
self::ENCRYPTED_SECURITY_CODE,
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 @@
"name": "adyen/module-payment",
"description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.",
"type": "magento2-module",
"version": "4.1.1",
"version": "4.2.0",
"license": [
"OSL-3.0",
"AFL-3.0"
......
<?xml version="1.0"?>
<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">
<arguments>
<argument name="messages" xsi:type="array">
......
......@@ -59,6 +59,12 @@
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_cc_vault/active</config_path>
</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"
sortOrder="150">
......
......@@ -489,16 +489,8 @@
<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\CcAuthorizationDataBuilder
</item>
<item name="vault" xsi:type="string">Adyen\Payment\Gateway\Request\VaultDataBuilder</item>
</argument>
</arguments>
</virtualType>
......@@ -536,15 +528,7 @@
<virtualType name="AdyenPaymentOneclickAuthorizeRequest" 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\CcAuthorizationDataBuilder</item>
<item name="oneclick" xsi:type="string">Adyen\Payment\Gateway\Request\OneclickAuthorizationDataBuilder</item>
</argument>
</arguments>
</virtualType>
......@@ -644,6 +628,7 @@
<arguments>
<argument name="handlers" xsi:type="array">
<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>
</argument>
</arguments>
......@@ -885,8 +870,10 @@
type="Adyen\Payment\Model\AdyenRequestMerchantSession"/>
<preference for="Adyen\Payment\Api\AdyenInitiateTerminalApiInterface"
type="Adyen\Payment\Model\AdyenInitiateTerminalApi"/>
<preference for="Magento\Checkout\Api\PaymentInformationManagementInterface"
type="Adyen\Payment\Model\AdyenPaymentInformationManagement"/>
<preference for="Adyen\Payment\Api\AdyenPaymentProcessInterface"
type="Adyen\Payment\Model\AdyenPaymentProcess"/>
<preference for="Adyen\Payment\Api\AdyenThreeDS2ProcessInterface"
type="Adyen\Payment\Model\AdyenThreeDS2Process"/>
<type name="Magento\Vault\Api\PaymentTokenRepositoryInterface">
<plugin name="AdyenPaymentVaultDeleteToken" type="Adyen\Payment\Plugin\PaymentVaultDeleteToken" sortOrder="10"/>
</type>
......
......@@ -24,7 +24,7 @@
-->
<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>
<module name="Magento_Sales"/>
<module name="Magento_Quote"/>
......
......@@ -57,4 +57,18 @@
<resource ref="anonymous"/>
</resources>
</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>
\ No newline at end of file
......@@ -104,7 +104,10 @@ echo $code; ?>" style="display:none">
var cardNode = document.getElementById("cardContainer-<?php /* @noEscape */ echo $code; ?>");
var checkout = new AdyenCheckout({
locale: "<?php echo $block->getLocale(); ?>"
locale: "<?php echo $block->getLocale(); ?>",
risk: {
enabled: false
}
});
var hideCVC = "<?php echo !$block->hasVerification(); ?>";
......
......@@ -25,9 +25,17 @@
}
.checkout-payment-method .ccard .changable-card-expiry { 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 .changable-card-expiry {
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 {
width: 225px;
......@@ -44,8 +52,7 @@
}
.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);
font-weight: 200;
}
......@@ -58,20 +65,21 @@
}
.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 {
background:url(../images/logos/pm_gloss.png) no-repeat;
background: url(../images/logos/pm_gloss.png) no-repeat;
background-position: 0 -272px;
width:65px;
height:42px;
width: 65px;
height: 42px;
display: inline-block;
}
.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 {
......@@ -91,13 +99,13 @@
}
.checkout-payment-method .payment-method-title label div.adyen-sprite.adyen_apple_pay {
background:url(../images/logos/apple_pay.png) no-repeat;
height:43px;
background: url(../images/logos/apple_pay.png) no-repeat;
height: 43px;
}
.checkout-payment-method .input-text._has-datepicker {
width:20%;
margin-right:10px;
width: 20%;
margin-right: 10px;
}
.apple-pay-button-with-text {
......@@ -109,37 +117,44 @@
padding: 0px;
box-sizing: border-box;
/*min-width: 200px;*/
width:100%;
width: 100%;
min-height: 32px;
max-height: 64px;
margin-bottom: 10px;
cursor: pointer;
}
.apple-pay-button-black-with-text {
background-color: black;
color: white;
}
.apple-pay-button-white-with-text {
background-color: white;
color: black;
}
.apple-pay-button-white-with-line-with-text {
background-color: white;
color: black;
border: .5px solid black;
}
.apple-pay-button-with-text.apple-pay-button-black-with-text > .logo {
background-image: -webkit-named-image(apple-pay-logo-white);
background-color: black;
}
.apple-pay-button-with-text.apple-pay-button-white-with-text > .logo {
background-image: -webkit-named-image(apple-pay-logo-black);
background-color: white;
}
.apple-pay-button-with-text.apple-pay-button-white-with-line-with-text > .logo {
background-image: -webkit-named-image(apple-pay-logo-black);
background-color: white;
}
.apple-pay-button-with-text > .text {
font-family: -apple-system;
font-size: calc(1em * var(--apple-pay-scale));
......@@ -148,6 +163,7 @@
margin-right: calc(2px * var(--apple-pay-scale));
}
.apple-pay-button-with-text > .logo {
width: calc(35px * var(--apple-pay-scale));
height: 100%;
......@@ -164,706 +180,803 @@
Custom style for ideal component
*/
#iDealContainer .adyen-checkout__dropdown__button{
#iDealContainer .adyen-checkout__dropdown__button {
padding: 0 0 0 8px;
max-width: 290px;
}
#iDealContainer .adyen-checkout__dropdown--large{
#iDealContainer .adyen-checkout__dropdown--large {
margin-left: 21px;
}
#iDealContainer .adyen-checkout__dropdown__element{
#iDealContainer .adyen-checkout__dropdown__element {
margin-bottom: 0;
}
/* 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;
}
.adyen-checkout__link adyen-checkout__link--more-information{
.adyen-checkout__link adyen-checkout__link--more-information {
margin-bottom: 10px;
}
.message.error.hpp-message{
.message.error.hpp-message {
margin-top: 10px;
display: none;
}
/* Checkout component Adyen styling start */
.adyen-checkout__spinner__wrapper{
align-items:center;
display:flex;
height:100%;
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)
}
.adyen-checkout__spinner__wrapper {
align-items: center;
display: flex;
height: 100%;
justify-content: center
}
@keyframes rotateSpinner{
0%{
-webkit-transform:rotate(0deg);
transform:rotate(0deg)
}
to{
-webkit-transform:rotate(1turn);
transform:rotate(1turn)
}
.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__pay-button{
background:#001b2b;
border:0;
border-radius:3px;
box-shadow:0 3px 4px rgba(0,15,45,.2);
color:#fff;
cursor:pointer;
font-size:1em;
font-weight:700;
height:48px;
padding:15px;
transition:background .3s ease-out;
width:100%
}
.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)
.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:scaleX(1);
transform:scaleX(1)
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn)
}
}
@keyframes expand{
0%{
-webkit-transform:scaleY(0);
transform:scaleY(0)
@keyframes rotateSpinner {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg)
}
to{
-webkit-transform:scaleX(1);
transform:scaleX(1)
to {
-webkit-transform: rotate(1turn);
transform: rotate(1turn)
}
}
.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::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__pay-button {
background: #001b2b;
border: 0;
border-radius: 3px;
box-shadow: 0 3px 4px rgba(0, 15, 45, .2);
color: #fff;
cursor: pointer;
font-size: 1em;
font-weight: 700;
height: 48px;
padding: 15px;
transition: background .3s ease-out;
width: 100%
}
.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;
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{
max-width:540px
......@@ -874,164 +987,234 @@
.adyen-checkout__open-invoice .adyen-checkout__checkbox{
margin:0 0 20px
}
.adyen-checkout__applepay__button{
height:40px;
width:240px
}
.adyen-checkout__card-input__form{
transition:opacity .25s ease-out
}
.adyen-checkout__card__exp-cvc{
display:flex
}
.adyen-checkout__card__cardNumber{
max-width:400px
}
.adyen-checkout__card__cardNumber__input{
padding:5px 8px 5px 57px
}
.adyen-checkout__card__exp-date__input--oneclick{
font-weight:400;
height:40px;
line-height:40px
}
.adyen-checkout__card__exp-cvc .adyen-checkout__field{
margin-bottom:0;
margin-right:24px
}
.adyen-checkout__card-input .adyen-checkout__store-details{
margin-top:16px
}
.adyen-checkout__giropay__results{
background:#fff;
border:1px solid #b9c4c9;
border-radius:4px;
max-height:140px;
min-height:100px;
overflow-y:scroll;
width:100%
}
.adyen-checkout__giropay__no-results{
color:#687282;
display:block;
font-size:13px;
padding:0 0 0 2px
}
.adyen-checkout__giropay__placeholder{
color:#90a2bd;
display:block;
font-weight:200;
padding:0 0 0 2px
}
.adyen-checkout__giropay__loading{
display:block;
min-height:100px
}
.adyen-checkout__giropay__loading .adyen-checkout__spinner__wrapper{
display:inline-block;
vertical-align:middle
}
.adyen-checkout__giropay__loading-text{
color:#687282;
font-size:13px;
line-height:16px;
vertical-align:middle
}
.adyen-checkout__giropay__error{
color:#d0021b;
font-size:13px
}
.adyen-checkout__phone-input{
display:flex
}
.adyen-checkout__phone-input__prefix{
margin-right:.5em
}
.adyen-checkout__phone-input .adyen-checkout__field{
margin-bottom:0
}
.adyen-checkout__iban-input__number{
padding:5px 36px 5px 8px;
text-transform:uppercase
}
.adyen-checkout__wechatpay{
background:#fff;
border:1px solid #dde1e3;
border-radius:3px;
min-height:443px;
padding:40px;
text-align:center
}
.adyen-checkout__wechatpay__brand-logo{
height:20px;
width:109px
}
.adyen-checkout__wechatpay__subtitle{
margin-top:32px
}
.adyen-checkout__wechatpay__payment_amount,.adyen-checkout__wechatpay__subtitle{
color:#001b2b;
font-size:16px;
line-height:19px
}
.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
.adyen-checkout__applepay__button {
height: 40px;
width: 240px
}
.adyen-checkout__card-input__form {
transition: opacity .25s ease-out
}
.adyen-checkout__card__exp-cvc {
display: flex
}
.adyen-checkout__card__cardNumber {
max-width: 400px
}
.adyen-checkout__card__cardNumber__input {
padding: 5px 8px 5px 57px
}
.adyen-checkout__card__exp-date__input--oneclick {
font-weight: 400;
height: 40px;
line-height: 40px
}
.adyen-checkout__card__exp-cvc .adyen-checkout__field {
margin-bottom: 0;
margin-right: 24px
}
.adyen-checkout__card-input .adyen-checkout__store-details {
margin-top: 16px
}
.adyen-checkout__giropay__results {
background: #fff;
border: 1px solid #b9c4c9;
border-radius: 4px;
max-height: 140px;
min-height: 100px;
overflow-y: scroll;
width: 100%
}
.adyen-checkout__giropay__no-results {
color: #687282;
display: block;
font-size: 13px;
padding: 0 0 0 2px
}
.adyen-checkout__giropay__placeholder {
color: #90a2bd;
display: block;
font-weight: 200;
padding: 0 0 0 2px
}
.adyen-checkout__giropay__loading {
display: block;
min-height: 100px
}
.adyen-checkout__giropay__loading .adyen-checkout__spinner__wrapper {
display: inline-block;
vertical-align: middle
}
.adyen-checkout__giropay__loading-text {
color: #687282;
font-size: 13px;
line-height: 16px;
vertical-align: middle
}
.adyen-checkout__giropay__error {
color: #d0021b;
font-size: 13px
}
.adyen-checkout__phone-input {
display: flex
}
.adyen-checkout__phone-input__prefix {
margin-right: .5em
}
.adyen-checkout__phone-input .adyen-checkout__field {
margin-bottom: 0
}
.adyen-checkout__iban-input__number {
padding: 5px 36px 5px 8px;
text-transform: uppercase
}
.adyen-checkout__threeds2__challenge-container {
background-color: transparent;
box-sizing: border-box;
display: block;
overflow: auto;
width: 100%
}
.adyen-checkout__threeds2__challenge-container--01 {
height: 400px;
width: 250px
}
.adyen-checkout__threeds2__challenge-container--02 {
height: 400px;
width: 390px
}
.adyen-checkout__threeds2__challenge-container--03 {
height: 600px;
width: 500px
}
.adyen-checkout__threeds2__challenge-container--04 {
height: 400px;
width: 600px
}
.adyen-checkout__threeds2_challenge-container--05 {
height: 100%;
width: 100%
}
.adyen-checkout__wechatpay {
background: #fff;
border: 1px solid #dde1e3;
border-radius: 3px;
min-height: 443px;
padding: 40px;
text-align: center
}
.adyen-checkout__wechatpay__brand-logo {
height: 20px;
width: 109px
}
.adyen-checkout__wechatpay__subtitle {
margin-top: 32px
}
.adyen-checkout__wechatpay__payment_amount, .adyen-checkout__wechatpay__subtitle {
color: #001b2b;
font-size: 16px;
line-height: 19px
}
.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 */
/**
* 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(
'Magento_Checkout/js/model/quote',
'Adyen_Payment/js/model/installments',
'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';
......@@ -43,7 +50,7 @@ define(
defaults: {
template: 'Adyen_Payment/payment/cc-form',
creditCardOwner: '',
setStoreCc: false,
storeCc: false,
installment: '',
creditCardDetailsValid: false
},
......@@ -56,6 +63,14 @@ define(
this.vaultEnabler.setPaymentCode(this.getVaultCode());
this.vaultEnabler.isActivePaymentTokenEnabler(false);
// initialize adyen component for general use
this.checkout = new AdyenCheckout({
locale: this.getLocale(),
risk: {
enabled: false
}
});
return this;
},
initObservable: function () {
......@@ -67,7 +82,6 @@ define(
'securityCode',
'expiryMonth',
'expiryYear',
'setStoreCc',
'installment',
'creditCardDetailsValid',
'variant',
......@@ -77,6 +91,13 @@ define(
return this;
},
getInstallments: installments.getInstallments(),
/**
* Returns true if card details can be stored
* @returns {*|boolean}
*/
getEnableStoreDetails: function () {
return this.canCreateBillingAgreement() && !this.isVaultEnabled();
},
/**
* Renders the secure fields,
* creates the card component,
......@@ -85,6 +106,7 @@ define(
*/
renderSecureFields: function () {
var self = this;
if (!self.getOriginKey()) {
return;
}
......@@ -95,20 +117,18 @@ define(
var allInstallments = self.getAllInstallments();
var cardNode = document.getElementById('cardContainer');
var checkout = new AdyenCheckout({
locale: self.getLocale()
});
var card = checkout.create('card', {
self.cardComponent = self.checkout.create('card', {
originKey: self.getOriginKey(),
loadingContext: self.getLoadingContext(),
type: 'card',
hasHolderName: true,
holderNameRequired: true,
enableStoreDetails: self.getEnableStoreDetails(),
groupTypes: self.getAvailableCardTypeAltCodes(),
onChange: function (state, component) {
if (!!state.isValid && !component.state.errors.encryptedSecurityCode) {
self.storeCc = !!state.data.storeDetails;
self.variant(state.brand);
self.creditCardNumber(state.data.encryptedCardNumber);
self.expiryMonth(state.data.encryptedExpiryMonth);
......@@ -173,16 +193,87 @@ define(
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));
}
});
self.threeDS2IdentifyComponent.mount(threeDS2Node);
card.mount(cardNode);
} 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
*
* @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 = {
'method': this.item.method,
additional_data: {
......@@ -193,13 +284,35 @@ define(
'expiryMonth': this.expiryMonth(),
'expiryYear': this.expiryYear(),
'holderName': this.creditCardOwner(),
'store_cc': this.setStoreCc(),
'number_of_installments': this.installment()
'store_cc': this.storeCc,
'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);
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 {boolean}
......@@ -224,11 +337,34 @@ define(
}
if (this.validate() && additionalValidators.validate()) {
this.isPlaceOrderActionAllowed(false);
fullScreenLoader.startLoader();
self.isPlaceOrderActionAllowed(false);
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);
this.getPlaceOrderDeferredObject()
if (!!response.threeDS2) {
// render component
self.renderThreeDS2Component(response.type, response.token);
} else {
self.getPlaceOrderDeferredObject()
.fail(
function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true);
}
).done(
......@@ -241,11 +377,7 @@ define(
}
}
);
return true;
}
return false;
},
/**
* Validates the payment date when clicking the pay button
......
......@@ -81,7 +81,10 @@ define(
* @type {AdyenCheckout}
*/
self.checkoutComponent = new AdyenCheckout({
locale: self.getLocale()
locale: self.getLocale(),
risk: {
enabled: false
}
});
// reset variable:
......
......@@ -32,10 +32,16 @@ define(
'Magento_Checkout/js/action/redirect-on-success',
'uiLayout',
'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',
'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';
......@@ -59,7 +65,7 @@ define(
.observe([
'recurringDetailReference',
'creditCardType',
'creditCardVerificationNumber',
'encryptedCreditCardVerificationNumber',
'variant',
'numberOfInstallments'
]);
......@@ -104,7 +110,10 @@ define(
var checkout = new AdyenCheckout({
locale: self.getLocale(),
originKey: self.getOriginKey(),
loadingContext: self.getLoadingContext()
loadingContext: self.getLoadingContext(),
risk: {
enabled: false
}
});
// convert to list so you can iterate
......@@ -165,7 +174,13 @@ define(
return self.isActive() && this.getCode() == self.isChecked() && self.isBillingAgreementChecked() && this.placeOrderAllowed();
},
/**
* Custom place order function
*
* @override
*
* @param data
* @param event
* @returns {boolean}
*/
placeOrder: function (data, event) {
var self = this;
......@@ -173,38 +188,31 @@ define(
if (event) {
event.preventDefault();
}
// only use installments for cards
if (self.agreement_data.card) {
if (self.hasVerification()) {
var options = {enableValidations: false};
}
// set payment method to adyen_hpp
// TODO can observer in front-end this not needed
numberOfInstallments(self.installment);
}
// in different context so need custom place order logic
if (this.validate() && additionalValidators.validate()) {
fullScreenLoader.startLoader();
self.isPlaceOrderActionAllowed(false);
this.getPlaceOrderDeferredObject()
.fail(
function () {
self.isPlaceOrderActionAllowed(true);
}
).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;
threeds2.processPayment(this.getCcData()).done(function (responseJSON) {
self.validateThreeDS2OrPlaceOrder(responseJSON);
}).error(function () {
fullScreenLoader.stopLoader();
self.isPlaceOrderActionAllowed(true);
});
return false;
}
return false;
},
/**
* Renders the secure CVC field,
* creates the card component,
......@@ -275,6 +283,123 @@ define(
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
* details object that we get from the paymentMethods call. This function is a fix for BCMC.
......@@ -282,7 +407,7 @@ define(
* should be removed
* @returns {*}
*/
getOneclickDetails: function() {
getOneclickDetails: function () {
var self = this;
if (self.agreement_data.variant === 'bcmc') {
......@@ -310,9 +435,7 @@ define(
variant: variant(),
recurring_detail_reference: recurringDetailReference(),
number_of_installments: numberOfInstallments(),
cvc: self.encryptedCreditCardVerificationNumber,
expiryMonth: self.creditCardExpMonth(),
expiryYear: self.creditCardExpYear()
cvc: self.encryptedCreditCardVerificationNumber
}
};
},
......@@ -345,7 +468,7 @@ define(
getMessageContainer: function () {
return messageContainer;
},
getOriginKey:function () {
getOriginKey: function () {
return self.getOriginKey();
},
isPlaceOrderActionAllowed: function () {
......
......@@ -77,6 +77,9 @@
<div afterRender="renderSecureFields()" data-bind="attr: { id: 'cardContainer'}"></div>
</div>
<div id="threeDS2Modal">
<div id="threeDS2Container"></div>
</div>
<!-- ko if: (hasInstallments())-->
......@@ -117,23 +120,6 @@
</div>
<!-- /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>
</form>
......
......@@ -134,6 +134,11 @@
</div>
</div>
<!-- /ko -->
<div id="threeDS2ModalOneClick">
<div id="threeDS2ContainerOneClick"></div>
</div>
</fieldset>
</form>
<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