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

Commit 6f6a2efe authored by cyattilakiss's avatar cyattilakiss Committed by GitHub

Merge pull request #452 from Adyen/develop

Release 4.2.0
parents 5b8e6426 296f8de9
......@@ -15,32 +15,20 @@
*
* 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